Annotation of sys/net/if_media.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_media.c,v 1.16 2005/07/28 02:15:15 brad Exp $ */
2: /* $NetBSD: if_media.c,v 1.10 2000/03/13 23:52:39 soren Exp $ */
3:
4: /*-
5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
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 the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * Copyright (c) 1997
43: * Jonathan Stone and Jason R. Thorpe. All rights reserved.
44: *
45: * This software is derived from information provided by Matt Thomas.
46: *
47: * Redistribution and use in source and binary forms, with or without
48: * modification, are permitted provided that the following conditions
49: * are met:
50: * 1. Redistributions of source code must retain the above copyright
51: * notice, this list of conditions and the following disclaimer.
52: * 2. Redistributions in binary form must reproduce the above copyright
53: * notice, this list of conditions and the following disclaimer in the
54: * documentation and/or other materials provided with the distribution.
55: * 3. All advertising materials mentioning features or use of this software
56: * must display the following acknowledgement:
57: * This product includes software developed by Jonathan Stone
58: * and Jason R. Thorpe for the NetBSD Project.
59: * 4. The names of the authors may not be used to endorse or promote products
60: * derived from this software without specific prior written permission.
61: *
62: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
63: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
64: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
65: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
66: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
67: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
68: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
69: * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
70: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72: * SUCH DAMAGE.
73: */
74:
75: /*
76: * BSD/OS-compatible network interface media selection.
77: *
78: * Where it is safe to do so, this code strays slightly from the BSD/OS
79: * design. Software which uses the API (device drivers, basically)
80: * shouldn't notice any difference.
81: *
82: * Many thanks to Matt Thomas for providing the information necessary
83: * to implement this interface.
84: */
85:
86: #include <sys/param.h>
87: #include <sys/systm.h>
88: #include <sys/errno.h>
89: #include <sys/ioctl.h>
90: #include <sys/socket.h>
91: #include <sys/malloc.h>
92:
93: #include <net/if.h>
94: #include <net/if_media.h>
95: #include <net/netisr.h>
96:
97: /*
98: * Compile-time options:
99: * IFMEDIA_DEBUG:
100: * turn on implementation-level debug printfs.
101: * Useful for debugging newly-ported drivers.
102: */
103:
104: #ifdef IFMEDIA_DEBUG
105: int ifmedia_debug = 0;
106: static void ifmedia_printword(int);
107: #endif
108:
109: /*
110: * Initialize if_media struct for a specific interface instance.
111: */
112: void
113: ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
114: ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
115: {
116: TAILQ_INIT(&ifm->ifm_list);
117: ifm->ifm_cur = NULL;
118: ifm->ifm_media = 0;
119: ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */
120: ifm->ifm_change = change_callback;
121: ifm->ifm_status = status_callback;
122: }
123:
124: /*
125: * Add a media configuration to the list of supported media
126: * for a specific interface instance.
127: */
128: void
129: ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux)
130: {
131: struct ifmedia_entry *entry;
132:
133: #ifdef IFMEDIA_DEBUG
134: if (ifmedia_debug) {
135: if (ifm == NULL) {
136: printf("ifmedia_add: null ifm\n");
137: return;
138: }
139: printf("Adding entry for ");
140: ifmedia_printword(mword);
141: }
142: #endif
143:
144: entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
145: if (entry == NULL)
146: panic("ifmedia_add: can't malloc entry");
147:
148: entry->ifm_media = mword;
149: entry->ifm_data = data;
150: entry->ifm_aux = aux;
151:
152: TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list);
153: }
154:
155: /*
156: * Add an array of media configurations to the list of
157: * supported media for a specific interface instance.
158: */
159: void
160: ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count)
161: {
162: int i;
163:
164: for (i = 0; i < count; i++)
165: ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
166: lp[i].ifm_aux);
167: }
168:
169: /*
170: * Set the default active media.
171: *
172: * Called by device-specific code which is assumed to have already
173: * selected the default media in hardware. We do _not_ call the
174: * media-change callback.
175: */
176: void
177: ifmedia_set(struct ifmedia *ifm, int target)
178: {
179: struct ifmedia_entry *match;
180:
181: match = ifmedia_match(ifm, target, ifm->ifm_mask);
182:
183: /*
184: * If we didn't find the requested media, then we try to fall
185: * back to target-type (IFM_ETHER, e.g.) | IFM_NONE. If that's
186: * not on the list, then we add it and set the media to it.
187: *
188: * Since ifmedia_set is almost always called with IFM_AUTO or
189: * with a known-good media, this really should only occur if we:
190: *
191: * a) didn't find any PHYs, or
192: * b) didn't find an autoselect option on the PHY when the
193: * parent ethernet driver expected to.
194: *
195: * In either case, it makes sense to select no media.
196: */
197: if (match == NULL) {
198: printf("ifmedia_set: no match for 0x%x/0x%x\n",
199: target, ~ifm->ifm_mask);
200: target = (target & IFM_NMASK) | IFM_NONE;
201: match = ifmedia_match(ifm, target, ifm->ifm_mask);
202: if (match == NULL) {
203: ifmedia_add(ifm, target, 0, NULL);
204: match = ifmedia_match(ifm, target, ifm->ifm_mask);
205: if (match == NULL) {
206: panic("ifmedia_set failed");
207: }
208: }
209: }
210: ifm->ifm_cur = match;
211:
212: #ifdef IFMEDIA_DEBUG
213: if (ifmedia_debug) {
214: printf("ifmedia_set: target ");
215: ifmedia_printword(target);
216: printf("ifmedia_set: setting to ");
217: ifmedia_printword(ifm->ifm_cur->ifm_media);
218: }
219: #endif
220: }
221:
222: /*
223: * Device-independent media ioctl support function.
224: */
225: int
226: ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
227: u_long cmd)
228: {
229: struct ifmedia_entry *match;
230: struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
231: int error = 0;
232:
233: if (ifp == NULL || ifr == NULL || ifm == NULL)
234: return (EINVAL);
235:
236: switch (cmd) {
237:
238: /*
239: * Set the current media.
240: */
241: case SIOCSIFMEDIA:
242: {
243: struct ifmedia_entry *oldentry;
244: u_int oldmedia;
245: u_int newmedia = ifr->ifr_media;
246:
247: match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
248: if (match == NULL) {
249: #ifdef IFMEDIA_DEBUG
250: if (ifmedia_debug) {
251: printf(
252: "ifmedia_ioctl: no media found for 0x%x\n",
253: newmedia);
254: }
255: #endif
256: return (EINVAL);
257: }
258:
259: /*
260: * If no change, we're done.
261: * XXX Automedia may involve software intervention.
262: * Keep going in case the connected media changed.
263: * Similarly, if best match changed (kernel debugger?).
264: */
265: if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
266: (newmedia == ifm->ifm_media) &&
267: (match == ifm->ifm_cur))
268: return 0;
269:
270: /*
271: * We found a match, now make the driver switch to it.
272: * Make sure to preserve our old media type in case the
273: * driver can't switch.
274: */
275: #ifdef IFMEDIA_DEBUG
276: if (ifmedia_debug) {
277: printf("ifmedia_ioctl: switching %s to ",
278: ifp->if_xname);
279: ifmedia_printword(match->ifm_media);
280: }
281: #endif
282: oldentry = ifm->ifm_cur;
283: oldmedia = ifm->ifm_media;
284: ifm->ifm_cur = match;
285: ifm->ifm_media = newmedia;
286: error = (*ifm->ifm_change)(ifp);
287: if (error) {
288: ifm->ifm_cur = oldentry;
289: ifm->ifm_media = oldmedia;
290: }
291: break;
292: }
293:
294: /*
295: * Get list of available media and current media on interface.
296: */
297: case SIOCGIFMEDIA:
298: {
299: struct ifmedia_entry *ep;
300: size_t nwords;
301:
302: if(ifmr->ifm_count < 0)
303: return (EINVAL);
304:
305: ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
306: ifm->ifm_cur->ifm_media : IFM_NONE;
307: ifmr->ifm_mask = ifm->ifm_mask;
308: ifmr->ifm_status = 0;
309: (*ifm->ifm_status)(ifp, ifmr);
310:
311: /*
312: * Count them so we know a-priori how much is the max we'll
313: * need.
314: */
315: ep = TAILQ_FIRST(&ifm->ifm_list);
316: for (nwords = 0; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list))
317: nwords++;
318:
319: if (ifmr->ifm_count != 0) {
320: size_t count;
321: size_t minwords = nwords > (size_t)ifmr->ifm_count
322: ? (size_t)ifmr->ifm_count
323: : nwords;
324: int *kptr = (int *)malloc(minwords * sizeof(int),
325: M_TEMP, M_WAITOK);
326: /*
327: * Get the media words from the interface's list.
328: */
329: ep = TAILQ_FIRST(&ifm->ifm_list);
330: for (count = 0; ep != NULL && count < minwords;
331: ep = TAILQ_NEXT(ep, ifm_list), count++)
332: kptr[count] = ep->ifm_media;
333:
334: error = copyout(kptr, ifmr->ifm_ulist,
335: minwords * sizeof(int));
336: if (error == 0 && ep != NULL)
337: error = E2BIG; /* oops! */
338: free(kptr, M_TEMP);
339: }
340: ifmr->ifm_count = nwords;
341: break;
342: }
343:
344: default:
345: return (EINVAL);
346: }
347:
348: return (error);
349: }
350:
351: /*
352: * Find media entry matching a given ifm word.
353: */
354: struct ifmedia_entry *
355: ifmedia_match(struct ifmedia *ifm, u_int target, u_int mask)
356: {
357: struct ifmedia_entry *match, *next;
358:
359: match = NULL;
360: mask = ~mask;
361:
362: for (next = TAILQ_FIRST(&ifm->ifm_list); next != NULL;
363: next = TAILQ_NEXT(next, ifm_list)) {
364: if ((next->ifm_media & mask) == (target & mask)) {
365: if (match) {
366: #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
367: printf("ifmedia_match: multiple match for "
368: "0x%x/0x%x, selected instance %d\n",
369: target, mask, IFM_INST(match->ifm_media));
370: #endif
371: break;
372: }
373: match = next;
374: }
375: }
376:
377: return match;
378: }
379:
380: /*
381: * Delete all media for a given instance.
382: */
383: void
384: ifmedia_delete_instance(struct ifmedia *ifm, u_int inst)
385: {
386: struct ifmedia_entry *ife, *nife;
387:
388: for (ife = TAILQ_FIRST(&ifm->ifm_list); ife != NULL;
389: ife = nife) {
390: nife = TAILQ_NEXT(ife, ifm_list);
391: if (inst == IFM_INST_ANY ||
392: inst == IFM_INST(ife->ifm_media)) {
393: TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list);
394: free(ife, M_IFADDR);
395: }
396: }
397: }
398:
399: /*
400: * Compute the interface `baudrate' from the media, for the interface
401: * metrics (used by routing daemons).
402: */
403: struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
404: IFM_BAUDRATE_DESCRIPTIONS;
405:
406: int
407: ifmedia_baudrate(int mword)
408: {
409: int i;
410:
411: for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
412: if ((mword & (IFM_NMASK|IFM_TMASK)) ==
413: ifmedia_baudrate_descriptions[i].ifmb_word)
414: return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
415: }
416:
417: /* Not known. */
418: return (0);
419: }
420:
421: #ifdef IFMEDIA_DEBUG
422:
423: struct ifmedia_description ifm_type_descriptions[] =
424: IFM_TYPE_DESCRIPTIONS;
425:
426: struct ifmedia_description ifm_subtype_descriptions[] =
427: IFM_SUBTYPE_DESCRIPTIONS;
428:
429: struct ifmedia_description ifm_option_descriptions[] =
430: IFM_OPTION_DESCRIPTIONS;
431:
432: /*
433: * print a media word.
434: */
435: static void
436: ifmedia_printword(int ifmw)
437: {
438: struct ifmedia_description *desc;
439: int seen_option = 0;
440:
441: /* Print the top-level interface type. */
442: for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
443: desc++) {
444: if (IFM_TYPE(ifmw) == desc->ifmt_word)
445: break;
446: }
447: if (desc->ifmt_string == NULL)
448: printf("<unknown type> ");
449: else
450: printf("%s ", desc->ifmt_string);
451:
452: /* Print the subtype. */
453: for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
454: desc++) {
455: if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
456: IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmw))
457: break;
458: }
459: if (desc->ifmt_string == NULL)
460: printf("<unknown subtype>");
461: else
462: printf("%s", desc->ifmt_string);
463:
464: /* Print any options. */
465: for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
466: desc++) {
467: if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
468: (ifmw & desc->ifmt_word) != 0 &&
469: (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
470: if (seen_option == 0)
471: printf(" <");
472: printf("%s%s", seen_option ? "," : "",
473: desc->ifmt_string);
474: seen_option |= IFM_OPTIONS(desc->ifmt_word);
475: }
476: }
477: printf("%s\n", seen_option ? ">" : "");
478: }
479:
480: #endif /* IFMEDIA_DEBUG */
CVSweb