1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | /* $NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $ */ |
---|
4 | /* $FreeBSD$ */ |
---|
5 | |
---|
6 | /*- |
---|
7 | * Copyright (c) 1997 |
---|
8 | * Jonathan Stone and Jason R. Thorpe. All rights reserved. |
---|
9 | * |
---|
10 | * This software is derived from information provided by Matt Thomas. |
---|
11 | * |
---|
12 | * Redistribution and use in source and binary forms, with or without |
---|
13 | * modification, are permitted provided that the following conditions |
---|
14 | * are met: |
---|
15 | * 1. Redistributions of source code must retain the above copyright |
---|
16 | * notice, this list of conditions and the following disclaimer. |
---|
17 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
18 | * notice, this list of conditions and the following disclaimer in the |
---|
19 | * documentation and/or other materials provided with the distribution. |
---|
20 | * 3. All advertising materials mentioning features or use of this software |
---|
21 | * must display the following acknowledgement: |
---|
22 | * This product includes software developed by Jonathan Stone |
---|
23 | * and Jason R. Thorpe for the NetBSD Project. |
---|
24 | * 4. The names of the authors may not be used to endorse or promote products |
---|
25 | * derived from this software without specific prior written permission. |
---|
26 | * |
---|
27 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR |
---|
28 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
29 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
30 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
31 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
---|
32 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
33 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
---|
34 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
---|
35 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
37 | * SUCH DAMAGE. |
---|
38 | */ |
---|
39 | |
---|
40 | /* |
---|
41 | * BSD/OS-compatible network interface media selection. |
---|
42 | * |
---|
43 | * Where it is safe to do so, this code strays slightly from the BSD/OS |
---|
44 | * design. Software which uses the API (device drivers, basically) |
---|
45 | * shouldn't notice any difference. |
---|
46 | * |
---|
47 | * Many thanks to Matt Thomas for providing the information necessary |
---|
48 | * to implement this interface. |
---|
49 | */ |
---|
50 | |
---|
51 | #include <rtems/bsd/local/opt_ifmedia.h> |
---|
52 | |
---|
53 | #include <sys/param.h> |
---|
54 | #include <sys/systm.h> |
---|
55 | #include <sys/socket.h> |
---|
56 | #include <sys/sockio.h> |
---|
57 | #include <sys/malloc.h> |
---|
58 | #include <sys/module.h> |
---|
59 | #include <sys/sysctl.h> |
---|
60 | |
---|
61 | #include <net/if.h> |
---|
62 | #include <net/if_media.h> |
---|
63 | |
---|
64 | /* |
---|
65 | * Compile-time options: |
---|
66 | * IFMEDIA_DEBUG: |
---|
67 | * turn on implementation-level debug printfs. |
---|
68 | * Useful for debugging newly-ported drivers. |
---|
69 | */ |
---|
70 | |
---|
71 | static struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm, |
---|
72 | int flags, int mask); |
---|
73 | |
---|
74 | #ifdef IFMEDIA_DEBUG |
---|
75 | #include <net/if_var.h> |
---|
76 | int ifmedia_debug = 0; |
---|
77 | SYSCTL_INT(_debug, OID_AUTO, ifmedia, CTLFLAG_RW, &ifmedia_debug, |
---|
78 | 0, "if_media debugging msgs"); |
---|
79 | static void ifmedia_printword(int); |
---|
80 | #endif |
---|
81 | |
---|
82 | /* |
---|
83 | * Initialize if_media struct for a specific interface instance. |
---|
84 | */ |
---|
85 | void |
---|
86 | ifmedia_init(ifm, dontcare_mask, change_callback, status_callback) |
---|
87 | struct ifmedia *ifm; |
---|
88 | int dontcare_mask; |
---|
89 | ifm_change_cb_t change_callback; |
---|
90 | ifm_stat_cb_t status_callback; |
---|
91 | { |
---|
92 | |
---|
93 | LIST_INIT(&ifm->ifm_list); |
---|
94 | ifm->ifm_cur = NULL; |
---|
95 | ifm->ifm_media = 0; |
---|
96 | ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */ |
---|
97 | ifm->ifm_change = change_callback; |
---|
98 | ifm->ifm_status = status_callback; |
---|
99 | } |
---|
100 | |
---|
101 | void |
---|
102 | ifmedia_removeall(ifm) |
---|
103 | struct ifmedia *ifm; |
---|
104 | { |
---|
105 | struct ifmedia_entry *entry; |
---|
106 | |
---|
107 | for (entry = LIST_FIRST(&ifm->ifm_list); entry; |
---|
108 | entry = LIST_FIRST(&ifm->ifm_list)) { |
---|
109 | LIST_REMOVE(entry, ifm_list); |
---|
110 | free(entry, M_IFADDR); |
---|
111 | } |
---|
112 | ifm->ifm_cur = NULL; |
---|
113 | } |
---|
114 | |
---|
115 | /* |
---|
116 | * Add a media configuration to the list of supported media |
---|
117 | * for a specific interface instance. |
---|
118 | */ |
---|
119 | void |
---|
120 | ifmedia_add(ifm, mword, data, aux) |
---|
121 | struct ifmedia *ifm; |
---|
122 | int mword; |
---|
123 | int data; |
---|
124 | void *aux; |
---|
125 | { |
---|
126 | register struct ifmedia_entry *entry; |
---|
127 | |
---|
128 | #ifdef IFMEDIA_DEBUG |
---|
129 | if (ifmedia_debug) { |
---|
130 | if (ifm == NULL) { |
---|
131 | printf("ifmedia_add: null ifm\n"); |
---|
132 | return; |
---|
133 | } |
---|
134 | printf("Adding entry for "); |
---|
135 | ifmedia_printword(mword); |
---|
136 | } |
---|
137 | #endif |
---|
138 | |
---|
139 | entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT); |
---|
140 | if (entry == NULL) |
---|
141 | panic("ifmedia_add: can't malloc entry"); |
---|
142 | |
---|
143 | entry->ifm_media = mword; |
---|
144 | entry->ifm_data = data; |
---|
145 | entry->ifm_aux = aux; |
---|
146 | |
---|
147 | LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list); |
---|
148 | } |
---|
149 | |
---|
150 | /* |
---|
151 | * Add an array of media configurations to the list of |
---|
152 | * supported media for a specific interface instance. |
---|
153 | */ |
---|
154 | void |
---|
155 | ifmedia_list_add(ifm, lp, count) |
---|
156 | struct ifmedia *ifm; |
---|
157 | struct ifmedia_entry *lp; |
---|
158 | int count; |
---|
159 | { |
---|
160 | int i; |
---|
161 | |
---|
162 | for (i = 0; i < count; i++) |
---|
163 | ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data, |
---|
164 | lp[i].ifm_aux); |
---|
165 | } |
---|
166 | |
---|
167 | /* |
---|
168 | * Set the default active media. |
---|
169 | * |
---|
170 | * Called by device-specific code which is assumed to have already |
---|
171 | * selected the default media in hardware. We do _not_ call the |
---|
172 | * media-change callback. |
---|
173 | */ |
---|
174 | void |
---|
175 | ifmedia_set(ifm, target) |
---|
176 | struct ifmedia *ifm; |
---|
177 | int target; |
---|
178 | |
---|
179 | { |
---|
180 | struct ifmedia_entry *match; |
---|
181 | |
---|
182 | match = ifmedia_match(ifm, target, ifm->ifm_mask); |
---|
183 | |
---|
184 | if (match == NULL) { |
---|
185 | printf("ifmedia_set: no match for 0x%x/0x%x\n", |
---|
186 | target, ~ifm->ifm_mask); |
---|
187 | panic("ifmedia_set"); |
---|
188 | } |
---|
189 | ifm->ifm_cur = match; |
---|
190 | |
---|
191 | #ifdef IFMEDIA_DEBUG |
---|
192 | if (ifmedia_debug) { |
---|
193 | printf("ifmedia_set: target "); |
---|
194 | ifmedia_printword(target); |
---|
195 | printf("ifmedia_set: setting to "); |
---|
196 | ifmedia_printword(ifm->ifm_cur->ifm_media); |
---|
197 | } |
---|
198 | #endif |
---|
199 | } |
---|
200 | |
---|
201 | /* |
---|
202 | * Given a media word, return one suitable for an application |
---|
203 | * using the original encoding. |
---|
204 | */ |
---|
205 | static int |
---|
206 | compat_media(int media) |
---|
207 | { |
---|
208 | |
---|
209 | if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) { |
---|
210 | media &= ~(IFM_ETH_XTYPE|IFM_TMASK); |
---|
211 | media |= IFM_OTHER; |
---|
212 | } |
---|
213 | return (media); |
---|
214 | } |
---|
215 | |
---|
216 | /* |
---|
217 | * Device-independent media ioctl support function. |
---|
218 | */ |
---|
219 | int |
---|
220 | ifmedia_ioctl(ifp, ifr, ifm, cmd) |
---|
221 | struct ifnet *ifp; |
---|
222 | struct ifreq *ifr; |
---|
223 | struct ifmedia *ifm; |
---|
224 | u_long cmd; |
---|
225 | { |
---|
226 | struct ifmedia_entry *match; |
---|
227 | struct ifmediareq *ifmr = (struct ifmediareq *) ifr; |
---|
228 | int error = 0; |
---|
229 | |
---|
230 | if (ifp == NULL || ifr == NULL || ifm == NULL) |
---|
231 | return(EINVAL); |
---|
232 | |
---|
233 | switch (cmd) { |
---|
234 | |
---|
235 | /* |
---|
236 | * Set the current media. |
---|
237 | */ |
---|
238 | case SIOCSIFMEDIA: |
---|
239 | { |
---|
240 | struct ifmedia_entry *oldentry; |
---|
241 | int oldmedia; |
---|
242 | int newmedia = ifr->ifr_media; |
---|
243 | |
---|
244 | match = ifmedia_match(ifm, newmedia, ifm->ifm_mask); |
---|
245 | if (match == NULL) { |
---|
246 | #ifdef IFMEDIA_DEBUG |
---|
247 | if (ifmedia_debug) { |
---|
248 | printf( |
---|
249 | "ifmedia_ioctl: no media found for 0x%x\n", |
---|
250 | newmedia); |
---|
251 | } |
---|
252 | #endif |
---|
253 | return (ENXIO); |
---|
254 | } |
---|
255 | |
---|
256 | /* |
---|
257 | * If no change, we're done. |
---|
258 | * XXX Automedia may invole software intervention. |
---|
259 | * Keep going in case the connected media changed. |
---|
260 | * Similarly, if best match changed (kernel debugger?). |
---|
261 | */ |
---|
262 | if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) && |
---|
263 | (newmedia == ifm->ifm_media) && |
---|
264 | (match == ifm->ifm_cur)) |
---|
265 | return 0; |
---|
266 | |
---|
267 | /* |
---|
268 | * We found a match, now make the driver switch to it. |
---|
269 | * Make sure to preserve our old media type in case the |
---|
270 | * driver can't switch. |
---|
271 | */ |
---|
272 | #ifdef IFMEDIA_DEBUG |
---|
273 | if (ifmedia_debug) { |
---|
274 | printf("ifmedia_ioctl: switching %s to ", |
---|
275 | ifp->if_xname); |
---|
276 | ifmedia_printword(match->ifm_media); |
---|
277 | } |
---|
278 | #endif |
---|
279 | oldentry = ifm->ifm_cur; |
---|
280 | oldmedia = ifm->ifm_media; |
---|
281 | ifm->ifm_cur = match; |
---|
282 | ifm->ifm_media = newmedia; |
---|
283 | error = (*ifm->ifm_change)(ifp); |
---|
284 | if (error) { |
---|
285 | ifm->ifm_cur = oldentry; |
---|
286 | ifm->ifm_media = oldmedia; |
---|
287 | } |
---|
288 | break; |
---|
289 | } |
---|
290 | |
---|
291 | /* |
---|
292 | * Get list of available media and current media on interface. |
---|
293 | */ |
---|
294 | case SIOCGIFMEDIA: |
---|
295 | case SIOCGIFXMEDIA: |
---|
296 | { |
---|
297 | struct ifmedia_entry *ep; |
---|
298 | int i; |
---|
299 | |
---|
300 | if (ifmr->ifm_count < 0) |
---|
301 | return (EINVAL); |
---|
302 | |
---|
303 | if (cmd == SIOCGIFMEDIA) { |
---|
304 | ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? |
---|
305 | compat_media(ifm->ifm_cur->ifm_media) : IFM_NONE; |
---|
306 | } else { |
---|
307 | ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? |
---|
308 | ifm->ifm_cur->ifm_media : IFM_NONE; |
---|
309 | } |
---|
310 | ifmr->ifm_mask = ifm->ifm_mask; |
---|
311 | ifmr->ifm_status = 0; |
---|
312 | (*ifm->ifm_status)(ifp, ifmr); |
---|
313 | |
---|
314 | /* |
---|
315 | * If there are more interfaces on the list, count |
---|
316 | * them. This allows the caller to set ifmr->ifm_count |
---|
317 | * to 0 on the first call to know how much space to |
---|
318 | * allocate. |
---|
319 | */ |
---|
320 | i = 0; |
---|
321 | LIST_FOREACH(ep, &ifm->ifm_list, ifm_list) |
---|
322 | if (i++ < ifmr->ifm_count) { |
---|
323 | error = copyout(&ep->ifm_media, |
---|
324 | ifmr->ifm_ulist + i - 1, sizeof(int)); |
---|
325 | if (error) |
---|
326 | break; |
---|
327 | } |
---|
328 | if (error == 0 && i > ifmr->ifm_count) |
---|
329 | error = ifmr->ifm_count ? E2BIG : 0; |
---|
330 | ifmr->ifm_count = i; |
---|
331 | break; |
---|
332 | } |
---|
333 | |
---|
334 | default: |
---|
335 | return (EINVAL); |
---|
336 | } |
---|
337 | |
---|
338 | return (error); |
---|
339 | } |
---|
340 | |
---|
341 | /* |
---|
342 | * Find media entry matching a given ifm word. |
---|
343 | * |
---|
344 | */ |
---|
345 | static struct ifmedia_entry * |
---|
346 | ifmedia_match(ifm, target, mask) |
---|
347 | struct ifmedia *ifm; |
---|
348 | int target; |
---|
349 | int mask; |
---|
350 | { |
---|
351 | struct ifmedia_entry *match, *next; |
---|
352 | |
---|
353 | match = NULL; |
---|
354 | mask = ~mask; |
---|
355 | |
---|
356 | LIST_FOREACH(next, &ifm->ifm_list, ifm_list) { |
---|
357 | if ((next->ifm_media & mask) == (target & mask)) { |
---|
358 | #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) |
---|
359 | if (match) { |
---|
360 | printf("ifmedia_match: multiple match for " |
---|
361 | "0x%x/0x%x\n", target, mask); |
---|
362 | } |
---|
363 | #endif |
---|
364 | match = next; |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | return match; |
---|
369 | } |
---|
370 | |
---|
371 | /* |
---|
372 | * Compute the interface `baudrate' from the media, for the interface |
---|
373 | * metrics (used by routing daemons). |
---|
374 | */ |
---|
375 | static const struct ifmedia_baudrate ifmedia_baudrate_descriptions[] = |
---|
376 | IFM_BAUDRATE_DESCRIPTIONS; |
---|
377 | |
---|
378 | uint64_t |
---|
379 | ifmedia_baudrate(int mword) |
---|
380 | { |
---|
381 | int i; |
---|
382 | |
---|
383 | for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) { |
---|
384 | if (IFM_TYPE_MATCH(mword, ifmedia_baudrate_descriptions[i].ifmb_word)) |
---|
385 | return (ifmedia_baudrate_descriptions[i].ifmb_baudrate); |
---|
386 | } |
---|
387 | |
---|
388 | /* Not known. */ |
---|
389 | return (0); |
---|
390 | } |
---|
391 | |
---|
392 | #ifdef IFMEDIA_DEBUG |
---|
393 | struct ifmedia_description ifm_type_descriptions[] = |
---|
394 | IFM_TYPE_DESCRIPTIONS; |
---|
395 | |
---|
396 | struct ifmedia_description ifm_subtype_ethernet_descriptions[] = |
---|
397 | IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; |
---|
398 | |
---|
399 | struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = |
---|
400 | IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; |
---|
401 | |
---|
402 | struct ifmedia_description ifm_subtype_tokenring_descriptions[] = |
---|
403 | IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; |
---|
404 | |
---|
405 | struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = |
---|
406 | IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; |
---|
407 | |
---|
408 | struct ifmedia_description ifm_subtype_fddi_descriptions[] = |
---|
409 | IFM_SUBTYPE_FDDI_DESCRIPTIONS; |
---|
410 | |
---|
411 | struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = |
---|
412 | IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; |
---|
413 | |
---|
414 | struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = |
---|
415 | IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; |
---|
416 | |
---|
417 | struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = |
---|
418 | IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; |
---|
419 | |
---|
420 | struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = |
---|
421 | IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; |
---|
422 | |
---|
423 | struct ifmedia_description ifm_subtype_atm_descriptions[] = |
---|
424 | IFM_SUBTYPE_ATM_DESCRIPTIONS; |
---|
425 | |
---|
426 | struct ifmedia_description ifm_subtype_atm_option_descriptions[] = |
---|
427 | IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; |
---|
428 | |
---|
429 | struct ifmedia_description ifm_subtype_shared_descriptions[] = |
---|
430 | IFM_SUBTYPE_SHARED_DESCRIPTIONS; |
---|
431 | |
---|
432 | struct ifmedia_description ifm_shared_option_descriptions[] = |
---|
433 | IFM_SHARED_OPTION_DESCRIPTIONS; |
---|
434 | |
---|
435 | struct ifmedia_type_to_subtype { |
---|
436 | struct ifmedia_description *subtypes; |
---|
437 | struct ifmedia_description *options; |
---|
438 | struct ifmedia_description *modes; |
---|
439 | }; |
---|
440 | |
---|
441 | /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ |
---|
442 | struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { |
---|
443 | { |
---|
444 | &ifm_subtype_ethernet_descriptions[0], |
---|
445 | &ifm_subtype_ethernet_option_descriptions[0], |
---|
446 | NULL, |
---|
447 | }, |
---|
448 | { |
---|
449 | &ifm_subtype_tokenring_descriptions[0], |
---|
450 | &ifm_subtype_tokenring_option_descriptions[0], |
---|
451 | NULL, |
---|
452 | }, |
---|
453 | { |
---|
454 | &ifm_subtype_fddi_descriptions[0], |
---|
455 | &ifm_subtype_fddi_option_descriptions[0], |
---|
456 | NULL, |
---|
457 | }, |
---|
458 | { |
---|
459 | &ifm_subtype_ieee80211_descriptions[0], |
---|
460 | &ifm_subtype_ieee80211_option_descriptions[0], |
---|
461 | &ifm_subtype_ieee80211_mode_descriptions[0] |
---|
462 | }, |
---|
463 | { |
---|
464 | &ifm_subtype_atm_descriptions[0], |
---|
465 | &ifm_subtype_atm_option_descriptions[0], |
---|
466 | NULL, |
---|
467 | }, |
---|
468 | }; |
---|
469 | |
---|
470 | /* |
---|
471 | * print a media word. |
---|
472 | */ |
---|
473 | static void |
---|
474 | ifmedia_printword(ifmw) |
---|
475 | int ifmw; |
---|
476 | { |
---|
477 | struct ifmedia_description *desc; |
---|
478 | struct ifmedia_type_to_subtype *ttos; |
---|
479 | int seen_option = 0; |
---|
480 | |
---|
481 | /* Find the top-level interface type. */ |
---|
482 | for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; |
---|
483 | desc->ifmt_string != NULL; desc++, ttos++) |
---|
484 | if (IFM_TYPE(ifmw) == desc->ifmt_word) |
---|
485 | break; |
---|
486 | if (desc->ifmt_string == NULL) { |
---|
487 | printf("<unknown type>\n"); |
---|
488 | return; |
---|
489 | } |
---|
490 | printf("%s", desc->ifmt_string); |
---|
491 | |
---|
492 | /* Any mode. */ |
---|
493 | for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++) |
---|
494 | if (IFM_MODE(ifmw) == desc->ifmt_word) { |
---|
495 | if (desc->ifmt_string != NULL) |
---|
496 | printf(" mode %s", desc->ifmt_string); |
---|
497 | break; |
---|
498 | } |
---|
499 | |
---|
500 | /* |
---|
501 | * Check for the shared subtype descriptions first, then the |
---|
502 | * type-specific ones. |
---|
503 | */ |
---|
504 | for (desc = ifm_subtype_shared_descriptions; |
---|
505 | desc->ifmt_string != NULL; desc++) |
---|
506 | if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) |
---|
507 | goto got_subtype; |
---|
508 | |
---|
509 | for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++) |
---|
510 | if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) |
---|
511 | break; |
---|
512 | if (desc->ifmt_string == NULL) { |
---|
513 | printf(" <unknown subtype>\n"); |
---|
514 | return; |
---|
515 | } |
---|
516 | |
---|
517 | got_subtype: |
---|
518 | printf(" %s", desc->ifmt_string); |
---|
519 | |
---|
520 | /* |
---|
521 | * Look for shared options. |
---|
522 | */ |
---|
523 | for (desc = ifm_shared_option_descriptions; |
---|
524 | desc->ifmt_string != NULL; desc++) { |
---|
525 | if (ifmw & desc->ifmt_word) { |
---|
526 | if (seen_option == 0) |
---|
527 | printf(" <"); |
---|
528 | printf("%s%s", seen_option++ ? "," : "", |
---|
529 | desc->ifmt_string); |
---|
530 | } |
---|
531 | } |
---|
532 | |
---|
533 | /* |
---|
534 | * Look for subtype-specific options. |
---|
535 | */ |
---|
536 | for (desc = ttos->options; desc->ifmt_string != NULL; desc++) { |
---|
537 | if (ifmw & desc->ifmt_word) { |
---|
538 | if (seen_option == 0) |
---|
539 | printf(" <"); |
---|
540 | printf("%s%s", seen_option++ ? "," : "", |
---|
541 | desc->ifmt_string); |
---|
542 | } |
---|
543 | } |
---|
544 | printf("%s\n", seen_option ? ">" : ""); |
---|
545 | } |
---|
546 | #endif /* IFMEDIA_DEBUG */ |
---|