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