2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * The contents of this file constitute Original Code as defined in and 
   7  * are subject to the Apple Public Source License Version 1.1 (the 
   8  * "License").  You may not use this file except in compliance with the 
   9  * License.  Please obtain a copy of the License at 
  10  * http://www.apple.com/publicsource and read it before using this file. 
  12  * This Original Code and all software distributed under the License are 
  13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the 
  17  * License for the specific language governing rights and limitations 
  20  * @APPLE_LICENSE_HEADER_END@ 
  22 /*      $NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $     */ 
  23 /* $FreeBSD: src/sys/net/if_media.c,v 1.9.2.4 2001/07/04 00:12:38 brooks Exp $ */ 
  27  *      Jonathan Stone and Jason R. Thorpe.  All rights reserved. 
  29  * This software is derived from information provided by Matt Thomas. 
  31  * Redistribution and use in source and binary forms, with or without 
  32  * modification, are permitted provided that the following conditions 
  34  * 1. Redistributions of source code must retain the above copyright 
  35  *    notice, this list of conditions and the following disclaimer. 
  36  * 2. Redistributions in binary form must reproduce the above copyright 
  37  *    notice, this list of conditions and the following disclaimer in the 
  38  *    documentation and/or other materials provided with the distribution. 
  39  * 3. All advertising materials mentioning features or use of this software 
  40  *    must display the following acknowledgement: 
  41  *      This product includes software developed by Jonathan Stone 
  42  *      and Jason R. Thorpe for the NetBSD Project. 
  43  * 4. The names of the authors may not be used to endorse or promote products 
  44  *    derived from this software without specific prior written permission. 
  46  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 
  47  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
  48  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
  49  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 
  50  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
  51  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
  52  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
  53  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
  55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  60  * BSD/OS-compatible network interface media selection. 
  62  * Where it is safe to do so, this code strays slightly from the BSD/OS 
  63  * design.  Software which uses the API (device drivers, basically) 
  64  * shouldn't notice any difference. 
  66  * Many thanks to Matt Thomas for providing the information necessary 
  67  * to implement this interface. 
  70 #include <sys/param.h> 
  71 #include <sys/systm.h> 
  72 #include <sys/socket.h> 
  73 #include <sys/sockio.h> 
  74 #include <sys/malloc.h> 
  77 #include <net/if_media.h> 
  80  * Compile-time options: 
  82  *      turn on implementation-level debug printfs. 
  83  *      Useful for debugging newly-ported  drivers. 
  86 static struct ifmedia_entry 
*ifmedia_match 
__P((struct ifmedia 
*ifm
, 
  87     int flags
, int mask
)); 
  90 int     ifmedia_debug 
= 0; 
  91 static  void ifmedia_printword 
__P((int)); 
  95  * Initialize if_media struct for a specific interface instance. 
  98 ifmedia_init(ifm
, dontcare_mask
, change_callback
, status_callback
) 
 101         ifm_change_cb_t change_callback
; 
 102         ifm_stat_cb_t status_callback
; 
 105         LIST_INIT(&ifm
->ifm_list
); 
 108         ifm
->ifm_mask 
= dontcare_mask
;          /* IF don't-care bits */ 
 109         ifm
->ifm_change 
= change_callback
; 
 110         ifm
->ifm_status 
= status_callback
; 
 114 ifmedia_removeall(ifm
) 
 117         struct ifmedia_entry 
*entry
; 
 119         for (entry 
= LIST_FIRST(&ifm
->ifm_list
); entry
; 
 120              entry 
= LIST_FIRST(&ifm
->ifm_list
)) { 
 121                 LIST_REMOVE(entry
, ifm_list
); 
 122                 FREE(entry
, M_IFADDR
); 
 127  * Add a media configuration to the list of supported media 
 128  * for a specific interface instance. 
 131 ifmedia_add(ifm
, mword
, data
, aux
) 
 137         register struct ifmedia_entry 
*entry
; 
 142                         printf("ifmedia_add: null ifm\n"); 
 145                 printf("Adding entry for "); 
 146                 ifmedia_printword(mword
); 
 150         entry 
= _MALLOC(sizeof(*entry
), M_IFADDR
, M_NOWAIT
); 
 152                 panic("ifmedia_add: can't malloc entry"); 
 154         entry
->ifm_media 
= mword
; 
 155         entry
->ifm_data 
= data
; 
 156         entry
->ifm_aux 
= aux
; 
 158         LIST_INSERT_HEAD(&ifm
->ifm_list
, entry
, ifm_list
); 
 162  * Add an array of media configurations to the list of 
 163  * supported media for a specific interface instance. 
 166 ifmedia_list_add(ifm
, lp
, count
) 
 168         struct ifmedia_entry 
*lp
; 
 173         for (i 
= 0; i 
< count
; i
++) 
 174                 ifmedia_add(ifm
, lp
[i
].ifm_media
, lp
[i
].ifm_data
, 
 179  * Set the default active media.  
 181  * Called by device-specific code which is assumed to have already 
 182  * selected the default media in hardware.  We do _not_ call the 
 183  * media-change callback. 
 186 ifmedia_set(ifm
, target
) 
 191         struct ifmedia_entry 
*match
; 
 193         match 
= ifmedia_match(ifm
, target
, ifm
->ifm_mask
); 
 196                 printf("ifmedia_set: no match for 0x%x/0x%x\n", 
 197                     target
, ~ifm
->ifm_mask
); 
 198                 panic("ifmedia_set"); 
 200         ifm
->ifm_cur 
= match
; 
 204                 printf("ifmedia_set: target "); 
 205                 ifmedia_printword(target
); 
 206                 printf("ifmedia_set: setting to "); 
 207                 ifmedia_printword(ifm
->ifm_cur
->ifm_media
); 
 213  * Device-independent media ioctl support function. 
 216 ifmedia_ioctl(ifp
, ifr
, ifm
, cmd
) 
 222         struct ifmedia_entry 
*match
; 
 223         struct ifmediareq 
*ifmr 
= (struct ifmediareq 
*) ifr
; 
 224         int error 
= 0, sticky
; 
 226         if (ifp 
== NULL 
|| ifr 
== NULL 
|| ifm 
== NULL
) 
 232          * Set the current media. 
 236                 struct ifmedia_entry 
*oldentry
; 
 238                 int newmedia 
= ifr
->ifr_media
; 
 240                 match 
= ifmedia_match(ifm
, newmedia
, ifm
->ifm_mask
); 
 245                                     "ifmedia_ioctl: no media found for 0x%x\n",  
 253                  * If no change, we're done. 
 254                  * XXX Automedia may invole software intervention. 
 255                  *     Keep going in case the the connected media changed. 
 256                  *     Similarly, if best match changed (kernel debugger?). 
 258                 if ((IFM_SUBTYPE(newmedia
) != IFM_AUTO
) && 
 259                     (newmedia 
== ifm
->ifm_media
) && 
 260                     (match 
== ifm
->ifm_cur
)) 
 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. 
 270                         printf("ifmedia_ioctl: switching %s to ", 
 272                         ifmedia_printword(match
->ifm_media
); 
 275                 oldentry 
= ifm
->ifm_cur
; 
 276                 oldmedia 
= ifm
->ifm_media
; 
 277                 ifm
->ifm_cur 
= match
; 
 278                 ifm
->ifm_media 
= newmedia
; 
 279                 error 
= (*ifm
->ifm_change
)(ifp
); 
 281                         ifm
->ifm_cur 
= oldentry
; 
 282                         ifm
->ifm_media 
= oldmedia
; 
 288          * Get list of available media and current media on interface. 
 292                 struct ifmedia_entry 
*ep
; 
 294                 int usermax
;    /* user requested max */ 
 296                 kptr 
= NULL
;            /* XXX gcc */ 
 298                 ifmr
->ifm_active 
= ifmr
->ifm_current 
= ifm
->ifm_cur 
? 
 299                     ifm
->ifm_cur
->ifm_media 
: IFM_NONE
; 
 300                 ifmr
->ifm_mask 
= ifm
->ifm_mask
; 
 301                 ifmr
->ifm_status 
= 0; 
 302                 (*ifm
->ifm_status
)(ifp
, ifmr
); 
 308                  * If there are more interfaces on the list, count 
 309                  * them.  This allows the caller to set ifmr->ifm_count 
 310                  * to 0 on the first call to know how much space to 
 313                 LIST_FOREACH(ep
, &ifm
->ifm_list
, ifm_list
) 
 317                  * Don't allow the user to ask for too many 
 318                  * or a negative number. 
 320                 if (ifmr
->ifm_count 
> usermax
) 
 321                         ifmr
->ifm_count 
= usermax
; 
 322                 else if (ifmr
->ifm_count 
< 0) 
 325                 if (ifmr
->ifm_count 
!= 0) { 
 326                         kptr 
= (int *) _MALLOC(ifmr
->ifm_count 
* sizeof(int), 
 330                          * Get the media words from the interface's list. 
 332                         ep 
= LIST_FIRST(&ifm
->ifm_list
); 
 333                         for (; ep 
!= NULL 
&& count 
< ifmr
->ifm_count
; 
 334                             ep 
= LIST_NEXT(ep
, ifm_list
), count
++) 
 335                                 kptr
[count
] = ep
->ifm_media
; 
 338                                 error 
= E2BIG
;  /* oops! */ 
 344                  * We do the copyout on E2BIG, because that's 
 345                  * just our way of telling userland that there 
 346                  * are more.  This is the behavior I've observed 
 350                 if ((error 
== 0 || error 
== E2BIG
) && ifmr
->ifm_count 
!= 0) { 
 351                         error 
= copyout((caddr_t
)kptr
, 
 352                             (caddr_t
)ifmr
->ifm_ulist
, 
 353                             ifmr
->ifm_count 
* sizeof(int)); 
 359                 if (ifmr
->ifm_count 
!= 0) 
 362                 ifmr
->ifm_count 
= count
; 
 374  * Find media entry matching a given ifm word. 
 377 static struct ifmedia_entry 
* 
 378 ifmedia_match(ifm
, target
, mask
) 
 383         struct ifmedia_entry 
*match
, *next
; 
 388         LIST_FOREACH(next
, &ifm
->ifm_list
, ifm_list
) { 
 389                 if ((next
->ifm_media 
& mask
) == (target 
& mask
)) { 
 390 #if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) 
 392                                 printf("ifmedia_match: multiple match for " 
 393                                     "0x%x/0x%x\n", target
, mask
); 
 404 struct ifmedia_description ifm_type_descriptions
[] = 
 405     IFM_TYPE_DESCRIPTIONS
; 
 407 struct ifmedia_description ifm_subtype_ethernet_descriptions
[] = 
 408     IFM_SUBTYPE_ETHERNET_DESCRIPTIONS
; 
 410 struct ifmedia_description ifm_subtype_ethernet_option_descriptions
[] = 
 411     IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS
; 
 413 struct ifmedia_description ifm_subtype_tokenring_descriptions
[] = 
 414     IFM_SUBTYPE_TOKENRING_DESCRIPTIONS
; 
 416 struct ifmedia_description ifm_subtype_tokenring_option_descriptions
[] = 
 417     IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS
; 
 419 struct ifmedia_description ifm_subtype_fddi_descriptions
[] = 
 420     IFM_SUBTYPE_FDDI_DESCRIPTIONS
; 
 422 struct ifmedia_description ifm_subtype_fddi_option_descriptions
[] = 
 423     IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS
; 
 425 struct ifmedia_description ifm_subtype_80211_descriptions
[] = 
 426     IFM_SUBTYPE_IEEE80211_DESCRIPTIONS
; 
 428 struct ifmedia_description ifm_subtype_80211_option_descriptions
[] = 
 429     IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS
; 
 431 struct ifmedia_description ifm_subtype_shared_descriptions
[] = 
 432     IFM_SUBTYPE_SHARED_DESCRIPTIONS
; 
 434 struct ifmedia_description ifm_shared_option_descriptions
[] = 
 435     IFM_SHARED_OPTION_DESCRIPTIONS
; 
 437 struct ifmedia_type_to_subtype 
{ 
 438         struct ifmedia_description 
*subtypes
; 
 439         struct ifmedia_description 
*options
; 
 442 /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ 
 443 struct ifmedia_type_to_subtype ifmedia_types_to_subtypes
[] = { 
 445           &ifm_subtype_ethernet_descriptions
[0], 
 446           &ifm_subtype_ethernet_option_descriptions
[0] 
 449           &ifm_subtype_tokenring_descriptions
[0], 
 450           &ifm_subtype_tokenring_option_descriptions
[0] 
 453           &ifm_subtype_fddi_descriptions
[0], 
 454           &ifm_subtype_fddi_option_descriptions
[0] 
 457           &ifm_subtype_80211_descriptions
[0], 
 458           &ifm_subtype_80211_option_descriptions
[0] 
 463  * print a media word. 
 466 ifmedia_printword(ifmw
) 
 469         struct ifmedia_description 
*desc
; 
 470         struct ifmedia_type_to_subtype 
*ttos
; 
 473         /* Find the top-level interface type. */ 
 474         for (desc 
= ifm_type_descriptions
, ttos 
= ifmedia_types_to_subtypes
; 
 475             desc
->ifmt_string 
!= NULL
; desc
++, ttos
++) 
 476                 if (IFM_TYPE(ifmw
) == desc
->ifmt_word
) 
 478         if (desc
->ifmt_string 
== NULL
) { 
 479                 printf("<unknown type>\n"); 
 482         printf(desc
->ifmt_string
); 
 485          * Check for the shared subtype descriptions first, then the 
 486          * type-specific ones. 
 488         for (desc 
= ifm_subtype_shared_descriptions
; 
 489             desc
->ifmt_string 
!= NULL
; desc
++) 
 490                 if (IFM_SUBTYPE(ifmw
) == desc
->ifmt_word
) 
 493         for (desc 
= ttos
->subtypes
; desc
->ifmt_string 
!= NULL
; desc
++) 
 494                 if (IFM_SUBTYPE(ifmw
) == desc
->ifmt_word
) 
 496         if (desc
->ifmt_string 
== NULL
) { 
 497                 printf(" <unknown subtype>\n"); 
 502         printf(" %s", desc
->ifmt_string
); 
 505          * Look for shared options. 
 507         for (desc 
= ifm_shared_option_descriptions
; 
 508             desc
->ifmt_string 
!= NULL
; desc
++) { 
 509                 if (ifmw 
& desc
->ifmt_word
) { 
 510                         if (seen_option 
== 0) 
 512                         printf("%s%s", seen_option
++ ? "," : "", 
 518          * Look for subtype-specific options. 
 520         for (desc 
= ttos
->options
; desc
->ifmt_string 
!= NULL
; desc
++) { 
 521                 if (ifmw 
& desc
->ifmt_word
) { 
 522                         if (seen_option 
== 0) 
 524                         printf("%s%s", seen_option
++ ? "," : "", 
 528         printf("%s\n", seen_option 
? ">" : ""); 
 530 #endif /* IFMEDIA_DEBUG */