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