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 <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "libifconfig.h" 54 #include "libifconfig_internal.h" 55 56 57 static struct ifmedia_description *get_toptype_desc(int); 58 static struct ifmedia_type_to_subtype *get_toptype_ttos(int); 59 static struct ifmedia_description *get_subtype_desc(int, 60 struct ifmedia_type_to_subtype *ttos); 61 62 #define IFM_OPMODE(x) \ 63 ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ 64 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \ 65 IFM_IEEE80211_MBSS)) 66 #define IFM_IEEE80211_STA 0 67 68 static struct ifmedia_description ifm_type_descriptions[] = 69 IFM_TYPE_DESCRIPTIONS; 70 71 static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = 72 IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; 73 74 static struct ifmedia_description ifm_subtype_ethernet_aliases[] = 75 IFM_SUBTYPE_ETHERNET_ALIASES; 76 77 static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = 78 IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; 79 80 static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = 81 IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; 82 83 static struct ifmedia_description ifm_subtype_tokenring_aliases[] = 84 IFM_SUBTYPE_TOKENRING_ALIASES; 85 86 static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = 87 IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; 88 89 static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = 90 IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; 91 92 static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = 93 IFM_SUBTYPE_IEEE80211_ALIASES; 94 95 static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = 96 IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; 97 98 static struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = 99 IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; 100 101 static struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = 102 IFM_SUBTYPE_IEEE80211_MODE_ALIASES; 103 104 static struct ifmedia_description ifm_subtype_atm_descriptions[] = 105 IFM_SUBTYPE_ATM_DESCRIPTIONS; 106 107 static struct ifmedia_description ifm_subtype_atm_aliases[] = 108 IFM_SUBTYPE_ATM_ALIASES; 109 110 static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = 111 IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; 112 113 static struct ifmedia_description ifm_subtype_shared_descriptions[] = 114 IFM_SUBTYPE_SHARED_DESCRIPTIONS; 115 116 static struct ifmedia_description ifm_subtype_shared_aliases[] = 117 IFM_SUBTYPE_SHARED_ALIASES; 118 119 static struct ifmedia_description ifm_shared_option_descriptions[] = 120 IFM_SHARED_OPTION_DESCRIPTIONS; 121 122 static struct ifmedia_description ifm_shared_option_aliases[] = 123 IFM_SHARED_OPTION_ALIASES; 124 125 struct ifmedia_type_to_subtype { 126 struct { 127 struct ifmedia_description *desc; 128 int alias; 129 } 130 subtypes[5]; 131 struct { 132 struct ifmedia_description *desc; 133 int alias; 134 } 135 options[4]; 136 struct { 137 struct ifmedia_description *desc; 138 int alias; 139 } 140 modes[3]; 141 }; 142 143 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 144 static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = 145 { 146 { 147 { 148 { &ifm_subtype_shared_descriptions[0], 0 }, 149 { &ifm_subtype_shared_aliases[0], 1 }, 150 { &ifm_subtype_ethernet_descriptions[0], 0 }, 151 { &ifm_subtype_ethernet_aliases[0], 1 }, 152 { NULL, 0 }, 153 }, 154 { 155 { &ifm_shared_option_descriptions[0], 0 }, 156 { &ifm_shared_option_aliases[0], 1 }, 157 { &ifm_subtype_ethernet_option_descriptions[0], 0 }, 158 { NULL, 0 }, 159 }, 160 { 161 { NULL, 0 }, 162 }, 163 }, 164 { 165 { 166 { &ifm_subtype_shared_descriptions[0], 0 }, 167 { &ifm_subtype_shared_aliases[0], 1 }, 168 { &ifm_subtype_tokenring_descriptions[0], 0 }, 169 { &ifm_subtype_tokenring_aliases[0], 1 }, 170 { NULL, 0 }, 171 }, 172 { 173 { &ifm_shared_option_descriptions[0], 0 }, 174 { &ifm_shared_option_aliases[0], 1 }, 175 { &ifm_subtype_tokenring_option_descriptions[0], 0 }, 176 { NULL, 0 }, 177 }, 178 { 179 { NULL, 0 }, 180 }, 181 }, 182 { 183 { 184 { &ifm_subtype_shared_descriptions[0], 0 }, 185 { &ifm_subtype_shared_aliases[0], 1 }, 186 { &ifm_subtype_ieee80211_descriptions[0], 0 }, 187 { &ifm_subtype_ieee80211_aliases[0], 1 }, 188 { NULL, 0 }, 189 }, 190 { 191 { &ifm_shared_option_descriptions[0], 0 }, 192 { &ifm_shared_option_aliases[0], 1 }, 193 { &ifm_subtype_ieee80211_option_descriptions[0], 0 }, 194 { NULL, 0 }, 195 }, 196 { 197 { &ifm_subtype_ieee80211_mode_descriptions[0], 0 }, 198 { &ifm_subtype_ieee80211_mode_aliases[0], 0 }, 199 { NULL, 0 }, 200 }, 201 }, 202 { 203 { 204 { &ifm_subtype_shared_descriptions[0], 0 }, 205 { &ifm_subtype_shared_aliases[0], 1 }, 206 { &ifm_subtype_atm_descriptions[0], 0 }, 207 { &ifm_subtype_atm_aliases[0], 1 }, 208 { NULL, 0 }, 209 }, 210 { 211 { &ifm_shared_option_descriptions[0], 0 }, 212 { &ifm_shared_option_aliases[0], 1 }, 213 { &ifm_subtype_atm_option_descriptions[0], 0 }, 214 { NULL, 0 }, 215 }, 216 { 217 { NULL, 0 }, 218 }, 219 }, 220 }; 221 222 static struct ifmedia_description * 223 get_toptype_desc(int ifmw) 224 { 225 struct ifmedia_description *desc; 226 227 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) { 228 if (IFM_TYPE(ifmw) == desc->ifmt_word) { 229 break; 230 } 231 } 232 233 return (desc); 234 } 235 236 static struct ifmedia_type_to_subtype * 237 get_toptype_ttos(int ifmw) 238 { 239 struct ifmedia_description *desc; 240 struct ifmedia_type_to_subtype *ttos; 241 242 for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; 243 desc->ifmt_string != NULL; desc++, ttos++) { 244 if (IFM_TYPE(ifmw) == desc->ifmt_word) { 245 break; 246 } 247 } 248 249 return (ttos); 250 } 251 252 static struct ifmedia_description * 253 get_subtype_desc(int ifmw, 254 struct ifmedia_type_to_subtype *ttos) 255 { 256 int i; 257 struct ifmedia_description *desc; 258 259 for (i = 0; ttos->subtypes[i].desc != NULL; i++) { 260 if (ttos->subtypes[i].alias) { 261 continue; 262 } 263 for (desc = ttos->subtypes[i].desc; 264 desc->ifmt_string != NULL; desc++) { 265 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) { 266 return (desc); 267 } 268 } 269 } 270 271 return (NULL); 272 } 273 274 const char * 275 ifconfig_media_get_type(int ifmw) 276 { 277 struct ifmedia_description *desc; 278 279 /*int seen_option = 0, i;*/ 280 281 /* Find the top-level interface type. */ 282 desc = get_toptype_desc(ifmw); 283 if (desc->ifmt_string == NULL) { 284 return ("<unknown type>"); 285 } else { 286 return (desc->ifmt_string); 287 } 288 } 289 290 const char * 291 ifconfig_media_get_subtype(int ifmw) 292 { 293 struct ifmedia_description *desc; 294 struct ifmedia_type_to_subtype *ttos; 295 296 ttos = get_toptype_ttos(ifmw); 297 desc = get_subtype_desc(ifmw, ttos); 298 return (desc->ifmt_string); 299 } 300 301 /*************************************************************************** 302 * Above this point, this file is mostly copied from sbin/ifconfig/ifmedia.c 303 ***************************************************************************/ 304 305 /* Internal structure used for allocations and frees */ 306 struct _ifconfig_media_status { 307 struct ifmediareq ifmr; 308 int medialist[0]; 309 }; 310 311 int 312 ifconfig_media_get_mediareq(ifconfig_handle_t *h, const char *name, 313 struct ifmediareq **ifmr) 314 { 315 struct _ifconfig_media_status *ms, *ms2; 316 unsigned long cmd = SIOCGIFXMEDIA; 317 318 *ifmr = NULL; 319 ms = calloc(1, sizeof(*ms)); 320 if (ms == NULL) { 321 h->error.errtype = OTHER; 322 h->error.errcode = ENOMEM; 323 return (-1); 324 } 325 (void)memset(ms, 0, sizeof(*ms)); 326 (void)strlcpy(ms->ifmr.ifm_name, name, sizeof(ms->ifmr.ifm_name)); 327 328 /* 329 * Check if interface supports extended media types. 330 */ 331 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { 332 cmd = SIOCGIFMEDIA; 333 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms->ifmr) < 0) { 334 /* Interface doesn't support SIOC{G,S}IFMEDIA. */ 335 h->error.errtype = OK; 336 free(ms); 337 return (-1); 338 } 339 } 340 if (ms->ifmr.ifm_count == 0) { 341 *ifmr = &ms->ifmr; 342 return (0); /* Interface has no media types ?*/ 343 } 344 345 ms2 = realloc(ms, sizeof(*ms) + sizeof(int) * ms->ifmr.ifm_count); 346 if (ms2 == NULL) { 347 h->error.errtype = OTHER; 348 h->error.errcode = ENOMEM; 349 free(ms); 350 return (-1); 351 } 352 ms2->ifmr.ifm_ulist = &ms2->medialist[0]; 353 354 if (ifconfig_ioctlwrap(h, AF_LOCAL, cmd, &ms2->ifmr) < 0) { 355 free(ms2); 356 return (-1); 357 } 358 359 *ifmr = &ms2->ifmr; 360 return (0); 361 } 362 363 const char * 364 ifconfig_media_get_status(const struct ifmediareq *ifmr) 365 { 366 switch (IFM_TYPE(ifmr->ifm_active)) { 367 case IFM_ETHER: 368 case IFM_ATM: 369 if (ifmr->ifm_status & IFM_ACTIVE) { 370 return ("active"); 371 } else { 372 return ("no carrier"); 373 } 374 break; 375 376 case IFM_IEEE80211: 377 if (ifmr->ifm_status & IFM_ACTIVE) { 378 /* NB: only sta mode associates */ 379 if (IFM_OPMODE(ifmr->ifm_active) == IFM_IEEE80211_STA) { 380 return ("associated"); 381 } else { 382 return ("running"); 383 } 384 } else { 385 return ("no carrier"); 386 } 387 break; 388 default: 389 return (""); 390 } 391 } 392 393 void 394 ifconfig_media_get_options_string(int ifmw, char *buf, size_t buflen) 395 { 396 struct ifmedia_type_to_subtype *ttos; 397 struct ifmedia_description *desc; 398 int i, seen_option = 0; 399 size_t len; 400 401 assert(buflen > 0); 402 buf[0] = '\0'; 403 ttos = get_toptype_ttos(ifmw); 404 for (i = 0; ttos->options[i].desc != NULL; i++) { 405 if (ttos->options[i].alias) { 406 continue; 407 } 408 for (desc = ttos->options[i].desc; 409 desc->ifmt_string != NULL; desc++) { 410 if (ifmw & desc->ifmt_word) { 411 if (seen_option++) { 412 strlcat(buf, ",", buflen); 413 } 414 len = strlcat(buf, desc->ifmt_string, buflen); 415 assert(len < buflen); 416 buf += len; 417 buflen -= len; 418 } 419 } 420 } 421 } 422