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$ */
    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 <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/socket.h>
   52 #include <sys/sockio.h>
   53 #include <sys/malloc.h>
   54 
   55 #include <net/if.h>
   56 #include <net/if_media.h>
   57 
   58 /*
   59  * Compile-time options:
   60  * IFMEDIA_DEBUG:
   61  *      turn on implementation-level debug printfs.
   62  *      Useful for debugging newly-ported  drivers.
   63  */
   64 
   65 static struct ifmedia_entry *ifmedia_match __P((struct ifmedia *ifm,
   66     int flags, int mask));
   67 
   68 #ifdef IFMEDIA_DEBUG
   69 int     ifmedia_debug = 0;
   70 static  void ifmedia_printword __P((int));
   71 #endif
   72 
   73 /*
   74  * Initialize if_media struct for a specific interface instance.
   75  */
   76 void
   77 ifmedia_init(ifm, dontcare_mask, change_callback, status_callback)
   78         struct ifmedia *ifm;
   79         int dontcare_mask;
   80         ifm_change_cb_t change_callback;
   81         ifm_stat_cb_t status_callback;
   82 {
   83 
   84         LIST_INIT(&ifm->ifm_list);
   85         ifm->ifm_cur = NULL;
   86         ifm->ifm_media = 0;
   87         ifm->ifm_mask = dontcare_mask;          /* IF don't-care bits */
   88         ifm->ifm_change = change_callback;
   89         ifm->ifm_status = status_callback;
   90 }
   91 
   92 /*
   93  * Add a media configuration to the list of supported media
   94  * for a specific interface instance.
   95  */
   96 void
   97 ifmedia_add(ifm, mword, data, aux)
   98         struct ifmedia *ifm;
   99         int mword;
  100         int data;
  101         void *aux;
  102 {
  103         register struct ifmedia_entry *entry;
  104 
  105 #ifdef IFMEDIA_DEBUG
  106         if (ifmedia_debug) {
  107                 if (ifm == NULL) {
  108                         printf("ifmedia_add: null ifm\n");
  109                         return;
  110                 }
  111                 printf("Adding entry for ");
  112                 ifmedia_printword(mword);
  113         }
  114 #endif
  115 
  116         entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
  117         if (entry == NULL)
  118                 panic("ifmedia_add: can't malloc entry");
  119 
  120         entry->ifm_media = mword;
  121         entry->ifm_data = data;
  122         entry->ifm_aux = aux;
  123 
  124         LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list);
  125 }
  126 
  127 /*
  128  * Add an array of media configurations to the list of
  129  * supported media for a specific interface instance.
  130  */
  131 void
  132 ifmedia_list_add(ifm, lp, count)
  133         struct ifmedia *ifm;
  134         struct ifmedia_entry *lp;
  135         int count;
  136 {
  137         int i;
  138 
  139         for (i = 0; i < count; i++)
  140                 ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
  141                     lp[i].ifm_aux);
  142 }
  143 
  144 /*
  145  * Set the default active media. 
  146  *
  147  * Called by device-specific code which is assumed to have already
  148  * selected the default media in hardware.  We do _not_ call the
  149  * media-change callback.
  150  */
  151 void
  152 ifmedia_set(ifm, target)
  153         struct ifmedia *ifm; 
  154         int target;
  155 
  156 {
  157         struct ifmedia_entry *match;
  158 
  159         match = ifmedia_match(ifm, target, ifm->ifm_mask);
  160 
  161         if (match == NULL) {
  162                 printf("ifmedia_set: no match for 0x%x/0x%x\n",
  163                     target, ~ifm->ifm_mask);
  164                 panic("ifmedia_set");
  165         }
  166         ifm->ifm_cur = match;
  167 
  168 #ifdef IFMEDIA_DEBUG
  169         if (ifmedia_debug) {
  170                 printf("ifmedia_set: target ");
  171                 ifmedia_printword(target);
  172                 printf("ifmedia_set: setting to ");
  173                 ifmedia_printword(ifm->ifm_cur->ifm_media);
  174         }
  175 #endif
  176 }
  177 
  178 /*
  179  * Device-independent media ioctl support function.
  180  */
  181 int
  182 ifmedia_ioctl(ifp, ifr, ifm, cmd)
  183         struct ifnet *ifp;
  184         struct ifreq *ifr;
  185         struct ifmedia *ifm;
  186         u_long cmd;
  187 {
  188         struct ifmedia_entry *match;
  189         struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
  190         int error = 0, sticky;
  191 
  192         if (ifp == NULL || ifr == NULL || ifm == NULL)
  193                 return(EINVAL);
  194 
  195         switch (cmd) {
  196 
  197         /*
  198          * Set the current media.
  199          */
  200         case  SIOCSIFMEDIA:
  201         {
  202                 struct ifmedia_entry *oldentry;
  203                 int oldmedia;
  204                 int newmedia = ifr->ifr_media;
  205 
  206                 match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
  207                 if (match == NULL) {
  208 #ifdef IFMEDIA_DEBUG
  209                         if (ifmedia_debug) {
  210                                 printf(
  211                                     "ifmedia_ioctl: no media found for 0x%x\n", 
  212                                     newmedia);
  213                         }
  214 #endif
  215                         return (ENXIO);
  216                 }
  217 
  218                 /*
  219                  * If no change, we're done.
  220                  * XXX Automedia may invole software intervention.
  221                  *     Keep going in case the the connected media changed.
  222                  *     Similarly, if best match changed (kernel debugger?).
  223                  */
  224                 if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
  225                     (newmedia == ifm->ifm_media) &&
  226                     (match == ifm->ifm_cur))
  227                         return 0;
  228 
  229                 /*
  230                  * We found a match, now make the driver switch to it.
  231                  * Make sure to preserve our old media type in case the
  232                  * driver can't switch.
  233                  */
  234 #ifdef IFMEDIA_DEBUG
  235                 if (ifmedia_debug) {
  236                         printf("ifmedia_ioctl: switching %s to ",
  237                             ifp->if_xname);
  238                         ifmedia_printword(match->ifm_media);
  239                 }
  240 #endif
  241                 oldentry = ifm->ifm_cur;
  242                 oldmedia = ifm->ifm_media;
  243                 ifm->ifm_cur = match;
  244                 ifm->ifm_media = newmedia;
  245                 error = (*ifm->ifm_change)(ifp);
  246                 if (error) {
  247                         ifm->ifm_cur = oldentry;
  248                         ifm->ifm_media = oldmedia;
  249                 }
  250                 break;
  251         }
  252 
  253         /*
  254          * Get list of available media and current media on interface.
  255          */
  256         case  SIOCGIFMEDIA: 
  257         {
  258                 struct ifmedia_entry *ep;
  259                 int *kptr, count;
  260 
  261                 kptr = NULL;            /* XXX gcc */
  262 
  263                 ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
  264                     ifm->ifm_cur->ifm_media : IFM_NONE;
  265                 ifmr->ifm_mask = ifm->ifm_mask;
  266                 ifmr->ifm_status = 0;
  267                 (*ifm->ifm_status)(ifp, ifmr);
  268 
  269                 count = 0;
  270                 ep = ifm->ifm_list.lh_first;
  271 
  272                 if (ifmr->ifm_count != 0) {
  273                         kptr = (int *)malloc(ifmr->ifm_count * sizeof(int),
  274                             M_TEMP, M_WAITOK);
  275 
  276                         /*
  277                          * Get the media words from the interface's list.
  278                          */
  279                         for (; ep != NULL && count < ifmr->ifm_count;
  280                             ep = ep->ifm_list.le_next, count++)
  281                                 kptr[count] = ep->ifm_media;
  282 
  283                         if (ep != NULL)
  284                                 error = E2BIG;  /* oops! */
  285                 }
  286 
  287                 /*
  288                  * If there are more interfaces on the list, count
  289                  * them.  This allows the caller to set ifmr->ifm_count
  290                  * to 0 on the first call to know how much space to
  291                  * callocate.
  292                  */
  293                 for (; ep != NULL; ep = ep->ifm_list.le_next)
  294                         count++;
  295 
  296                 /*
  297                  * We do the copyout on E2BIG, because that's
  298                  * just our way of telling userland that there
  299                  * are more.  This is the behavior I've observed
  300                  * under BSD/OS 3.0
  301                  */
  302                 sticky = error;
  303                 if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) {
  304                         error = copyout((caddr_t)kptr,
  305                             (caddr_t)ifmr->ifm_ulist,
  306                             ifmr->ifm_count * sizeof(int));
  307                 }
  308 
  309                 if (error == 0)
  310                         error = sticky;
  311 
  312                 if (ifmr->ifm_count != 0)
  313                         free(kptr, M_TEMP);
  314 
  315                 ifmr->ifm_count = count;
  316                 break;
  317         }
  318 
  319         default:
  320                 return (EINVAL);
  321         }
  322 
  323         return (error);
  324 }
  325 
  326 /*
  327  * Find media entry matching a given ifm word.
  328  *
  329  */
  330 static struct ifmedia_entry *
  331 ifmedia_match(ifm, target, mask)
  332         struct ifmedia *ifm; 
  333         int target;
  334         int mask;
  335 {
  336         struct ifmedia_entry *match, *next;
  337 
  338         match = NULL;
  339         mask = ~mask;
  340 
  341         for (next = ifm->ifm_list.lh_first; next != NULL;
  342             next = next->ifm_list.le_next) {
  343                 if ((next->ifm_media & mask) == (target & mask)) {
  344 #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
  345                         if (match) {
  346                                 printf("ifmedia_match: multiple match for "
  347                                     "0x%x/0x%x\n", target, mask);
  348                         }
  349 #endif
  350                         match = next;
  351                 }
  352         }
  353 
  354         return match;
  355 }
  356 
  357 #ifdef IFMEDIA_DEBUG
  358 struct ifmedia_description ifm_type_descriptions[] =
  359     IFM_TYPE_DESCRIPTIONS;
  360 
  361 struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
  362     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
  363 
  364 struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
  365     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
  366 
  367 struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
  368     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
  369 
  370 struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
  371     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
  372 
  373 struct ifmedia_description ifm_subtype_fddi_descriptions[] =
  374     IFM_SUBTYPE_FDDI_DESCRIPTIONS;
  375 
  376 struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
  377     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
  378 
  379 struct ifmedia_description ifm_subtype_shared_descriptions[] =
  380     IFM_SUBTYPE_SHARED_DESCRIPTIONS;
  381 
  382 struct ifmedia_description ifm_shared_option_descriptions[] =
  383     IFM_SHARED_OPTION_DESCRIPTIONS;
  384 
  385 struct ifmedia_type_to_subtype {
  386         struct ifmedia_description *subtypes;
  387         struct ifmedia_description *options;
  388 };
  389 
  390 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */
  391 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
  392         {
  393           &ifm_subtype_ethernet_descriptions[0],
  394           &ifm_subtype_ethernet_option_descriptions[0]
  395         },
  396         {
  397           &ifm_subtype_tokenring_descriptions[0],
  398           &ifm_subtype_tokenring_option_descriptions[0]
  399         },
  400         {
  401           &ifm_subtype_fddi_descriptions[0],
  402           &ifm_subtype_fddi_option_descriptions[0]
  403         },
  404 };
  405 
  406 /*
  407  * print a media word.
  408  */
  409 static void
  410 ifmedia_printword(ifmw)
  411         int ifmw;
  412 {
  413         struct ifmedia_description *desc;
  414         struct ifmedia_type_to_subtype *ttos;
  415         int seen_option = 0;
  416 
  417         /* Find the top-level interface type. */
  418         for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
  419             desc->ifmt_string != NULL; desc++, ttos++)
  420                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
  421                         break;
  422         if (desc->ifmt_string == NULL) {
  423                 printf("<unknown type>\n");
  424                 return;
  425         }
  426         printf(desc->ifmt_string);
  427 
  428         /*
  429          * Check for the shared subtype descriptions first, then the
  430          * type-specific ones.
  431          */
  432         for (desc = ifm_subtype_shared_descriptions;
  433             desc->ifmt_string != NULL; desc++)
  434                 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
  435                         goto got_subtype;
  436 
  437         for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++)
  438                 if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
  439                         break;
  440         if (desc->ifmt_string == NULL) {
  441                 printf(" <unknown subtype>\n");
  442                 return;
  443         }
  444 
  445  got_subtype:
  446         printf(" %s", desc->ifmt_string);
  447 
  448         /*
  449          * Look for shared options.
  450          */
  451         for (desc = ifm_shared_option_descriptions;
  452             desc->ifmt_string != NULL; desc++) {
  453                 if (ifmw & desc->ifmt_word) {
  454                         if (seen_option == 0)
  455                                 printf(" <");
  456                         printf("%s%s", seen_option++ ? "," : "",
  457                             desc->ifmt_string);
  458                 }
  459         }
  460 
  461         /*
  462          * Look for subtype-specific options.
  463          */
  464         for (desc = ttos->options; desc->ifmt_string != NULL; desc++) {
  465                 if (ifmw & desc->ifmt_word) {
  466                         if (seen_option == 0)
  467                                 printf(" <");
  468                         printf("%s%s", seen_option++ ? "," : "",
  469                             desc->ifmt_string); 
  470                 }
  471         }
  472         printf("%s\n", seen_option ? ">" : "");
  473 }
  474 #endif /* IFMEDIA_DEBUG */

Cache object: e91d7eb4cf473070892a707ce878b3c8


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