libifconfig_media.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*
  2. * Copyright (c) 1983, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #include <sys/param.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/socket.h>
  32. #include <sys/sysctl.h>
  33. #include <sys/time.h>
  34. #include <net/if.h>
  35. #include <net/if_dl.h>
  36. #include <net/if_types.h>
  37. #include <net/if_media.h>
  38. #include <net/route.h>
  39. #include <assert.h>
  40. #include <ctype.h>
  41. #include <err.h>
  42. #include <errno.h>
  43. #include <fcntl.h>
  44. #include <stdbool.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <unistd.h>
  49. #include "libifconfig.h"
  50. #include "libifconfig_internal.h"
  51. static const struct ifmedia_description *lookup_media_desc(
  52. const struct ifmedia_description *, const char *);
  53. static const struct ifmedia_type_to_subtype *get_toptype_ttos(ifmedia_t);
  54. #define IFM_OPMODE(x) \
  55. ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
  56. IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
  57. IFM_IEEE80211_MBSS))
  58. #define IFM_IEEE80211_STA 0
  59. static const struct ifmedia_description
  60. ifm_type_descriptions[] =
  61. IFM_TYPE_DESCRIPTIONS;
  62. static const struct ifmedia_description
  63. ifm_subtype_ethernet_descriptions[] =
  64. IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
  65. static const struct ifmedia_description
  66. ifm_subtype_ethernet_aliases[] =
  67. IFM_SUBTYPE_ETHERNET_ALIASES;
  68. static const struct ifmedia_description
  69. ifm_subtype_ethernet_option_descriptions[] =
  70. IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
  71. static const struct ifmedia_description
  72. ifm_subtype_ieee80211_descriptions[] =
  73. IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
  74. static const struct ifmedia_description
  75. ifm_subtype_ieee80211_aliases[] =
  76. IFM_SUBTYPE_IEEE80211_ALIASES;
  77. static const struct ifmedia_description
  78. ifm_subtype_ieee80211_option_descriptions[] =
  79. IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
  80. static const struct ifmedia_description
  81. ifm_subtype_ieee80211_mode_descriptions[] =
  82. IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
  83. static const struct ifmedia_description
  84. ifm_subtype_ieee80211_mode_aliases[] =
  85. IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
  86. static const struct ifmedia_description
  87. ifm_subtype_atm_descriptions[] =
  88. IFM_SUBTYPE_ATM_DESCRIPTIONS;
  89. static const struct ifmedia_description
  90. ifm_subtype_atm_aliases[] =
  91. IFM_SUBTYPE_ATM_ALIASES;
  92. static const struct ifmedia_description
  93. ifm_subtype_atm_option_descriptions[] =
  94. IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
  95. static const struct ifmedia_description
  96. ifm_subtype_shared_descriptions[] =
  97. IFM_SUBTYPE_SHARED_DESCRIPTIONS;
  98. static const struct ifmedia_description
  99. ifm_subtype_shared_aliases[] =
  100. IFM_SUBTYPE_SHARED_ALIASES;
  101. static const struct ifmedia_description
  102. ifm_shared_option_descriptions[] =
  103. IFM_SHARED_OPTION_DESCRIPTIONS;
  104. static const struct ifmedia_description
  105. ifm_shared_option_aliases[] =
  106. IFM_SHARED_OPTION_ALIASES;
  107. static const struct ifmedia_description *
  108. lookup_media_desc(const struct ifmedia_description *desc, const char *name)
  109. {
  110. for (; desc->ifmt_string != NULL; ++desc)
  111. if (strcasecmp(desc->ifmt_string, name) == 0)
  112. return (desc);
  113. return (NULL);
  114. }
  115. struct ifmedia_type_to_subtype {
  116. struct {
  117. const struct ifmedia_description *desc;
  118. bool alias;
  119. }
  120. subtypes[5];
  121. struct {
  122. const struct ifmedia_description *desc;
  123. bool alias;
  124. }
  125. options[4];
  126. struct {
  127. const struct ifmedia_description *desc;
  128. bool alias;
  129. }
  130. modes[3];
  131. };
  132. /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
  133. static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] =
  134. {
  135. {
  136. {
  137. { &ifm_subtype_shared_descriptions[0], 0 },
  138. { &ifm_subtype_shared_aliases[0], 1 },
  139. { &ifm_subtype_ethernet_descriptions[0], 0 },
  140. { &ifm_subtype_ethernet_aliases[0], 1 },
  141. { NULL, 0 },
  142. },
  143. {
  144. { &ifm_shared_option_descriptions[0], 0 },
  145. { &ifm_shared_option_aliases[0], 1 },
  146. { &ifm_subtype_ethernet_option_descriptions[0], 0 },
  147. { NULL, 0 },
  148. },
  149. {
  150. { NULL, 0 },
  151. },
  152. },
  153. {
  154. {
  155. { &ifm_subtype_shared_descriptions[0], 0 },
  156. { &ifm_subtype_shared_aliases[0], 1 },
  157. { &ifm_subtype_ieee80211_descriptions[0], 0 },
  158. { &ifm_subtype_ieee80211_aliases[0], 1 },
  159. { NULL, 0 },
  160. },
  161. {
  162. { &ifm_shared_option_descriptions[0], 0 },
  163. { &ifm_shared_option_aliases[0], 1 },
  164. { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
  165. { NULL, 0 },
  166. },
  167. {
  168. { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
  169. { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
  170. { NULL, 0 },
  171. },
  172. },
  173. {
  174. {
  175. { &ifm_subtype_shared_descriptions[0], 0 },
  176. { &ifm_subtype_shared_aliases[0], 1 },
  177. { &ifm_subtype_atm_descriptions[0], 0 },
  178. { &ifm_subtype_atm_aliases[0], 1 },
  179. { NULL, 0 },
  180. },
  181. {
  182. { &ifm_shared_option_descriptions[0], 0 },
  183. { &ifm_shared_option_aliases[0], 1 },
  184. { &ifm_subtype_atm_option_descriptions[0], 0 },
  185. { NULL, 0 },
  186. },
  187. {
  188. { NULL, 0 },
  189. },
  190. },
  191. };
  192. static const struct ifmedia_type_to_subtype *
  193. get_toptype_ttos(ifmedia_t media)
  194. {
  195. const struct ifmedia_description *desc;
  196. const struct ifmedia_type_to_subtype *ttos;
  197. for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
  198. desc->ifmt_string != NULL; desc++, ttos++) {
  199. if (IFM_TYPE(media) == desc->ifmt_word)
  200. return (ttos);
  201. }
  202. errno = ENOENT;
  203. return (NULL);
  204. }
  205. const char *
  206. ifconfig_media_get_type(ifmedia_t media)
  207. {
  208. const struct ifmedia_description *desc;
  209. for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; ++desc) {
  210. if (IFM_TYPE(media) == desc->ifmt_word)
  211. return (desc->ifmt_string);
  212. }
  213. errno = ENOENT;
  214. return (NULL);
  215. }
  216. ifmedia_t
  217. ifconfig_media_lookup_type(const char *name)
  218. {
  219. const struct ifmedia_description *desc;
  220. desc = lookup_media_desc(ifm_type_descriptions, name);
  221. return (desc == NULL ? INVALID_IFMEDIA : desc->ifmt_word);
  222. }
  223. const char *
  224. ifconfig_media_get_subtype(ifmedia_t media)
  225. {
  226. const struct ifmedia_description *desc;
  227. const struct ifmedia_type_to_subtype *ttos;
  228. ttos = get_toptype_ttos(media);
  229. if (ttos == NULL) {
  230. errno = EINVAL;
  231. return (NULL);
  232. }
  233. for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) {
  234. if (ttos->subtypes[i].alias)
  235. continue;
  236. for (desc = ttos->subtypes[i].desc;
  237. desc->ifmt_string != NULL; ++desc) {
  238. if (IFM_SUBTYPE(media) == desc->ifmt_word)
  239. return (desc->ifmt_string);
  240. }
  241. }
  242. errno = ENOENT;
  243. return (NULL);
  244. }
  245. ifmedia_t
  246. ifconfig_media_lookup_subtype(ifmedia_t media, const char *name)
  247. {
  248. const struct ifmedia_description *desc;
  249. const struct ifmedia_type_to_subtype *ttos;
  250. ttos = get_toptype_ttos(media);
  251. if (ttos == NULL) {
  252. errno = EINVAL;
  253. return (INVALID_IFMEDIA);
  254. }
  255. for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) {
  256. desc = lookup_media_desc(ttos->subtypes[i].desc, name);
  257. if (desc != NULL)
  258. return (desc->ifmt_word);
  259. }
  260. errno = ENOENT;
  261. return (INVALID_IFMEDIA);
  262. }
  263. const char *
  264. ifconfig_media_get_mode(ifmedia_t media)
  265. {
  266. const struct ifmedia_description *desc;
  267. const struct ifmedia_type_to_subtype *ttos;
  268. ttos = get_toptype_ttos(media);
  269. if (ttos == NULL) {
  270. errno = EINVAL;
  271. return (NULL);
  272. }
  273. for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) {
  274. if (ttos->modes[i].alias)
  275. continue;
  276. for (desc = ttos->modes[i].desc;
  277. desc->ifmt_string != NULL; ++desc) {
  278. if (IFM_MODE(media) == desc->ifmt_word)
  279. return (desc->ifmt_string);
  280. }
  281. }
  282. errno = ENOENT;
  283. return (NULL);
  284. }
  285. ifmedia_t
  286. ifconfig_media_lookup_mode(ifmedia_t media, const char *name)
  287. {
  288. const struct ifmedia_description *desc;
  289. const struct ifmedia_type_to_subtype *ttos;
  290. ttos = get_toptype_ttos(media);
  291. if (ttos == NULL) {
  292. errno = EINVAL;
  293. return (INVALID_IFMEDIA);
  294. }
  295. for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) {
  296. desc = lookup_media_desc(ttos->modes[i].desc, name);
  297. if (desc != NULL)
  298. return (desc->ifmt_word);
  299. }
  300. errno = ENOENT;
  301. return (INVALID_IFMEDIA);
  302. }
  303. const char **
  304. ifconfig_media_get_options(ifmedia_t media)
  305. {
  306. const char **options;
  307. const struct ifmedia_description *desc;
  308. const struct ifmedia_type_to_subtype *ttos;
  309. size_t n;
  310. ttos = get_toptype_ttos(media);
  311. if (ttos == NULL) {
  312. errno = EINVAL;
  313. return (NULL);
  314. }
  315. n = 0;
  316. for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
  317. if (ttos->options[i].alias)
  318. continue;
  319. for (desc = ttos->options[i].desc;
  320. desc->ifmt_string != NULL; ++desc) {
  321. if ((media & desc->ifmt_word) != 0)
  322. ++n;
  323. }
  324. }
  325. if (n == 0) {
  326. errno = ENOENT;
  327. return (NULL);
  328. }
  329. options = calloc(n + 1, sizeof(*options));
  330. if (options == NULL)
  331. return (NULL);
  332. options[n] = NULL;
  333. n = 0;
  334. for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
  335. if (ttos->options[i].alias)
  336. continue;
  337. for (desc = ttos->options[i].desc;
  338. desc->ifmt_string != NULL; ++desc) {
  339. if ((media & desc->ifmt_word) != 0) {
  340. options[n] = desc->ifmt_string;
  341. ++n;
  342. }
  343. }
  344. }
  345. return (options);
  346. }
  347. ifmedia_t *
  348. ifconfig_media_lookup_options(ifmedia_t media, const char **opts, size_t nopts)
  349. {
  350. ifmedia_t *options;
  351. const struct ifmedia_description *desc, *opt;
  352. const struct ifmedia_type_to_subtype *ttos;
  353. assert(opts != NULL);
  354. assert(nopts > 0);
  355. ttos = get_toptype_ttos(media);
  356. if (ttos == NULL) {
  357. errno = EINVAL;
  358. return (NULL);
  359. }
  360. options = calloc(nopts, sizeof(*options));
  361. if (options == NULL)
  362. return (NULL);
  363. (void)memset(options, INVALID_IFMEDIA, nopts * sizeof(ifmedia_t));
  364. for (size_t i = 0; ttos->options[i].desc != NULL; ++i) {
  365. desc = ttos->options[i].desc;
  366. for (size_t j = 0; j < nopts; ++j) {
  367. opt = lookup_media_desc(desc, opts[j]);
  368. if (opt != NULL)
  369. options[j] = opt->ifmt_word;
  370. }
  371. }
  372. return (options);
  373. }
  374. /***************************************************************************
  375. * Above this point, this file is mostly copied from sbin/ifconfig/ifmedia.c
  376. ***************************************************************************/
  377. /* Internal structure used for allocations and frees */
  378. struct _ifconfig_media_status {
  379. struct ifmediareq ifmr;
  380. int medialist[0];
  381. };
  382. int
  383. ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name,
  384. struct ifmediareq **ifmr)
  385. {
  386. struct _ifconfig_media_status *ms, *ms2;
  387. unsigned long cmd = SIOCGIFXMEDIA;
  388. *ifmr = NULL;
  389. ms = calloc(1, sizeof(*ms));
  390. if (ms == NULL) {
  391. h->error.errtype = OTHER;
  392. h->error.errcode = ENOMEM;
  393. return (-1);
  394. }
  395. (void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name));
  396. /*
  397. * Check if interface supports extended media types.
  398. */
  399. if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) {
  400. cmd = SIOCGIFMEDIA;
  401. if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) {
  402. /* Interface doesn't support SIOC{G,S}IFMEDIA. */
  403. h->error.errtype = OK;
  404. free(ms);
  405. return (-1);
  406. }
  407. }
  408. if (ms->ifmr.ifm_count == 0) {
  409. *ifmr = &ms->ifmr;
  410. return (0); /* Interface has no media types ?*/
  411. }
  412. ms2 = realloc(ms, sizeof(*ms) + sizeof(int) * ms->ifmr.ifm_count);
  413. if (ms2 == NULL) {
  414. h->error.errtype = OTHER;
  415. h->error.errcode = ENOMEM;
  416. free(ms);
  417. return (-1);
  418. }
  419. ms2->ifmr.ifm_ulist = &ms2->medialist[0];
  420. if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms2->ifmr) < 0) {
  421. free(ms2);
  422. return (-1);
  423. }
  424. *ifmr = &ms2->ifmr;
  425. return (0);
  426. }
  427. const char *
  428. ifconfig_media_get_status(const struct ifmediareq *ifmr)
  429. {
  430. switch (IFM_TYPE(ifmr->ifm_active)) {
  431. case IFM_ETHER:
  432. case IFM_ATM:
  433. if (ifmr->ifm_status & IFM_ACTIVE) {
  434. return ("active");
  435. } else {
  436. return ("no carrier");
  437. }
  438. break;
  439. case IFM_IEEE80211:
  440. if (ifmr->ifm_status & IFM_ACTIVE) {
  441. /* NB: only sta mode associates */
  442. if (IFM_OPMODE(ifmr->ifm_active) == IFM_IEEE80211_STA) {
  443. return ("associated");
  444. } else {
  445. return ("running");
  446. }
  447. } else {
  448. return ("no carrier");
  449. }
  450. break;
  451. default:
  452. return ("");
  453. }
  454. }
  455. int
  456. ifconfig_media_get_downreason(ifconfig_handle_t *h, const char *name,
  457. struct ifdownreason *ifdr)
  458. {
  459. (void)memset(ifdr, 0, sizeof(*ifdr));
  460. (void)strlcpy(ifdr->ifdr_name, name, sizeof(ifdr->ifdr_name));
  461. return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDOWNREASON, ifdr));
  462. }