The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/net/if_media.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: b8dcf6c34cbdbdf605b07afba132e0a6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.