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 *
lookup_media_desc(const struct ifmedia_description * desc,const char * name)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 *
get_toptype_ttos(ifmedia_t media)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 *
ifconfig_media_get_type(ifmedia_t media)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
ifconfig_media_lookup_type(const char * name)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 *
ifconfig_media_get_subtype(ifmedia_t media)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
ifconfig_media_lookup_subtype(ifmedia_t media,const char * name)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 *
ifconfig_media_get_mode(ifmedia_t media)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
ifconfig_media_lookup_mode(ifmedia_t media,const char * name)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 **
ifconfig_media_get_options(ifmedia_t media)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 *
ifconfig_media_lookup_options(ifmedia_t media,const char ** opts,size_t nopts)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
ifconfig_media_get_mediareq(ifconfig_handle_t * h,const char * name,struct ifmediareq ** ifmr)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 *
ifconfig_media_get_status(const struct ifmediareq * ifmr)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
ifconfig_media_get_downreason(ifconfig_handle_t * h,const char * name,struct ifdownreason * ifdr)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