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 35 #include <net/if.h> 36 #include <net/if_dl.h> 37 #include <net/if_types.h> 38 #include <net/if_media.h> 39 #include <net/route.h> 40 41 #include <assert.h> 42 #include <ctype.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdbool.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include "libifconfig.h" 53 #include "libifconfig_internal.h" 54 55 static const struct ifmedia_description *lookup_media_desc( 56 const struct ifmedia_description *, const char *); 57 static const struct ifmedia_type_to_subtype *get_toptype_ttos(ifmedia_t); 58 59 #define IFM_OPMODE(x) \ 60 ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ 61 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ 62 IFM_IEEE80211_MBSS)) 63 #define IFM_IEEE80211_STA 0 64 65 static const struct ifmedia_description 66 ifm_type_descriptions[] = 67 IFM_TYPE_DESCRIPTIONS; 68 69 static const struct ifmedia_description 70 ifm_subtype_ethernet_descriptions[] = 71 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 72 73 static const struct ifmedia_description 74 ifm_subtype_ethernet_aliases[] = 75 IFM_SUBTYPE_ETHERNET_ALIASES; 76 77 static const struct ifmedia_description 78 ifm_subtype_ethernet_option_descriptions[] = 79 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 80 81 static const struct ifmedia_description 82 ifm_subtype_ieee80211_descriptions[] = 83 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 84 85 static const struct ifmedia_description 86 ifm_subtype_ieee80211_aliases[] = 87 IFM_SUBTYPE_IEEE80211_ALIASES; 88 89 static const struct ifmedia_description 90 ifm_subtype_ieee80211_option_descriptions[] = 91 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 92 93 static const struct ifmedia_description 94 ifm_subtype_ieee80211_mode_descriptions[] = 95 IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; 96 97 static const struct ifmedia_description 98 ifm_subtype_ieee80211_mode_aliases[] = 99 IFM_SUBTYPE_IEEE80211_MODE_ALIASES; 100 101 static const struct ifmedia_description 102 ifm_subtype_atm_descriptions[] = 103 IFM_SUBTYPE_ATM_DESCRIPTIONS; 104 105 static const struct ifmedia_description 106 ifm_subtype_atm_aliases[] = 107 IFM_SUBTYPE_ATM_ALIASES; 108 109 static const struct ifmedia_description 110 ifm_subtype_atm_option_descriptions[] = 111 IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; 112 113 static const struct ifmedia_description 114 ifm_subtype_shared_descriptions[] = 115 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 116 117 static const struct ifmedia_description 118 ifm_subtype_shared_aliases[] = 119 IFM_SUBTYPE_SHARED_ALIASES; 120 121 static const struct ifmedia_description 122 ifm_shared_option_descriptions[] = 123 IFM_SHARED_OPTION_DESCRIPTIONS; 124 125 static const struct ifmedia_description 126 ifm_shared_option_aliases[] = 127 IFM_SHARED_OPTION_ALIASES; 128 129 static const struct ifmedia_description * 130 lookup_media_desc(const struct ifmedia_description *desc, const char *name) 131 { 132 133 for (; desc->ifmt_string != NULL; ++desc) 134 if (strcasecmp(desc->ifmt_string, name) == 0) 135 return (desc); 136 return (NULL); 137 } 138 139 struct ifmedia_type_to_subtype { 140 struct { 141 const struct ifmedia_description *desc; 142 bool alias; 143 } 144 subtypes[5]; 145 struct { 146 const struct ifmedia_description *desc; 147 bool alias; 148 } 149 options[4]; 150 struct { 151 const struct ifmedia_description *desc; 152 bool alias; 153 } 154 modes[3]; 155 }; 156 157 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 158 static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = 159 { 160 { 161 { 162 { &ifm_subtype_shared_descriptions[0], 0 }, 163 { &ifm_subtype_shared_aliases[0], 1 }, 164 { &ifm_subtype_ethernet_descriptions[0], 0 }, 165 { &ifm_subtype_ethernet_aliases[0], 1 }, 166 { NULL, 0 }, 167 }, 168 { 169 { &ifm_shared_option_descriptions[0], 0 }, 170 { &ifm_shared_option_aliases[0], 1 }, 171 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 172 { NULL, 0 }, 173 }, 174 { 175 { NULL, 0 }, 176 }, 177 }, 178 { 179 { 180 { &ifm_subtype_shared_descriptions[0], 0 }, 181 { &ifm_subtype_shared_aliases[0], 1 }, 182 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 183 { &ifm_subtype_ieee80211_aliases[0], 1 }, 184 { NULL, 0 }, 185 }, 186 { 187 { &ifm_shared_option_descriptions[0], 0 }, 188 { &ifm_shared_option_aliases[0], 1 }, 189 { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, 190 { NULL, 0 }, 191 }, 192 { 193 { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, 194 { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, 195 { NULL, 0 }, 196 }, 197 }, 198 { 199 { 200 { &ifm_subtype_shared_descriptions[0], 0 }, 201 { &ifm_subtype_shared_aliases[0], 1 }, 202 { &ifm_subtype_atm_descriptions[0], 0 }, 203 { &ifm_subtype_atm_aliases[0], 1 }, 204 { NULL, 0 }, 205 }, 206 { 207 { &ifm_shared_option_descriptions[0], 0 }, 208 { &ifm_shared_option_aliases[0], 1 }, 209 { &ifm_subtype_atm_option_descriptions[0], 0 }, 210 { NULL, 0 }, 211 }, 212 { 213 { NULL, 0 }, 214 }, 215 }, 216 }; 217 218 static const struct ifmedia_type_to_subtype * 219 get_toptype_ttos(ifmedia_t media) 220 { 221 const struct ifmedia_description *desc; 222 const struct ifmedia_type_to_subtype *ttos; 223 224 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 225 desc->ifmt_string != NULL; desc++, ttos++) { 226 if (IFM_TYPE(media) == desc->ifmt_word) 227 return (ttos); 228 } 229 errno = ENOENT; 230 return (NULL); 231 } 232 233 const char * 234 ifconfig_media_get_type(ifmedia_t media) 235 { 236 const struct ifmedia_description *desc; 237 238 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; ++desc) { 239 if (IFM_TYPE(media) == desc->ifmt_word) 240 return (desc->ifmt_string); 241 } 242 errno = ENOENT; 243 return (NULL); 244 } 245 246 ifmedia_t 247 ifconfig_media_lookup_type(const char *name) 248 { 249 const struct ifmedia_description *desc; 250 251 desc = lookup_media_desc(ifm_type_descriptions, name); 252 return (desc == NULL ? INVALID_IFMEDIA : desc->ifmt_word); 253 } 254 255 const char * 256 ifconfig_media_get_subtype(ifmedia_t media) 257 { 258 const struct ifmedia_description *desc; 259 const struct ifmedia_type_to_subtype *ttos; 260 261 ttos = get_toptype_ttos(media); 262 if (ttos == NULL) { 263 errno = EINVAL; 264 return (NULL); 265 } 266 267 for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) { 268 if (ttos->subtypes[i].alias) 269 continue; 270 for (desc = ttos->subtypes[i].desc; 271 desc->ifmt_string != NULL; ++desc) { 272 if (IFM_SUBTYPE(media) == desc->ifmt_word) 273 return (desc->ifmt_string); 274 } 275 } 276 errno = ENOENT; 277 return (NULL); 278 } 279 280 ifmedia_t 281 ifconfig_media_lookup_subtype(ifmedia_t media, const char *name) 282 { 283 const struct ifmedia_description *desc; 284 const struct ifmedia_type_to_subtype *ttos; 285 286 ttos = get_toptype_ttos(media); 287 if (ttos == NULL) { 288 errno = EINVAL; 289 return (INVALID_IFMEDIA); 290 } 291 292 for (size_t i = 0; ttos->subtypes[i].desc != NULL; ++i) { 293 desc = lookup_media_desc(ttos->subtypes[i].desc, name); 294 if (desc != NULL) 295 return (desc->ifmt_word); 296 } 297 errno = ENOENT; 298 return (INVALID_IFMEDIA); 299 } 300 301 const char * 302 ifconfig_media_get_mode(ifmedia_t media) 303 { 304 const struct ifmedia_description *desc; 305 const struct ifmedia_type_to_subtype *ttos; 306 307 ttos = get_toptype_ttos(media); 308 if (ttos == NULL) { 309 errno = EINVAL; 310 return (NULL); 311 } 312 313 for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) { 314 if (ttos->modes[i].alias) 315 continue; 316 for (desc = ttos->modes[i].desc; 317 desc->ifmt_string != NULL; ++desc) { 318 if (IFM_MODE(media) == desc->ifmt_word) 319 return (desc->ifmt_string); 320 } 321 } 322 errno = ENOENT; 323 return (NULL); 324 } 325 326 ifmedia_t 327 ifconfig_media_lookup_mode(ifmedia_t media, const char *name) 328 { 329 const struct ifmedia_description *desc; 330 const struct ifmedia_type_to_subtype *ttos; 331 332 ttos = get_toptype_ttos(media); 333 if (ttos == NULL) { 334 errno = EINVAL; 335 return (INVALID_IFMEDIA); 336 } 337 338 for (size_t i = 0; ttos->modes[i].desc != NULL; ++i) { 339 desc = lookup_media_desc(ttos->modes[i].desc, name); 340 if (desc != NULL) 341 return (desc->ifmt_word); 342 } 343 errno = ENOENT; 344 return (INVALID_IFMEDIA); 345 } 346 347 const char ** 348 ifconfig_media_get_options(ifmedia_t media) 349 { 350 const char **options; 351 const struct ifmedia_description *desc; 352 const struct ifmedia_type_to_subtype *ttos; 353 size_t n; 354 355 ttos = get_toptype_ttos(media); 356 if (ttos == NULL) { 357 errno = EINVAL; 358 return (NULL); 359 } 360 361 n = 0; 362 for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { 363 if (ttos->options[i].alias) 364 continue; 365 for (desc = ttos->options[i].desc; 366 desc->ifmt_string != NULL; ++desc) { 367 if ((media & desc->ifmt_word) != 0) 368 ++n; 369 } 370 } 371 if (n == 0) { 372 errno = ENOENT; 373 return (NULL); 374 } 375 376 options = calloc(n + 1, sizeof(*options)); 377 if (options == NULL) 378 return (NULL); 379 380 options[n] = NULL; 381 n = 0; 382 for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { 383 if (ttos->options[i].alias) 384 continue; 385 for (desc = ttos->options[i].desc; 386 desc->ifmt_string != NULL; ++desc) { 387 if ((media & desc->ifmt_word) != 0) { 388 options[n] = desc->ifmt_string; 389 ++n; 390 } 391 } 392 } 393 return (options); 394 } 395 396 ifmedia_t * 397 ifconfig_media_lookup_options(ifmedia_t media, const char **opts, size_t nopts) 398 { 399 ifmedia_t *options; 400 const struct ifmedia_description *desc, *opt; 401 const struct ifmedia_type_to_subtype *ttos; 402 403 assert(opts != NULL); 404 assert(nopts > 0); 405 406 ttos = get_toptype_ttos(media); 407 if (ttos == NULL) { 408 errno = EINVAL; 409 return (NULL); 410 } 411 412 options = calloc(nopts, sizeof(*options)); 413 if (options == NULL) 414 return (NULL); 415 (void)memset(options, INVALID_IFMEDIA, nopts * sizeof(ifmedia_t)); 416 417 for (size_t i = 0; ttos->options[i].desc != NULL; ++i) { 418 desc = ttos->options[i].desc; 419 for (size_t j = 0; j < nopts; ++j) { 420 opt = lookup_media_desc(desc, opts[j]); 421 if (opt != NULL) 422 options[j] = opt->ifmt_word; 423 } 424 } 425 return (options); 426 } 427 428 /*************************************************************************** 429 * Above this point, this file is mostly copied from sbin/ifconfig/ifmedia.c 430 ***************************************************************************/ 431 432 /* Internal structure used for allocations and frees */ 433 struct _ifconfig_media_status { 434 struct ifmediareq ifmr; 435 int medialist[0]; 436 }; 437 438 int 439 ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name, 440 struct ifmediareq **ifmr) 441 { 442 struct _ifconfig_media_status *ms, *ms2; 443 unsigned long cmd = SIOCGIFXMEDIA; 444 445 *ifmr = NULL; 446 ms = calloc(1, sizeof(*ms)); 447 if (ms == NULL) { 448 h->error.errtype = OTHER; 449 h->error.errcode = ENOMEM; 450 return (-1); 451 } 452 (void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name)); 453 454 /* 455 * Check if interface supports extended media types. 456 */ 457 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { 458 cmd = SIOCGIFMEDIA; 459 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { 460 /* Interface doesn't support SIOC{G,S}IFMEDIA. */ 461 h->error.errtype = OK; 462 free(ms); 463 return (-1); 464 } 465 } 466 if (ms->ifmr.ifm_count == 0) { 467 *ifmr = &ms->ifmr; 468 return (0); /* Interface has no media types ?*/ 469 } 470 471 ms2 = realloc(ms, sizeof(*ms) + sizeof(int) * ms->ifmr.ifm_count); 472 if (ms2 == NULL) { 473 h->error.errtype = OTHER; 474 h->error.errcode = ENOMEM; 475 free(ms); 476 return (-1); 477 } 478 ms2->ifmr.ifm_ulist = &ms2->medialist[0]; 479 480 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms2->ifmr) < 0) { 481 free(ms2); 482 return (-1); 483 } 484 485 *ifmr = &ms2->ifmr; 486 return (0); 487 } 488 489 const char * 490 ifconfig_media_get_status(const struct ifmediareq *ifmr) 491 { 492 switch (IFM_TYPE(ifmr->ifm_active)) { 493 case IFM_ETHER: 494 case IFM_ATM: 495 if (ifmr->ifm_status & IFM_ACTIVE) { 496 return ("active"); 497 } else { 498 return ("no carrier"); 499 } 500 break; 501 502 case IFM_IEEE80211: 503 if (ifmr->ifm_status & IFM_ACTIVE) { 504 /* NB: only sta mode associates */ 505 if (IFM_OPMODE(ifmr->ifm_active) == IFM_IEEE80211_STA) { 506 return ("associated"); 507 } else { 508 return ("running"); 509 } 510 } else { 511 return ("no carrier"); 512 } 513 break; 514 default: 515 return (""); 516 } 517 } 518 519 int 520 ifconfig_media_get_downreason(ifconfig_handle_t *h, const char *name, 521 struct ifdownreason *ifdr) 522 { 523 524 (void)memset(ifdr, 0, sizeof(*ifdr)); 525 (void)strlcpy(ifdr->ifdr_name, name, sizeof(ifdr->ifdr_name)); 526 return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDOWNREASON, ifdr)); 527 } 528