LCOV - code coverage report
Current view: top level - net - if_media.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 111 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 8 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_media.c,v 1.30 2017/01/24 10:08:30 krw Exp $       */
       2             : /*      $NetBSD: if_media.c,v 1.10 2000/03/13 23:52:39 soren Exp $      */
       3             : 
       4             : /*-
       5             :  * Copyright (c) 1998 The NetBSD Foundation, Inc.
       6             :  * All rights reserved.
       7             :  *
       8             :  * This code is derived from software contributed to The NetBSD Foundation
       9             :  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      10             :  * NASA Ames Research Center.
      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             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
      22             :  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
      23             :  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
      24             :  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
      25             :  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      26             :  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      27             :  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      28             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
      29             :  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      30             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
      31             :  * POSSIBILITY OF SUCH DAMAGE.
      32             :  */
      33             : 
      34             : /*
      35             :  * Copyright (c) 1997
      36             :  *      Jonathan Stone and Jason R. Thorpe.  All rights reserved.
      37             :  *
      38             :  * This software is derived from information provided by Matt Thomas.
      39             :  *
      40             :  * Redistribution and use in source and binary forms, with or without
      41             :  * modification, are permitted provided that the following conditions
      42             :  * are met:
      43             :  * 1. Redistributions of source code must retain the above copyright
      44             :  *    notice, this list of conditions and the following disclaimer.
      45             :  * 2. Redistributions in binary form must reproduce the above copyright
      46             :  *    notice, this list of conditions and the following disclaimer in the
      47             :  *    documentation and/or other materials provided with the distribution.
      48             :  * 3. All advertising materials mentioning features or use of this software
      49             :  *    must display the following acknowledgement:
      50             :  *      This product includes software developed by Jonathan Stone
      51             :  *      and Jason R. Thorpe for the NetBSD Project.
      52             :  * 4. The names of the authors may not be used to endorse or promote products
      53             :  *    derived from this software without specific prior written permission.
      54             :  *
      55             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
      56             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      57             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      58             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      59             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      60             :  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
      61             :  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      62             :  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      63             :  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      64             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      65             :  * SUCH DAMAGE.
      66             :  */
      67             : 
      68             : /*
      69             :  * BSD/OS-compatible network interface media selection.
      70             :  *
      71             :  * Where it is safe to do so, this code strays slightly from the BSD/OS
      72             :  * design.  Software which uses the API (device drivers, basically)
      73             :  * shouldn't notice any difference.
      74             :  *
      75             :  * Many thanks to Matt Thomas for providing the information necessary
      76             :  * to implement this interface.
      77             :  */
      78             : 
      79             : #include <sys/param.h>
      80             : #include <sys/systm.h>
      81             : #include <sys/errno.h>
      82             : #include <sys/ioctl.h>
      83             : #include <sys/socket.h>
      84             : #include <sys/malloc.h>
      85             : 
      86             : #include <net/if.h>
      87             : #ifdef IFMEDIA_DEBUG
      88             : #include <net/if_var.h>
      89             : #endif
      90             : #include <net/if_media.h>
      91             : #include <net/netisr.h>
      92             : 
      93             : /*
      94             :  * Compile-time options:
      95             :  * IFMEDIA_DEBUG:
      96             :  *      turn on implementation-level debug printfs.
      97             :  *      Useful for debugging newly-ported  drivers.
      98             :  */
      99             : 
     100             : #ifdef IFMEDIA_DEBUG
     101             : int     ifmedia_debug = 0;
     102             : static  void ifmedia_printword(uint64_t);
     103             : #endif
     104             : 
     105             : /*
     106             :  * Initialize if_media struct for a specific interface instance.
     107             :  */
     108             : void
     109           0 : ifmedia_init(struct ifmedia *ifm, uint64_t dontcare_mask,
     110             :     ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
     111             : {
     112           0 :         TAILQ_INIT(&ifm->ifm_list);
     113           0 :         ifm->ifm_cur = NULL;
     114           0 :         ifm->ifm_media = 0;
     115           0 :         ifm->ifm_mask = dontcare_mask;               /* IF don't-care bits */
     116           0 :         ifm->ifm_change = change_callback;
     117           0 :         ifm->ifm_status = status_callback;
     118           0 : }
     119             : 
     120             : /*
     121             :  * Add a media configuration to the list of supported media
     122             :  * for a specific interface instance.
     123             :  */
     124             : void
     125           0 : ifmedia_add(struct ifmedia *ifm, uint64_t mword, int data, void *aux)
     126             : {
     127             :         struct ifmedia_entry *entry;
     128             : 
     129             : #ifdef IFMEDIA_DEBUG
     130             :         if (ifmedia_debug) {
     131             :                 if (ifm == NULL) {
     132             :                         printf("ifmedia_add: null ifm\n");
     133             :                         return;
     134             :                 }
     135             :                 printf("Adding entry for ");
     136             :                 ifmedia_printword(mword);
     137             :         }
     138             : #endif
     139             : 
     140           0 :         entry = malloc(sizeof(*entry), M_IFADDR, M_NOWAIT);
     141           0 :         if (entry == NULL)
     142           0 :                 panic("ifmedia_add: can't malloc entry");
     143             : 
     144           0 :         entry->ifm_media = mword;
     145           0 :         entry->ifm_data = data;
     146           0 :         entry->ifm_aux = aux;
     147             : 
     148           0 :         TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list);
     149           0 : }
     150             : 
     151             : /*
     152             :  * Add an array of media configurations to the list of
     153             :  * supported media for a specific interface instance.
     154             :  */
     155             : void
     156           0 : ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count)
     157             : {
     158             :         int i;
     159             : 
     160           0 :         for (i = 0; i < count; i++)
     161           0 :                 ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data,
     162           0 :                     lp[i].ifm_aux);
     163           0 : }
     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           0 : ifmedia_set(struct ifmedia *ifm, uint64_t target)
     174             : {
     175             :         struct ifmedia_entry *match;
     176             : 
     177           0 :         match = ifmedia_match(ifm, target, ifm->ifm_mask);
     178             : 
     179             :         /*
     180             :          * If we didn't find the requested media, then we try to fall
     181             :          * back to target-type (IFM_ETHER, e.g.) | IFM_NONE.  If that's
     182             :          * not on the list, then we add it and set the media to it.
     183             :          *
     184             :          * Since ifmedia_set is almost always called with IFM_AUTO or
     185             :          * with a known-good media, this really should only occur if we:
     186             :          *
     187             :          * a) didn't find any PHYs, or
     188             :          * b) didn't find an autoselect option on the PHY when the
     189             :          *    parent ethernet driver expected to.
     190             :          *
     191             :          * In either case, it makes sense to select no media.
     192             :          */
     193           0 :         if (match == NULL) {
     194           0 :                 printf("ifmedia_set: no match for 0x%llx/0x%llx\n",
     195           0 :                     target, ~ifm->ifm_mask);
     196           0 :                 target = (target & IFM_NMASK) | IFM_NONE;
     197           0 :                 match = ifmedia_match(ifm, target, ifm->ifm_mask);
     198           0 :                 if (match == NULL) {
     199           0 :                         ifmedia_add(ifm, target, 0, NULL);
     200           0 :                         match = ifmedia_match(ifm, target, ifm->ifm_mask);
     201           0 :                         if (match == NULL)
     202           0 :                                 panic("ifmedia_set failed");
     203             :                 }
     204             :         }
     205           0 :         ifm->ifm_cur = match;
     206             : 
     207             : #ifdef IFMEDIA_DEBUG
     208             :         if (ifmedia_debug) {
     209             :                 printf("ifmedia_set: target ");
     210             :                 ifmedia_printword(target);
     211             :                 printf("ifmedia_set: setting to ");
     212             :                 ifmedia_printword(ifm->ifm_cur->ifm_media);
     213             :         }
     214             : #endif
     215           0 : }
     216             : 
     217             : /*
     218             :  * Device-independent media ioctl support function.
     219             :  */
     220             : int
     221           0 : ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
     222             :     u_long cmd)
     223             : {
     224             :         struct ifmedia_entry *match;
     225             :         int error = 0;
     226             : 
     227           0 :         if (ifp == NULL || ifr == NULL || ifm == NULL)
     228           0 :                 return (EINVAL);
     229             : 
     230           0 :         switch (cmd) {
     231             : 
     232             :         /*
     233             :          * Set the current media.
     234             :          */
     235             :         case SIOCSIFMEDIA:
     236             :         {
     237             :                 struct ifmedia_entry *oldentry;
     238             :                 uint64_t oldmedia;
     239           0 :                 uint64_t newmedia = ifr->ifr_media;
     240             : 
     241           0 :                 match = ifmedia_match(ifm, newmedia, ifm->ifm_mask);
     242           0 :                 if (match == NULL) {
     243             : #ifdef IFMEDIA_DEBUG
     244             :                         if (ifmedia_debug) {
     245             :                                 printf("ifmedia_ioctl: no media found for 0x%llx\n",
     246             :                                     newmedia);
     247             :                         }
     248             : #endif
     249           0 :                         return (EINVAL);
     250             :                 }
     251             : 
     252             :                 /*
     253             :                  * If no change, we're done.
     254             :                  * XXX Automedia may involve software intervention.
     255             :                  *     Keep going in case the connected media changed.
     256             :                  *     Similarly, if best match changed (kernel debugger?).
     257             :                  */
     258           0 :                 if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) &&
     259           0 :                     (newmedia == ifm->ifm_media) &&
     260           0 :                     (match == ifm->ifm_cur))
     261           0 :                         return (0);
     262             : 
     263             :                 /*
     264             :                  * We found a match, now make the driver switch to it.
     265             :                  * Make sure to preserve our old media type in case the
     266             :                  * driver can't switch.
     267             :                  */
     268             : #ifdef IFMEDIA_DEBUG
     269             :                 if (ifmedia_debug) {
     270             :                         printf("ifmedia_ioctl: switching %s to ",
     271             :                             ifp->if_xname);
     272             :                         ifmedia_printword(match->ifm_media);
     273             :                 }
     274             : #endif
     275           0 :                 oldentry = ifm->ifm_cur;
     276           0 :                 oldmedia = ifm->ifm_media;
     277           0 :                 ifm->ifm_cur = match;
     278           0 :                 ifm->ifm_media = newmedia;
     279           0 :                 error = (*ifm->ifm_change)(ifp);
     280           0 :                 if (error) {
     281           0 :                         ifm->ifm_cur = oldentry;
     282           0 :                         ifm->ifm_media = oldmedia;
     283           0 :                 }
     284           0 :                 break;
     285             :         }
     286             : 
     287             :         /*
     288             :          * Get list of available media and current media on interface.
     289             :          */
     290             :         case  SIOCGIFMEDIA:
     291             :         {
     292           0 :                 struct ifmediareq *ifmr = (struct ifmediareq *) ifr;
     293             :                 struct ifmedia_entry *ep;
     294             :                 size_t nwords;
     295             : 
     296           0 :                 if (ifmr->ifm_count < 0)
     297           0 :                         return (EINVAL);
     298             : 
     299           0 :                 ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
     300           0 :                     ifm->ifm_cur->ifm_media : IFM_NONE;
     301           0 :                 ifmr->ifm_mask = ifm->ifm_mask;
     302           0 :                 ifmr->ifm_status = 0;
     303           0 :                 (*ifm->ifm_status)(ifp, ifmr);
     304             : 
     305             :                 /*
     306             :                  * Count them so we know a-priori how much is the max we'll
     307             :                  * need.
     308             :                  */
     309           0 :                 ep = TAILQ_FIRST(&ifm->ifm_list);
     310           0 :                 for (nwords = 0; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list))
     311           0 :                         nwords++;
     312             : 
     313           0 :                 if (ifmr->ifm_count != 0) {
     314             :                         size_t minwords, ksiz;
     315             :                         uint64_t *kptr;
     316             : 
     317           0 :                         minwords = nwords > (size_t)ifmr->ifm_count ?
     318             :                             (size_t)ifmr->ifm_count : nwords;
     319           0 :                         kptr = mallocarray(nwords, sizeof(*kptr), M_TEMP,
     320             :                             M_WAITOK | M_ZERO);
     321           0 :                         ksiz = nwords * sizeof(*kptr);
     322             :                         /*
     323             :                          * Get the media words from the interface's list.
     324             :                          */
     325           0 :                         ep = TAILQ_FIRST(&ifm->ifm_list);
     326           0 :                         for (nwords = 0; ep != NULL && nwords < minwords;
     327           0 :                             ep = TAILQ_NEXT(ep, ifm_list))
     328           0 :                                 kptr[nwords++] = ep->ifm_media;
     329           0 :                         if (ep == NULL)
     330           0 :                                 error = copyout(kptr, ifmr->ifm_ulist,
     331           0 :                                     nwords * sizeof(*kptr));
     332             :                         else
     333             :                                 error = E2BIG;
     334           0 :                         free(kptr, M_TEMP, ksiz);
     335           0 :                 }
     336           0 :                 ifmr->ifm_count = nwords;
     337           0 :                 break;
     338             :         }
     339             : 
     340             :         default:
     341           0 :                 return (ENOTTY);
     342             :         }
     343             : 
     344           0 :         return (error);
     345           0 : }
     346             : 
     347             : /*
     348             :  * Find media entry matching a given ifm word.
     349             :  */
     350             : struct ifmedia_entry *
     351           0 : ifmedia_match(struct ifmedia *ifm, uint64_t target, uint64_t mask)
     352             : {
     353             :         struct ifmedia_entry *match, *next;
     354             : 
     355             :         match = NULL;
     356           0 :         mask = ~mask;
     357             : 
     358           0 :         TAILQ_FOREACH(next, &ifm->ifm_list, ifm_list) {
     359           0 :                 if ((next->ifm_media & mask) == (target & mask)) {
     360           0 :                         if (match) {
     361             : #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC)
     362           0 :                                 printf("ifmedia_match: multiple match for "
     363             :                                     "0x%llx/0x%llx, selected instance %lld\n",
     364           0 :                                     target, mask, IFM_INST(match->ifm_media));
     365             : #endif
     366           0 :                                 break;
     367             :                         }
     368             :                         match = next;
     369           0 :                 }
     370             :         }
     371             : 
     372           0 :         return (match);
     373             : }
     374             : 
     375             : /*
     376             :  * Delete all media for a given instance.
     377             :  */
     378             : void
     379           0 : ifmedia_delete_instance(struct ifmedia *ifm, uint64_t inst)
     380             : {
     381             :         struct ifmedia_entry *ife, *nife;
     382             : 
     383           0 :         TAILQ_FOREACH_SAFE(ife, &ifm->ifm_list, ifm_list, nife) {
     384           0 :                 if (inst == IFM_INST_ANY ||
     385           0 :                     inst == IFM_INST(ife->ifm_media)) {
     386           0 :                         TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list);
     387           0 :                         free(ife, M_IFADDR, sizeof *ife);
     388           0 :                 }
     389             :         }
     390           0 : }
     391             : 
     392             : /*
     393             :  * Compute the interface `baudrate' from the media, for the interface
     394             :  * metrics (used by routing daemons).
     395             :  */
     396             : struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
     397             :     IFM_BAUDRATE_DESCRIPTIONS;
     398             : 
     399             : uint64_t
     400           0 : ifmedia_baudrate(uint64_t mword)
     401             : {
     402             :         int i;
     403             : 
     404           0 :         for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
     405           0 :                 if ((mword & (IFM_NMASK|IFM_TMASK)) ==
     406             :                     ifmedia_baudrate_descriptions[i].ifmb_word)
     407           0 :                         return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
     408             :         }
     409             : 
     410             :         /* Not known. */
     411           0 :         return (0);
     412           0 : }
     413             : 
     414             : #ifdef IFMEDIA_DEBUG
     415             : 
     416             : struct ifmedia_description ifm_type_descriptions[] =
     417             :     IFM_TYPE_DESCRIPTIONS;
     418             : 
     419             : struct ifmedia_description ifm_subtype_descriptions[] =
     420             :     IFM_SUBTYPE_DESCRIPTIONS;
     421             : 
     422             : struct ifmedia_description ifm_option_descriptions[] =
     423             :     IFM_OPTION_DESCRIPTIONS;
     424             : 
     425             : /*
     426             :  * print a media word.
     427             :  */
     428             : static void
     429             : ifmedia_printword(uint64_t ifmw)
     430             : {
     431             :         struct ifmedia_description *desc;
     432             :         uint64_t seen_option = 0;
     433             : 
     434             :         /* Print the top-level interface type. */
     435             :         for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
     436             :              desc++) {
     437             :                 if (IFM_TYPE(ifmw) == desc->ifmt_word)
     438             :                         break;
     439             :         }
     440             :         if (desc->ifmt_string == NULL)
     441             :                 printf("<unknown type> ");
     442             :         else
     443             :                 printf("%s ", desc->ifmt_string);
     444             : 
     445             :         /* Print the subtype. */
     446             :         for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
     447             :              desc++) {
     448             :                 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
     449             :                     IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(ifmw))
     450             :                         break;
     451             :         }
     452             :         if (desc->ifmt_string == NULL)
     453             :                 printf("<unknown subtype>");
     454             :         else
     455             :                 printf("%s", desc->ifmt_string);
     456             : 
     457             :         /* Print any options. */
     458             :         for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
     459             :              desc++) {
     460             :                 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
     461             :                     (ifmw & desc->ifmt_word) != 0 &&
     462             :                     (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
     463             :                         if (seen_option == 0)
     464             :                                 printf(" <");
     465             :                         printf("%s%s", seen_option ? "," : "",
     466             :                             desc->ifmt_string);
     467             :                         seen_option |= IFM_OPTIONS(desc->ifmt_word);
     468             :                 }
     469             :         }
     470             :         printf("%s\n", seen_option ? ">" : "");
     471             : }
     472             : 
     473             : #endif /* IFMEDIA_DEBUG */

Generated by: LCOV version 1.13