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/12.0/sys/net/if_media.c 332895 2018-04-23 21:10:33Z brooks $ */
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-4-Clause
    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 "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         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_ieee80211_descriptions[] =
  403     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
  404 
  405 struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
  406     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
  407 
  408 struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
  409     IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
  410 
  411 struct ifmedia_description ifm_subtype_atm_descriptions[] =
  412     IFM_SUBTYPE_ATM_DESCRIPTIONS;
  413 
  414 struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
  415     IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
  416 
  417 struct ifmedia_description ifm_subtype_shared_descriptions[] =
  418     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
  419 
  420 struct ifmedia_description ifm_shared_option_descriptions[] =
  421     IFM_SHARED_OPTION_DESCRIPTIONS;
  422 
  423 struct ifmedia_type_to_subtype {
  424         struct ifmedia_description *subtypes;
  425         struct ifmedia_description *options;
  426         struct ifmedia_description *modes;
  427 };
  428 
  429 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
  430 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
  431         {
  432           &ifm_subtype_ethernet_descriptions[0],
  433           &ifm_subtype_ethernet_option_descriptions[0],
  434           NULL,
  435         },
  436         {
  437           &ifm_subtype_ieee80211_descriptions[0],
  438           &ifm_subtype_ieee80211_option_descriptions[0],
  439           &ifm_subtype_ieee80211_mode_descriptions[0]
  440         },
  441         {
  442           &ifm_subtype_atm_descriptions[0],
  443           &ifm_subtype_atm_option_descriptions[0],
  444           NULL,
  445         },
  446 };
  447 
  448 /*
  449  * print a media word.
  450  */
  451 static void
  452 ifmedia_printword(ifmw)
  453         int ifmw;
  454 {
  455         struct ifmedia_description *desc;
  456         struct ifmedia_type_to_subtype *ttos;
  457         int seen_option = 0;
  458 
  459         /* Find the top-level interface type. */
  460         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
  461             desc->ifmt_string != NULL; desc++, ttos++)
  462                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
  463                         break;
  464         if (desc->ifmt_string == NULL) {
  465                 printf("<unknown type>\n");
  466                 return;
  467         }
  468         printf("%s", desc->ifmt_string);
  469 
  470         /* Any mode. */
  471         for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++)
  472                 if (IFM_MODE(ifmw) == desc->ifmt_word) {
  473                         if (desc->ifmt_string != NULL)
  474                                 printf(" mode %s", desc->ifmt_string);
  475                         break;
  476                 }
  477 
  478         /*
  479          * Check for the shared subtype descriptions first, then the
  480          * type-specific ones.
  481          */
  482         for (desc = ifm_subtype_shared_descriptions;
  483             desc->ifmt_string != NULL; desc++)
  484                 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
  485                         goto got_subtype;
  486 
  487         for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++)
  488                 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
  489                         break;
  490         if (desc->ifmt_string == NULL) {
  491                 printf(" <unknown subtype>\n");
  492                 return;
  493         }
  494 
  495  got_subtype:
  496         printf(" %s", desc->ifmt_string);
  497 
  498         /*
  499          * Look for shared options.
  500          */
  501         for (desc = ifm_shared_option_descriptions;
  502             desc->ifmt_string != NULL; desc++) {
  503                 if (ifmw & desc->ifmt_word) {
  504                         if (seen_option == 0)
  505                                 printf(" <");
  506                         printf("%s%s", seen_option++ ? "," : "",
  507                             desc->ifmt_string);
  508                 }
  509         }
  510 
  511         /*
  512          * Look for subtype-specific options.
  513          */
  514         for (desc = ttos->options; desc->ifmt_string != NULL; desc++) {
  515                 if (ifmw & desc->ifmt_word) {
  516                         if (seen_option == 0)
  517                                 printf(" <");
  518                         printf("%s%s", seen_option++ ? "," : "",
  519                             desc->ifmt_string); 
  520                 }
  521         }
  522         printf("%s\n", seen_option ? ">" : "");
  523 }
  524 #endif /* IFMEDIA_DEBUG */

Cache object: be34cf9849b4c6864ec7cedca85cb01c


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