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.54 2022/09/03 02:47:59 thorpej Exp $    */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2020 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Copyright (c) 1997
   35  *      Jonathan Stone and Jason R. Thorpe.  All rights reserved.
   36  *
   37  * This software is derived from information provided by Matt Thomas.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  * 3. All advertising materials mentioning features or use of this software
   48  *    must display the following acknowledgement:
   49  *      This product includes software developed by Jonathan Stone
   50  *      and Jason R. Thorpe for the NetBSD Project.
   51  * 4. The names of the authors may not be used to endorse or promote products
   52  *    derived from this software without specific prior written permission.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
   55  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   56  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   57  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   58  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   59  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   61  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   62  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   64  * SUCH DAMAGE.
   65  */
   66 
   67 /*
   68  * BSD/OS-compatible network interface media selection.
   69  *
   70  * Where it is safe to do so, this code strays slightly from the BSD/OS
   71  * design.  Software which uses the API (device drivers, basically)
   72  * shouldn't notice any difference.
   73  *
   74  * Many thanks to Matt Thomas for providing the information necessary
   75  * to implement this interface.
   76  */
   77 
   78 #include <sys/cdefs.h>
   79 __KERNEL_RCSID(0, "$NetBSD: if_media.c,v 1.54 2022/09/03 02:47:59 thorpej Exp $");
   80 
   81 #define __IFMEDIA_PRIVATE
   82 
   83 #include <sys/param.h>
   84 #include <sys/systm.h>
   85 #include <sys/errno.h>
   86 #include <sys/ioctl.h>
   87 #include <sys/socket.h>
   88 #include <sys/kmem.h>
   89 
   90 #include <net/if.h>
   91 #include <net/if_media.h>
   92 
   93 static void     ifmedia_status(struct ifmedia *, struct ifnet *,
   94                     struct ifmediareq *);
   95 static struct ifmedia_entry *
   96                 ifmedia_match_locked(struct ifmedia *, u_int, u_int);
   97 
   98 /*
   99  * Compile-time options:
  100  * IFMEDIA_DEBUG:
  101  *      Turn on implementation-level debug printfs.
  102  *      Useful for debugging newly-ported drivers.
  103  */
  104 
  105 #ifdef IFMEDIA_DEBUG
  106 int     ifmedia_debug = 0;
  107 static  void ifmedia_printword(int);
  108 #endif
  109 
  110 /*
  111  * We need to implement a recursive mutex to handle the un-converted
  112  * driver case.  For a fully MP-safe driver, the media lock will be
  113  * held before calling any of the entry points that require it.  However,
  114  * this is not necessarily the case for a driver that hasn't yet been
  115  * converted, and the entry point calls may be nested (for example
  116  * mii_ifmedia_change -> ether_mediachange -> mii_mediachg).  Luckily,
  117  * the nesting won't be very deep, and 4 nested holds should be plenty.
  118  */
  119 #define IFM_L_OWNLOCK           0x01
  120 #define IFM_L_COUNT_MASK        0x3UL
  121 #define IFM_L_CPU_MASK          ~(IFM_L_COUNT_MASK)
  122 
  123 void
  124 ifmedia_lock_for_legacy(struct ifmedia *ifm)
  125 {
  126         uintptr_t cnt = IFM_L_OWNLOCK;
  127         uintptr_t ci;
  128 
  129         if (mutex_tryenter(ifm->ifm_lock)) {
  130                 goto gotit;
  131         }
  132 
  133         kpreempt_disable();
  134         ci = (uintptr_t)curcpu();
  135         if ((ifm->ifm_legacy & IFM_L_CPU_MASK) == ci) {
  136                 cnt = ifm->ifm_legacy & IFM_L_COUNT_MASK;
  137                 KASSERT(cnt < IFM_L_COUNT_MASK);
  138                 cnt++;
  139                 kpreempt_enable();
  140                 goto gotit;
  141         }
  142         kpreempt_enable();
  143 
  144         mutex_enter(ifm->ifm_lock);
  145  gotit:
  146         KASSERT(kpreempt_disabled());
  147         ci = (uintptr_t)curcpu();
  148         KASSERT((ci & IFM_L_CPU_MASK) == ci);
  149         ifm->ifm_legacy = ci | cnt;
  150 }
  151 
  152 void
  153 ifmedia_unlock_for_legacy(struct ifmedia *ifm)
  154 {
  155         uintptr_t cnt;
  156         uintptr_t ci = (uintptr_t)curcpu();
  157 
  158         KASSERT(kpreempt_disabled());
  159         KASSERT((ifm->ifm_legacy & IFM_L_CPU_MASK) == ci);
  160         cnt = ifm->ifm_legacy & IFM_L_COUNT_MASK;
  161         KASSERT(cnt != 0);
  162         if (cnt == IFM_L_OWNLOCK) {
  163                 ifm->ifm_legacy = IFM_L_OWNLOCK;
  164                 mutex_exit(ifm->ifm_lock);
  165                 return;
  166         }
  167         cnt--;
  168         ifm->ifm_legacy = ci | cnt;
  169 }
  170 
  171 /*
  172  * Initialize if_media struct for a specific interface instance.
  173  */
  174 void
  175 ifmedia_init_with_lock(struct ifmedia *ifm, int dontcare_mask,
  176     ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback,
  177     kmutex_t *lock)
  178 {
  179 
  180         /*
  181          * XXX Would really like to assert:
  182          *
  183          *      !if_is_mpsafe(ifp) || ((if_is_mpsafe(ifp) && lock != NULL)
  184          *
  185          * ...but we don't have access to the ifnet here.
  186          */
  187 
  188         TAILQ_INIT(&ifm->ifm_list);
  189         ifm->ifm_cur = NULL;
  190         ifm->ifm_media = IFM_NONE;
  191         ifm->ifm_mask = dontcare_mask;          /* IF don't-care bits */
  192         ifm->ifm_change = change_callback;
  193         ifm->ifm_status = status_callback;
  194         ifm->ifm_legacy = 0;
  195 
  196         if (lock == NULL) {
  197                 /*
  198                  * This is to support drivers that are not yet MP-safe
  199                  * with regard to the ifmedia layer.  In these cases,
  200                  * we supply the lock and we ensure it's taken upon entry
  201                  * to various routines that expect it to be held.  When
  202                  * we do this, we expect that the driver is in general a
  203                  * non-MP-safe driver and has already gone to splnet().
  204                  */
  205                 lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
  206                 ifm->ifm_legacy = IFM_L_OWNLOCK;
  207         }
  208         ifm->ifm_lock = lock;
  209 }
  210 
  211 void
  212 ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
  213     ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
  214 {
  215         ifmedia_init_with_lock(ifm, dontcare_mask, change_callback,
  216             status_callback, NULL);
  217 }
  218 
  219 /*
  220  * Free resources associated with an ifmedia.
  221  */
  222 void
  223 ifmedia_fini(struct ifmedia *ifm)
  224 {
  225 
  226         ifmedia_removeall(ifm);
  227 
  228         if (ifm->ifm_legacy) {
  229                 KASSERT(ifm->ifm_legacy == IFM_L_OWNLOCK);
  230                 mutex_obj_free(ifm->ifm_lock);
  231         }
  232         ifm->ifm_legacy = 0;
  233         ifm->ifm_lock = NULL;
  234 }
  235 
  236 int
  237 ifmedia_change(struct ifmedia *ifm, struct ifnet *ifp)
  238 {
  239         int rv;
  240 
  241         IFMEDIA_LOCK_FOR_LEGACY(ifm);
  242         KASSERT(ifmedia_locked(ifm));
  243         if (ifm->ifm_change)
  244                 rv = (*ifm->ifm_change)(ifp);
  245         else
  246                 rv = -1;
  247         IFMEDIA_UNLOCK_FOR_LEGACY(ifm);
  248 
  249         return rv;
  250 }
  251 
  252 static void
  253 ifmedia_status(struct ifmedia *ifm, struct ifnet *ifp, struct ifmediareq *ifmr)
  254 {
  255 
  256         KASSERT(ifmedia_locked(ifm));
  257         if (ifm->ifm_status == NULL)
  258                 return;
  259         (*ifm->ifm_status)(ifp, ifmr);
  260 }
  261 
  262 /*
  263  * Add a media configuration to the list of supported media
  264  * for a specific interface instance.
  265  */
  266 static void
  267 ifmedia_add_entry(struct ifmedia *ifm, int mword, int data, void *aux,
  268     struct ifmedia_entry *entry)
  269 {
  270 
  271 #ifdef IFMEDIA_DEBUG
  272         if (ifmedia_debug) {
  273                 if (ifm == NULL) {
  274                         printf("ifmedia_add: null ifm\n");
  275                         return;
  276                 }
  277                 printf("Adding entry for ");
  278                 ifmedia_printword(mword);
  279         }
  280 #endif
  281 
  282         entry->ifm_media = mword;
  283         entry->ifm_data = data;
  284         entry->ifm_aux = aux;
  285         TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list);
  286 }
  287 
  288 void
  289 ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux)
  290 {
  291         struct ifmedia_entry *entry;
  292 
  293         entry = kmem_zalloc(sizeof(*entry), KM_SLEEP);
  294         ifmedia_lock(ifm);
  295         ifmedia_add_entry(ifm, mword, data, aux, entry);
  296         ifmedia_unlock(ifm);
  297 }
  298 
  299 /*
  300  * Add an array of media configurations to the list of
  301  * supported media for a specific interface instance.
  302  */
  303 void
  304 ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count)
  305 {
  306         int i;
  307 
  308         for (i = 0; i < count; i++)
  309                 ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
  310                     lp[i].ifm_aux);
  311 }
  312 
  313 /*
  314  * Set the default active media.
  315  *
  316  * Called by device-specific code which is assumed to have already
  317  * selected the default media in hardware.  We do _not_ call the
  318  * media-change callback.
  319  */
  320 void
  321 ifmedia_set(struct ifmedia *ifm, int target)
  322 {
  323         struct ifmedia_entry *match, *entry = NULL;
  324 
  325         ifmedia_lock(ifm);
  326         match = ifmedia_match_locked(ifm, target, ifm->ifm_mask);
  327 
  328         /*
  329          * If we didn't find the requested media, then we try to fall
  330          * back to target-type (IFM_ETHER, e.g.) | IFM_NONE.  If that's
  331          * not on the list, then we add it and set the media to it.
  332          *
  333          * Since ifmedia_set is almost always called with IFM_AUTO or
  334          * with a known-good media, this really should only occur if we:
  335          *
  336          * a) didn't find any PHYs, or
  337          * b) didn't find an autoselect option on the PHY when the
  338          *    parent ethernet driver expected to.
  339          *
  340          * In either case, it makes sense to select no media.
  341          */
  342         if (match == NULL) {
  343                 printf("ifmedia_set: no match for 0x%x/0x%x\n",
  344                     target, ~ifm->ifm_mask);
  345                 target = (target & IFM_NMASK) | IFM_NONE;
  346                 match = ifmedia_match_locked(ifm, target, ifm->ifm_mask);
  347                 if (match == NULL) {
  348                         ifmedia_unlock(ifm);
  349                         entry = kmem_zalloc(sizeof(*entry), KM_SLEEP);
  350                         ifmedia_lock(ifm);
  351                         match = ifmedia_match_locked(ifm, target,
  352                             ifm->ifm_mask);
  353                         if (match == NULL) {
  354                                 ifmedia_add_entry(ifm, target, 0, NULL, entry);
  355                                 entry = NULL;
  356                         }
  357                         match = ifmedia_match_locked(ifm, target,
  358                             ifm->ifm_mask);
  359                         if (match == NULL)
  360                                 panic("ifmedia_set failed");
  361                 }
  362         }
  363         ifm->ifm_cur = match;
  364         ifmedia_unlock(ifm);
  365 
  366         if (entry)
  367                 kmem_free(entry, sizeof(*entry));
  368 
  369 #ifdef IFMEDIA_DEBUG
  370         if (ifmedia_debug) {
  371                 printf("ifmedia_set: target ");
  372                 ifmedia_printword(target);
  373                 printf("ifmedia_set: setting to ");
  374                 ifmedia_printword(ifm->ifm_cur->ifm_media);
  375         }
  376 #endif
  377 }
  378 
  379 static int
  380 ifmedia_getwords(struct ifmedia * const ifm, int *words, int maxwords)
  381 {
  382         struct ifmedia_entry *ep;
  383         int nwords = 0;
  384 
  385         KASSERT(ifmedia_locked(ifm));
  386 
  387         TAILQ_FOREACH(ep, &ifm->ifm_list, ifm_list) {
  388                 if (words != NULL && nwords < maxwords) {
  389                         words[nwords] = ep->ifm_media;
  390                 }
  391                 nwords++;
  392         }
  393 
  394         return nwords;
  395 }
  396 
  397 #define IFMEDIA_IOCTL_LOCK(ifm)                                         \
  398 do {                                                                    \
  399         if (ifmedia_islegacy(ifm))                                      \
  400                 ifmedia_lock_for_legacy(ifm);                           \
  401         else                                                            \
  402                 ifmedia_lock(ifm);                                      \
  403 } while (/*CONSTCOND*/0)
  404 
  405 #define IFMEDIA_IOCTL_UNLOCK(ifm)                                       \
  406 do {                                                                    \
  407         if (ifmedia_islegacy(ifm))                                      \
  408                 ifmedia_unlock_for_legacy(ifm);                         \
  409         else                                                            \
  410                 ifmedia_unlock(ifm);                                    \
  411 } while (/*CONSTCOND*/0)
  412 
  413 /*
  414  * Device-independent media ioctl support function.
  415  */
  416 int
  417 ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
  418     u_long cmd)
  419 {
  420         struct ifmedia_entry *match;
  421         struct ifmediareq *ifmr = (struct ifmediareq *)ifr;
  422         int error = 0;
  423 
  424         if (ifp == NULL || ifr == NULL || ifm == NULL)
  425                 return EINVAL;
  426 
  427         KERNEL_LOCK_UNLESS_IFP_MPSAFE(ifp);
  428 
  429         switch (cmd) {
  430         case SIOCSIFMEDIA:      /* Set the current media. */
  431         {
  432                 struct ifmedia_entry *oldentry;
  433                 u_int oldmedia;
  434                 u_int newmedia = ifr->ifr_media;
  435 
  436                 IFMEDIA_IOCTL_LOCK(ifm);
  437 
  438                 match = ifmedia_match_locked(ifm, newmedia, ifm->ifm_mask);
  439                 if (match == NULL) {
  440 #ifdef IFMEDIA_DEBUG
  441                         if (ifmedia_debug) {
  442                                 printf("ifmedia_ioctl: no media found for "
  443                                     "0x%08x\n", newmedia);
  444                         }
  445 #endif
  446                         IFMEDIA_IOCTL_UNLOCK(ifm);
  447                         error = EINVAL;
  448                         break;
  449                 }
  450 
  451                 /*
  452                  * If no change, we're done.
  453                  * XXX Automedia may involve software intervention.
  454                  *     Keep going in case the connected media changed.
  455                  *     Similarly, if best match changed (kernel debugger?).
  456                  */
  457                 if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
  458                     (newmedia == ifm->ifm_media) && (match == ifm->ifm_cur)) {
  459                         IFMEDIA_IOCTL_UNLOCK(ifm);
  460                         break;
  461                 }
  462 
  463                 /*
  464                  * We found a match, now make the driver switch to it.
  465                  * Make sure to preserve our old media type in case the
  466                  * driver can't switch.
  467                  */
  468 #ifdef IFMEDIA_DEBUG
  469                 if (ifmedia_debug) {
  470                         printf("ifmedia_ioctl: switching %s to ",
  471                             ifp->if_xname);
  472                         ifmedia_printword(match->ifm_media);
  473                 }
  474 #endif
  475                 oldentry = ifm->ifm_cur;
  476                 oldmedia = ifm->ifm_media;
  477                 ifm->ifm_cur = match;
  478                 ifm->ifm_media = newmedia;
  479                 error = ifmedia_change(ifm, ifp);
  480                 if (error) {
  481                         ifm->ifm_cur = oldentry;
  482                         ifm->ifm_media = oldmedia;
  483                 }
  484                 IFMEDIA_IOCTL_UNLOCK(ifm);
  485                 break;
  486         }
  487 
  488         /* Get list of available media and current media on interface. */
  489         case SIOCGIFMEDIA:
  490         {
  491                 int nwords1, nwords2;
  492 
  493                 if (ifmr->ifm_count < 0) {
  494                         error = EINVAL;
  495                         break;
  496                 }
  497 
  498                 IFMEDIA_IOCTL_LOCK(ifm);
  499                 ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
  500                     ifm->ifm_cur->ifm_media : IFM_NONE;
  501                 ifmr->ifm_mask = ifm->ifm_mask;
  502                 ifmr->ifm_status = 0;
  503                 ifmedia_status(ifm, ifp, ifmr);
  504 
  505                 /*
  506                  * Count them so we know how much is the max we'll
  507                  * need.
  508                  */
  509                 nwords1 = nwords2 = ifmedia_getwords(ifm, NULL, 0);
  510                 IFMEDIA_IOCTL_UNLOCK(ifm);
  511 
  512                 if (ifmr->ifm_count != 0) {
  513                         int maxwords = MIN(nwords1, ifmr->ifm_count);
  514                         int *kptr = kmem_zalloc(maxwords * sizeof(int),
  515                             KM_SLEEP);
  516 
  517                         ifmedia_lock(ifm);
  518                         nwords2 = ifmedia_getwords(ifm, kptr, maxwords);
  519                         ifmedia_unlock(ifm);
  520                         error = copyout(kptr, ifmr->ifm_ulist,
  521                             maxwords * sizeof(int));
  522                         if (error == 0 && nwords2 > nwords1)
  523                                 error = E2BIG;  /* oops! */
  524                         kmem_free(kptr, maxwords * sizeof(int));
  525                 }
  526                 /* Update with the real number */
  527                 ifmr->ifm_count = nwords2;
  528                 break;
  529         }
  530 
  531         default:
  532                 error = EINVAL;
  533                 break;
  534         }
  535 
  536         KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(ifp);
  537 
  538         return error;
  539 }
  540 
  541 /*
  542  * Find media entry matching a given ifm word.
  543  */
  544 static struct ifmedia_entry *
  545 ifmedia_match_locked(struct ifmedia *ifm, u_int target, u_int mask)
  546 {
  547         struct ifmedia_entry *match, *next;
  548 
  549         match = NULL;
  550         mask = ~mask;
  551 
  552         TAILQ_FOREACH(next, &ifm->ifm_list, ifm_list) {
  553                 if ((next->ifm_media & mask) == (target & mask)) {
  554                         if (match) {
  555 #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
  556                                 printf("ifmedia_match: multiple match for "
  557                                     "0x%x/0x%x, selected instance %d\n",
  558                                     target, mask, IFM_INST(match->ifm_media));
  559 #endif
  560                                 break;
  561                         }
  562                         match = next;
  563                 }
  564         }
  565 
  566         return match;
  567 }
  568 
  569 struct ifmedia_entry *
  570 ifmedia_match(struct ifmedia *ifm, u_int target, u_int mask)
  571 {
  572         struct ifmedia_entry *match;
  573 
  574         /*
  575          * N.B. We expect the caller is responsible fot the lifecycle
  576          * of the media entries.  Use with extreme caution.
  577          */
  578 
  579         ifmedia_lock(ifm);
  580         match = ifmedia_match_locked(ifm, target, mask);
  581         ifmedia_unlock(ifm);
  582         return match;
  583 }
  584 
  585 /*
  586  * Delete all media for a given instance.
  587  */
  588 void
  589 ifmedia_delete_instance(struct ifmedia *ifm, u_int inst)
  590 {
  591         struct ifmedia_entry *ife, *nife;
  592         TAILQ_HEAD(, ifmedia_entry) dead_entries;
  593 
  594         TAILQ_INIT(&dead_entries);
  595 
  596         ifmedia_lock(ifm);
  597         TAILQ_FOREACH_SAFE(ife, &ifm->ifm_list, ifm_list, nife) {
  598                 if (inst == IFM_INST_ANY ||
  599                     inst == IFM_INST(ife->ifm_media)) {
  600                         if (ifm->ifm_cur == ife) {
  601                                 ifm->ifm_cur = NULL;
  602                                 ifm->ifm_media = IFM_NONE;
  603                         }
  604                         TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list);
  605                         TAILQ_INSERT_TAIL(&dead_entries, ife, ifm_list);
  606                 }
  607         }
  608         ifmedia_unlock(ifm);
  609 
  610         TAILQ_FOREACH_SAFE(ife, &dead_entries, ifm_list, nife) {
  611                 TAILQ_REMOVE(&dead_entries, ife, ifm_list);
  612                 kmem_free(ife, sizeof(*ife));
  613         }
  614 }
  615 
  616 void
  617 ifmedia_removeall(struct ifmedia *ifm)
  618 {
  619 
  620         ifmedia_delete_instance(ifm, IFM_INST_ANY);
  621 }
  622 
  623 /*
  624  * Compute the interface `baudrate' from the media, for the interface
  625  * metrics (used by routing daemons).
  626  */
  627 static const struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
  628     IFM_BAUDRATE_DESCRIPTIONS;
  629 
  630 uint64_t
  631 ifmedia_baudrate(int mword)
  632 {
  633         int i;
  634 
  635         for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
  636                 if (IFM_TYPE_SUBTYPE_MATCH(mword,
  637                     ifmedia_baudrate_descriptions[i].ifmb_word))
  638                         return ifmedia_baudrate_descriptions[i].ifmb_baudrate;
  639         }
  640 
  641         /* Not known. */
  642         return 0;
  643 }
  644 
  645 #ifdef IFMEDIA_DEBUG
  646 
  647 static const struct ifmedia_description ifm_type_descriptions[] =
  648     IFM_TYPE_DESCRIPTIONS;
  649 
  650 static const struct ifmedia_description ifm_subtype_descriptions[] =
  651     IFM_SUBTYPE_DESCRIPTIONS;
  652 
  653 static const struct ifmedia_description ifm_option_descriptions[] =
  654     IFM_OPTION_DESCRIPTIONS;
  655 
  656 /*
  657  * print a media word.
  658  */
  659 static void
  660 ifmedia_printword(int ifmw)
  661 {
  662         const struct ifmedia_description *desc;
  663         int seen_option = 0;
  664 
  665         /* Print the top-level interface type. */
  666         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
  667              desc++) {
  668                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
  669                         break;
  670         }
  671         if (desc->ifmt_string == NULL)
  672                 printf("<unknown type> ");
  673         else
  674                 printf("%s ", desc->ifmt_string);
  675 
  676         /* Print the subtype. */
  677         for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
  678              desc++) {
  679                 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
  680                     IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmw))
  681                         break;
  682         }
  683         if (desc->ifmt_string == NULL)
  684                 printf("<unknown subtype>");
  685         else
  686                 printf("%s", desc->ifmt_string);
  687 
  688         /* Print any options. */
  689         for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
  690              desc++) {
  691                 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
  692                     (ifmw & desc->ifmt_word) != 0 &&
  693                     (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
  694                         if (seen_option == 0)
  695                                 printf(" <");
  696                         printf("%s%s", seen_option ? "," : "",
  697                             desc->ifmt_string);
  698                         seen_option |= IFM_OPTIONS(desc->ifmt_word);
  699                 }
  700         }
  701         printf("%s\n", seen_option ? ">" : "");
  702 }
  703 
  704 #endif /* IFMEDIA_DEBUG */

Cache object: 313ed8f2f38e18e2ef7c735d0e87c746


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