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

Cache object: 93b1583482e1275ef4d85ab2ade8bd3c


[ 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.