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