2011-06-16 23:47:30 +04:00
/* $NetBSD: if_ethersubr.c,v 1.188 2011/06/16 19:47:30 kefren Exp $ */
1999-07-01 12:12:45 +04:00
/*
* Copyright ( C ) 1995 , 1996 , 1997 , and 1998 WIDE Project .
* All rights reserved .
2005-02-27 01:45:09 +03:00
*
1999-07-01 12:12:45 +04:00
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
2005-02-27 01:45:09 +03:00
*
1999-07-01 12:12:45 +04:00
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*/
1994-06-29 10:29:24 +04:00
1993-03-21 12:45:37 +03:00
/*
1994-05-13 10:01:27 +04:00
* Copyright ( c ) 1982 , 1989 , 1993
* The Regents of the University of California . All rights reserved .
1993-03-21 12:45:37 +03:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2003-08-07 20:26:28 +04:00
* 3. Neither the name of the University nor the names of its contributors
1993-03-21 12:45:37 +03:00
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ` ` AS IS ' ' AND
* ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT
* LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
1998-03-01 05:20:01 +03:00
* @ ( # ) if_ethersubr . c 8.2 ( Berkeley ) 4 / 4 / 96
1993-03-21 12:45:37 +03:00
*/
2001-11-13 02:49:33 +03:00
# include <sys/cdefs.h>
2011-06-16 23:47:30 +04:00
__KERNEL_RCSID ( 0 , " $NetBSD: if_ethersubr.c,v 1.188 2011/06/16 19:47:30 kefren Exp $ " ) ;
2001-11-13 02:49:33 +03:00
1998-07-05 04:51:04 +04:00
# include "opt_inet.h"
# include "opt_atalk.h"
1998-07-05 08:37:35 +04:00
# include "opt_iso.h"
2003-06-23 15:00:59 +04:00
# include "opt_ipx.h"
# include "opt_mbuftrace.h"
2010-06-26 18:24:27 +04:00
# include "opt_mpls.h"
1998-04-30 01:37:52 +04:00
# include "opt_gateway.h"
2001-04-11 01:47:36 +04:00
# include "opt_pfil_hooks.h"
2006-08-05 21:20:54 +04:00
# include "opt_pppoe.h"
2000-09-28 02:58:21 +04:00
# include "vlan.h"
2001-04-29 13:50:36 +04:00
# include "pppoe.h"
2001-04-11 07:47:24 +04:00
# include "bridge.h"
2002-04-07 11:05:37 +04:00
# include "arp.h"
2005-03-18 14:11:50 +03:00
# include "agr.h"
1998-04-30 01:37:52 +04:00
1993-12-17 03:10:06 +03:00
# include <sys/param.h>
# include <sys/systm.h>
# include <sys/kernel.h>
2001-04-29 13:50:36 +04:00
# include <sys/callout.h>
1993-12-17 03:10:06 +03:00
# include <sys/malloc.h>
# include <sys/mbuf.h>
# include <sys/protosw.h>
# include <sys/socket.h>
# include <sys/ioctl.h>
# include <sys/errno.h>
# include <sys/syslog.h>
2006-05-15 01:19:33 +04:00
# include <sys/kauth.h>
2007-10-08 20:18:02 +04:00
# include <sys/cpu.h>
# include <sys/intr.h>
2008-01-01 01:48:41 +03:00
# include <sys/device.h>
1994-05-13 10:01:27 +04:00
1993-12-17 03:10:06 +03:00
# include <net/if.h>
# include <net/netisr.h>
# include <net/route.h>
# include <net/if_llc.h>
# include <net/if_dl.h>
1994-05-13 10:01:27 +04:00
# include <net/if_types.h>
1993-03-21 12:45:37 +03:00
2008-01-01 01:48:41 +03:00
# include <net/if_media.h>
# include <dev/mii/mii.h>
# include <dev/mii/miivar.h>
2002-04-07 11:05:37 +04:00
# if NARP == 0
/*
2003-01-22 14:47:05 +03:00
* XXX there should really be a way to issue this warning from within config ( 8 )
2002-04-07 11:05:37 +04:00
*/
2003-06-11 14:44:10 +04:00
# error You have included NETATALK or a pseudo-device in your configuration that depends on the presence of ethernet interfaces, but have no such interfaces configured. Check if you really need pseudo-device bridge, pppoe, vlan or options NETATALK.
2002-04-07 11:05:37 +04:00
# endif
2000-11-15 04:02:11 +03:00
# include <net/bpf.h>
1997-03-15 21:09:08 +03:00
# include <net/if_ether.h>
2000-09-28 02:58:21 +04:00
# include <net/if_vlanvar.h>
1997-03-15 21:09:08 +03:00
2001-04-29 13:50:36 +04:00
# if NPPPOE > 0
# include <net/if_pppoe.h>
# endif
2005-03-18 14:11:50 +03:00
# if NAGR > 0
# include <net/agr/ieee8023_slowprotocols.h> /* XXX */
# include <net/agr/ieee8023ad.h>
# include <net/agr/if_agrvar.h>
# endif
2001-04-11 07:47:24 +04:00
# if NBRIDGE > 0
# include <net/if_bridgevar.h>
# endif
1993-12-17 03:10:06 +03:00
# include <netinet/in.h>
1995-09-29 06:37:43 +03:00
# ifdef INET
1993-12-17 03:10:06 +03:00
# include <netinet/in_var.h>
1993-03-21 12:45:37 +03:00
# endif
1997-03-15 21:09:08 +03:00
# include <netinet/if_inarp.h>
1993-03-21 12:45:37 +03:00
1999-07-01 12:12:45 +04:00
# ifdef INET6
# ifndef INET
# include <netinet/in.h>
# endif
# include <netinet6/in6_var.h>
# include <netinet6/nd6.h>
# endif
1993-03-21 12:45:37 +03:00
2006-05-18 13:05:49 +04:00
# include "carp.h"
# if NCARP > 0
# include <netinet/ip_carp.h>
# endif
1998-05-04 16:54:22 +04:00
# ifdef IPX
# include <netipx/ipx.h>
# include <netipx/ipx_if.h>
# endif
1993-03-21 12:45:37 +03:00
# ifdef ISO
1993-12-17 03:10:06 +03:00
# include <netiso/argo_debug.h>
# include <netiso/iso.h>
# include <netiso/iso_var.h>
# include <netiso/iso_snpac.h>
1993-03-21 12:45:37 +03:00
# endif
1994-05-13 10:01:27 +04:00
1993-12-17 03:10:06 +03:00
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
# include <netatalk/at.h>
# include <netatalk/at_var.h>
# include <netatalk/at_extern.h>
# define llc_snap_org_code llc_un.type_snap.org_code
# define llc_snap_ether_type llc_un.type_snap.ether_type
extern u_char at_org_code [ 3 ] ;
extern u_char aarp_org_code [ 3 ] ;
# endif /* NETATALK */
2010-06-26 18:24:27 +04:00
# ifdef MPLS
# include <netmpls/mpls.h>
# include <netmpls/mpls_var.h>
# endif
2005-05-03 01:20:27 +04:00
static struct timeval bigpktppslim_last ;
static int bigpktppslim = 2 ; /* XXX */
static int bigpktpps_count ;
2005-01-08 06:18:18 +03:00
const uint8_t etherbroadcastaddr [ ETHER_ADDR_LEN ] =
{ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ;
2005-03-18 14:11:50 +03:00
const uint8_t ethermulticastaddr_slowprotocols [ ETHER_ADDR_LEN ] =
{ 0x01 , 0x80 , 0xc2 , 0x00 , 0x00 , 0x02 } ;
1994-05-13 10:01:27 +04:00
# define senderr(e) { error = (e); goto bad;}
1993-03-21 12:45:37 +03:00
2005-12-12 02:05:24 +03:00
static int ether_output ( struct ifnet * , struct mbuf * ,
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
const struct sockaddr * , struct rtentry * ) ;
1999-05-19 03:52:51 +04:00
1993-03-21 12:45:37 +03:00
/*
* Ethernet output routine .
* Encapsulate a packet of type family for the local net .
1997-03-15 21:09:08 +03:00
* Assumes that ifp is actually pointer to ethercom structure .
1993-03-21 12:45:37 +03:00
*/
1999-05-19 03:52:51 +04:00
static int
2010-05-05 22:12:24 +04:00
ether_output ( struct ifnet * const ifp0 , struct mbuf * const m0 ,
const struct sockaddr * const dst ,
2000-06-18 00:57:20 +04:00
struct rtentry * rt0 )
1993-03-21 12:45:37 +03:00
{
2008-02-20 20:05:52 +03:00
uint16_t etype = 0 ;
2005-03-31 19:48:13 +04:00
int error = 0 , hdrcmplt = 0 ;
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
uint8_t esrc [ 6 ] , edst [ 6 ] ;
1998-04-26 10:17:20 +04:00
struct mbuf * m = m0 ;
struct rtentry * rt ;
2007-07-21 06:24:11 +04:00
struct mbuf * mcopy = NULL ;
1998-04-26 10:17:20 +04:00
struct ether_header * eh ;
2006-05-18 13:05:49 +04:00
struct ifnet * ifp = ifp0 ;
2000-12-14 01:07:50 +03:00
ALTQ_DECL ( struct altq_pktattr pktattr ; )
1997-04-03 19:25:20 +04:00
# ifdef INET
1997-03-15 21:09:08 +03:00
struct arphdr * ah ;
1997-04-03 19:25:20 +04:00
# endif /* INET */
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
struct at_ifaddr * aa ;
# endif /* NETATALK */
1993-03-21 12:45:37 +03:00
2003-02-26 09:31:08 +03:00
# ifdef MBUFTRACE
2004-06-24 08:15:50 +04:00
m_claimm ( m , ifp - > if_mowner ) ;
2003-02-26 09:31:08 +03:00
# endif
2006-05-18 13:05:49 +04:00
# if NCARP > 0
if ( ifp - > if_type = = IFT_CARP ) {
struct ifaddr * ifa ;
/* loop back if this is going to the carp interface */
if ( dst ! = NULL & & ifp0 - > if_link_state = = LINK_STATE_UP & &
( ifa = ifa_ifwithaddr ( dst ) ) ! = NULL & &
ifa - > ifa_ifp = = ifp0 )
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
return looutput ( ifp0 , m , dst , rt0 ) ;
2006-05-18 13:05:49 +04:00
ifp = ifp - > if_carpdev ;
/* ac = (struct arpcom *)ifp; */
if ( ( ifp0 - > if_flags & ( IFF_UP | IFF_RUNNING ) ) ! =
( IFF_UP | IFF_RUNNING ) )
senderr ( ENETDOWN ) ;
}
# endif /* NCARP > 0 */
1994-05-13 10:01:27 +04:00
if ( ( ifp - > if_flags & ( IFF_UP | IFF_RUNNING ) ) ! = ( IFF_UP | IFF_RUNNING ) )
senderr ( ENETDOWN ) ;
1996-02-14 00:59:53 +03:00
if ( ( rt = rt0 ) ! = NULL ) {
1994-05-13 10:01:27 +04:00
if ( ( rt - > rt_flags & RTF_UP ) = = 0 ) {
1998-03-01 05:20:01 +03:00
if ( ( rt0 = rt = rtalloc1 ( dst , 1 ) ) ! = NULL ) {
1994-05-13 10:01:27 +04:00
rt - > rt_refcnt - - ;
1998-03-01 05:20:01 +03:00
if ( rt - > rt_ifp ! = ifp )
return ( * rt - > rt_ifp - > if_output )
( ifp , m0 , dst , rt ) ;
2005-02-27 01:45:09 +03:00
} else
1994-05-13 10:01:27 +04:00
senderr ( EHOSTUNREACH ) ;
}
1998-03-01 05:20:01 +03:00
if ( ( rt - > rt_flags & RTF_GATEWAY ) & & dst - > sa_family ! = AF_NS ) {
2008-05-12 00:13:30 +04:00
if ( rt - > rt_gwroute = = NULL )
1994-05-13 10:01:27 +04:00
goto lookup ;
if ( ( ( rt = rt - > rt_gwroute ) - > rt_flags & RTF_UP ) = = 0 ) {
rtfree ( rt ) ; rt = rt0 ;
lookup : rt - > rt_gwroute = rtalloc1 ( rt - > rt_gateway , 1 ) ;
2008-05-12 00:13:30 +04:00
if ( ( rt = rt - > rt_gwroute ) = = NULL )
1994-05-13 10:01:27 +04:00
senderr ( EHOSTUNREACH ) ;
1998-03-01 05:20:01 +03:00
/* the "G" test below also prevents rt == rt0 */
if ( ( rt - > rt_flags & RTF_GATEWAY ) | |
( rt - > rt_ifp ! = ifp ) ) {
rt - > rt_refcnt - - ;
2008-05-12 00:13:30 +04:00
rt0 - > rt_gwroute = NULL ;
1998-03-01 05:20:01 +03:00
senderr ( EHOSTUNREACH ) ;
}
1994-05-13 10:01:27 +04:00
}
}
if ( rt - > rt_flags & RTF_REJECT )
if ( rt - > rt_rmx . rmx_expire = = 0 | |
2006-06-08 02:33:33 +04:00
( u_long ) time_second < rt - > rt_rmx . rmx_expire )
1994-05-13 10:01:27 +04:00
senderr ( rt = = rt0 ? EHOSTDOWN : EHOSTUNREACH ) ;
}
2000-12-14 01:07:50 +03:00
1993-03-21 12:45:37 +03:00
switch ( dst - > sa_family ) {
# ifdef INET
case AF_INET :
1997-03-15 21:09:08 +03:00
if ( m - > m_flags & M_BCAST )
2009-11-28 05:58:21 +03:00
( void ) memcpy ( edst , etherbroadcastaddr , sizeof ( edst ) ) ;
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
else if ( m - > m_flags & M_MCAST )
ETHER_MAP_IP_MULTICAST ( & satocsin ( dst ) - > sin_addr , edst ) ;
else if ( ! arpresolve ( ifp , rt , m , dst , edst ) )
1993-03-21 12:45:37 +03:00
return ( 0 ) ; /* if not yet resolved */
1993-12-06 07:50:19 +03:00
/* If broadcasting on a simplex interface, loopback a copy */
if ( ( m - > m_flags & M_BCAST ) & & ( ifp - > if_flags & IFF_SIMPLEX ) )
1993-03-21 12:45:37 +03:00
mcopy = m_copy ( m , 0 , ( int ) M_COPYALL ) ;
1995-12-24 06:33:43 +03:00
etype = htons ( ETHERTYPE_IP ) ;
1994-05-13 10:01:27 +04:00
break ;
1997-03-15 21:09:08 +03:00
case AF_ARP :
ah = mtod ( m , struct arphdr * ) ;
if ( m - > m_flags & M_BCAST )
2009-11-28 05:58:21 +03:00
( void ) memcpy ( edst , etherbroadcastaddr , sizeof ( edst ) ) ;
2006-05-12 05:20:33 +04:00
else {
2007-03-04 08:59:00 +03:00
void * tha = ar_tha ( ah ) ;
2006-05-12 05:20:33 +04:00
2009-11-20 05:14:56 +03:00
if ( tha = = NULL ) {
/* fake with ARPHDR_IEEE1394 */
return 0 ;
}
2007-02-20 11:55:54 +03:00
memcpy ( edst , tha , sizeof ( edst ) ) ;
2006-05-12 05:20:33 +04:00
}
2005-02-27 01:45:09 +03:00
1997-03-15 21:09:08 +03:00
ah - > ar_hrd = htons ( ARPHRD_ETHER ) ;
2003-05-02 07:15:23 +04:00
switch ( ntohs ( ah - > ar_op ) ) {
1997-03-15 21:09:08 +03:00
case ARPOP_REVREQUEST :
case ARPOP_REVREPLY :
etype = htons ( ETHERTYPE_REVARP ) ;
break ;
case ARPOP_REQUEST :
case ARPOP_REPLY :
default :
etype = htons ( ETHERTYPE_ARP ) ;
}
break ;
1993-03-21 12:45:37 +03:00
# endif
1999-07-01 12:12:45 +04:00
# ifdef INET6
case AF_INET6 :
2008-05-12 00:13:30 +04:00
if ( ! nd6_storelladdr ( ifp , rt , m , dst , edst , sizeof ( edst ) ) ) {
2000-10-15 19:39:11 +04:00
/* something bad happened */
2002-09-11 09:36:26 +04:00
return ( 0 ) ;
1999-12-13 18:17:17 +03:00
}
1999-07-01 12:12:45 +04:00
etype = htons ( ETHERTYPE_IPV6 ) ;
break ;
# endif
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
case AF_APPLETALK :
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
if ( ! aarpresolve ( ifp , m , ( const struct sockaddr_at * ) dst , edst ) ) {
1997-04-03 01:23:26 +04:00
# ifdef NETATALKDEBUG
printf ( " aarpresolv failed \n " ) ;
# endif /* NETATALKDEBUG */
return ( 0 ) ;
}
/*
* ifaddr is the first thing in at_ifaddr
*/
aa = ( struct at_ifaddr * ) at_ifawithnet (
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
( const struct sockaddr_at * ) dst , ifp ) ;
1997-04-03 01:23:26 +04:00
if ( aa = = NULL )
goto bad ;
2005-02-27 01:45:09 +03:00
1997-04-03 01:23:26 +04:00
/*
* In the phase 2 case , we need to prepend an mbuf for the
* llc header . Since we must preserve the value of m ,
* which is passed to us by value , we m_copy ( ) the first
* mbuf , and use it for our llc header .
*/
if ( aa - > aa_flags & AFA_PHASE2 ) {
struct llc llc ;
1999-06-17 21:27:13 +04:00
M_PREPEND ( m , sizeof ( struct llc ) , M_DONTWAIT ) ;
1997-04-03 01:23:26 +04:00
llc . llc_dsap = llc . llc_ssap = LLC_SNAP_LSAP ;
llc . llc_control = LLC_UI ;
2007-02-20 11:55:54 +03:00
memcpy ( llc . llc_snap_org_code , at_org_code ,
1997-04-03 01:23:26 +04:00
sizeof ( llc . llc_snap_org_code ) ) ;
1998-10-13 06:34:31 +04:00
llc . llc_snap_ether_type = htons ( ETHERTYPE_ATALK ) ;
2007-03-04 08:59:00 +03:00
memcpy ( mtod ( m , void * ) , & llc , sizeof ( struct llc ) ) ;
1997-04-03 01:23:26 +04:00
} else {
1998-10-13 06:34:31 +04:00
etype = htons ( ETHERTYPE_ATALK ) ;
1997-04-03 01:23:26 +04:00
}
break ;
# endif /* NETATALK */
1998-05-04 16:54:22 +04:00
# ifdef IPX
case AF_IPX :
1998-12-10 18:50:54 +03:00
etype = htons ( ETHERTYPE_IPX ) ;
2007-02-20 11:55:54 +03:00
memcpy ( edst ,
& ( ( ( const struct sockaddr_ipx * ) dst ) - > sipx_addr . x_host ) ,
sizeof ( edst ) ) ;
1998-05-04 16:54:22 +04:00
/* If broadcasting on a simplex interface, loopback a copy */
if ( ( m - > m_flags & M_BCAST ) & & ( ifp - > if_flags & IFF_SIMPLEX ) )
mcopy = m_copy ( m , 0 , ( int ) M_COPYALL ) ;
break ;
# endif
1993-03-21 12:45:37 +03:00
# ifdef ISO
case AF_ISO : {
int snpalen ;
struct llc * l ;
2007-08-07 08:37:44 +04:00
const struct sockaddr_dl * sdl ;
1993-03-21 12:45:37 +03:00
2007-08-07 08:37:44 +04:00
if ( rt & & ( sdl = satocsdl ( rt - > rt_gateway ) ) & &
1994-05-13 10:01:27 +04:00
sdl - > sdl_family = = AF_LINK & & sdl - > sdl_alen > 0 ) {
2007-08-07 08:37:44 +04:00
memcpy ( edst , CLLADDR ( sdl ) , sizeof ( edst ) ) ;
1996-02-14 00:59:53 +03:00
} else {
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
error = iso_snparesolve ( ifp ,
( const struct sockaddr_iso * ) dst ,
1996-02-14 00:59:53 +03:00
( char * ) edst , & snpalen ) ;
if ( error )
goto bad ; /* Not Resolved */
}
1993-12-06 07:50:19 +03:00
/* If broadcasting on a simplex interface, loopback a copy */
1994-05-13 10:01:27 +04:00
if ( * edst & 1 )
m - > m_flags | = ( M_BCAST | M_MCAST ) ;
1993-12-06 07:50:19 +03:00
if ( ( m - > m_flags & M_BCAST ) & & ( ifp - > if_flags & IFF_SIMPLEX ) & &
1993-03-21 12:45:37 +03:00
( mcopy = m_copy ( m , 0 , ( int ) M_COPYALL ) ) ) {
M_PREPEND ( mcopy , sizeof ( * eh ) , M_DONTWAIT ) ;
if ( mcopy ) {
eh = mtod ( mcopy , struct ether_header * ) ;
2007-02-20 11:55:54 +03:00
memcpy ( eh - > ether_dhost , edst , sizeof ( edst ) ) ;
Use malloc(9) for sockaddrs instead of pool(9), and remove dom_sa_pool
and dom_sa_len members from struct domain. Pools of fixed-size
objects are too rigid for sockaddr_dls, whose size can vary over
a wide range.
Return sockaddr_dl to its "historical" size. Now that I'm using
malloc(9) instead of pool(9) to allocate sockaddr_dl, I can create
a sockaddr_dl of any size in the kernel, so expanding sockaddr_dl
is useless.
Avoid using sizeof(struct sockaddr_dl) in the kernel.
Introduce sockaddr_dl_alloc() for allocating & initializing an
arbitrary sockaddr_dl on the heap.
Add an argument, the sockaddr length, to sockaddr_alloc(),
sockaddr_copy(), and sockaddr_dl_setaddr().
Constify: LLADDR() -> CLLADDR().
Where the kernel overwrites LLADDR(), use sockaddr_dl_setaddr(),
instead. Used properly, sockaddr_dl_setaddr() will not overrun
the end of the sockaddr.
2007-08-30 06:17:34 +04:00
memcpy ( eh - > ether_shost , CLLADDR ( ifp - > if_sadl ) ,
2007-02-20 11:55:54 +03:00
sizeof ( edst ) ) ;
1993-03-21 12:45:37 +03:00
}
}
M_PREPEND ( m , 3 , M_DONTWAIT ) ;
if ( m = = NULL )
return ( 0 ) ;
l = mtod ( m , struct llc * ) ;
l - > llc_dsap = l - > llc_ssap = LLC_ISO_LSAP ;
l - > llc_control = LLC_UI ;
1996-02-14 00:59:53 +03:00
# ifdef ARGO_DEBUG
if ( argo_debug [ D_ETHER ] ) {
1993-03-21 12:45:37 +03:00
int i ;
1996-10-13 06:10:01 +04:00
printf ( " unoutput: sending pkt to: " ) ;
1993-03-21 12:45:37 +03:00
for ( i = 0 ; i < 6 ; i + + )
1996-10-13 06:10:01 +04:00
printf ( " %x " , edst [ i ] & 0xff ) ;
printf ( " \n " ) ;
1996-02-14 00:59:53 +03:00
}
# endif
1994-05-13 10:01:27 +04:00
} break ;
# endif /* ISO */
1993-03-21 12:45:37 +03:00
1998-04-30 04:05:41 +04:00
case pseudo_AF_HDRCMPLT :
hdrcmplt = 1 ;
2007-02-20 11:55:54 +03:00
memcpy ( esrc ,
( ( const struct ether_header * ) dst - > sa_data ) - > ether_shost ,
sizeof ( esrc ) ) ;
1998-04-30 04:05:41 +04:00
/* FALLTHROUGH */
1993-03-21 12:45:37 +03:00
case AF_UNSPEC :
2007-02-20 11:55:54 +03:00
memcpy ( edst ,
( ( const struct ether_header * ) dst - > sa_data ) - > ether_dhost ,
sizeof ( edst ) ) ;
1994-05-13 10:01:27 +04:00
/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
etype = ( ( const struct ether_header * ) dst - > sa_data ) - > ether_type ;
1994-05-13 10:01:27 +04:00
break ;
1993-03-21 12:45:37 +03:00
default :
1996-10-13 06:10:01 +04:00
printf ( " %s: can't handle af%d \n " , ifp - > if_xname ,
1993-03-21 12:45:37 +03:00
dst - > sa_family ) ;
1994-05-13 10:01:27 +04:00
senderr ( EAFNOSUPPORT ) ;
1993-03-21 12:45:37 +03:00
}
2010-06-26 18:24:27 +04:00
# ifdef MPLS
2010-11-17 03:20:49 +03:00
if ( rt0 ! = NULL & & rt_gettag ( rt0 ) ! = NULL & &
2011-06-16 23:47:30 +04:00
rt_gettag ( rt0 ) - > sa_family = = AF_MPLS & &
( m - > m_flags & ( M_MCAST | M_BCAST ) ) = = 0 ) {
2010-11-17 03:20:49 +03:00
union mpls_shim msh ;
msh . s_addr = MPLS_GETSADDR ( rt0 ) ;
if ( msh . shim . label ! = MPLS_LABEL_IMPLNULL )
etype = htons ( ETHERTYPE_MPLS ) ;
}
2010-06-26 18:24:27 +04:00
# endif
1993-03-21 12:45:37 +03:00
if ( mcopy )
KNF: de-__P, bzero -> memset, bcmp -> memcmp. Remove extraneous
parentheses in return statements.
Cosmetic: don't open-code TAILQ_FOREACH().
Cosmetic: change types of variables to avoid oodles of casts: in
in6_src.c, avoid casts by changing several route_in6 pointers
to struct route pointers. Remove unnecessary casts to caddr_t
elsewhere.
Pave the way for eliminating address family-specific route caches:
soon, struct route will not embed a sockaddr, but it will hold
a reference to an external sockaddr, instead. We will set the
destination sockaddr using rtcache_setdst(). (I created a stub
for it, but it isn't used anywhere, yet.) rtcache_free() will
free the sockaddr. I have extracted from rtcache_free() a helper
subroutine, rtcache_clear(). rtcache_clear() will "forget" a
cached route, but it will not forget the destination by releasing
the sockaddr. I use rtcache_clear() instead of rtcache_free()
in rtcache_update(), because rtcache_update() is not supposed
to forget the destination.
Constify:
1 Introduce const accessor for route->ro_dst, rtcache_getdst().
2 Constify the 'dst' argument to ifnet->if_output(). This
led me to constify a lot of code called by output routines.
3 Constify the sockaddr argument to protosw->pr_ctlinput. This
led me to constify a lot of code called by ctlinput routines.
4 Introduce const macros for converting from a generic sockaddr
to family-specific sockaddrs, e.g., sockaddr_in: satocsin6,
satocsin, et cetera.
2007-02-18 01:34:07 +03:00
( void ) looutput ( ifp , mcopy , dst , rt ) ;
1995-12-24 06:12:29 +03:00
1999-10-12 08:53:45 +04:00
/* If no ether type is set, this must be a 802.2 formatted packet.
*/
if ( etype = = 0 )
etype = htons ( m - > m_pkthdr . len ) ;
1993-03-21 12:45:37 +03:00
/*
* Add local net header . If no space in first mbuf ,
* allocate another .
*/
M_PREPEND ( m , sizeof ( struct ether_header ) , M_DONTWAIT ) ;
1994-05-13 10:01:27 +04:00
if ( m = = 0 )
senderr ( ENOBUFS ) ;
1993-03-21 12:45:37 +03:00
eh = mtod ( m , struct ether_header * ) ;
2002-08-19 22:58:50 +04:00
/* Note: etype is already in network byte order. */
2007-01-27 10:12:16 +03:00
( void ) memcpy ( & eh - > ether_type , & etype , sizeof ( eh - > ether_type ) ) ;
2007-02-20 11:55:54 +03:00
memcpy ( eh - > ether_dhost , edst , sizeof ( edst ) ) ;
1998-04-30 04:05:41 +04:00
if ( hdrcmplt )
2007-02-20 11:55:54 +03:00
memcpy ( eh - > ether_shost , esrc , sizeof ( eh - > ether_shost ) ) ;
1998-04-30 04:05:41 +04:00
else
2007-08-27 02:59:08 +04:00
memcpy ( eh - > ether_shost , CLLADDR ( ifp - > if_sadl ) ,
1998-04-30 04:05:41 +04:00
sizeof ( eh - > ether_shost ) ) ;
2001-04-11 01:47:36 +04:00
2006-05-18 13:05:49 +04:00
# if NCARP > 0
if ( ifp0 ! = ifp & & ifp0 - > if_type = = IFT_CARP ) {
2007-08-27 02:59:08 +04:00
memcpy ( eh - > ether_shost , CLLADDR ( ifp0 - > if_sadl ) ,
2006-05-18 13:05:49 +04:00
sizeof ( eh - > ether_shost ) ) ;
}
# endif /* NCARP > 0 */
2001-04-11 01:47:36 +04:00
# ifdef PFIL_HOOKS
if ( ( error = pfil_run_hooks ( & ifp - > if_pfil , & m , ifp , PFIL_OUT ) ) ! = 0 )
return ( error ) ;
if ( m = = NULL )
return ( 0 ) ;
# endif
2001-04-11 07:47:24 +04:00
# if NBRIDGE > 0
/*
* Bridges require special output handling .
*/
if ( ifp - > if_bridge )
return ( bridge_output ( ifp , m , NULL , NULL ) ) ;
# endif
2006-05-18 13:05:49 +04:00
# if NCARP > 0
if ( ifp ! = ifp0 )
ifp0 - > if_obytes + = m - > m_pkthdr . len + ETHER_HDR_LEN ;
# endif /* NCARP > 0 */
2001-04-11 01:47:36 +04:00
# ifdef ALTQ
/*
* If ALTQ is enabled on the parent interface , do
* classification ; the queueing discipline might not
* require classification , but might require the
* address family / header pointer in the pktattr .
*/
if ( ALTQ_IS_ENABLED ( & ifp - > if_snd ) )
altq_etherclassify ( & ifp - > if_snd , m , & pktattr ) ;
# endif
2005-03-31 19:48:13 +04:00
return ifq_enqueue ( ifp , m ALTQ_COMMA ALTQ_DECL ( & pktattr ) ) ;
1993-03-21 12:45:37 +03:00
bad :
if ( m )
m_freem ( m ) ;
return ( error ) ;
}
2001-04-07 22:01:48 +04:00
# ifdef ALTQ
/*
* This routine is a slight hack to allow a packet to be classified
* if the Ethernet headers are present . It will go away when ALTQ ' s
* classification engine understands link headers .
*/
void
altq_etherclassify ( struct ifaltq * ifq , struct mbuf * m ,
struct altq_pktattr * pktattr )
{
struct ether_header * eh ;
2008-02-20 20:05:52 +03:00
uint16_t ether_type ;
2001-04-07 22:01:48 +04:00
int hlen , af , hdrsize ;
2007-03-04 08:59:00 +03:00
void * hdr ;
2001-04-07 22:01:48 +04:00
hlen = ETHER_HDR_LEN ;
eh = mtod ( m , struct ether_header * ) ;
ether_type = htons ( eh - > ether_type ) ;
if ( ether_type < ETHERMTU ) {
/* LLC/SNAP */
struct llc * llc = ( struct llc * ) ( eh + 1 ) ;
hlen + = 8 ;
if ( m - > m_len < hlen | |
llc - > llc_dsap ! = LLC_SNAP_LSAP | |
llc - > llc_ssap ! = LLC_SNAP_LSAP | |
llc - > llc_control ! = LLC_UI ) {
/* Not SNAP. */
goto bad ;
}
ether_type = htons ( llc - > llc_un . type_snap . ether_type ) ;
}
switch ( ether_type ) {
case ETHERTYPE_IP :
af = AF_INET ;
hdrsize = 20 ; /* sizeof(struct ip) */
break ;
case ETHERTYPE_IPV6 :
af = AF_INET6 ;
hdrsize = 40 ; /* sizeof(struct ip6_hdr) */
break ;
default :
af = AF_UNSPEC ;
hdrsize = 0 ;
break ;
}
2002-05-19 02:52:44 +04:00
while ( m - > m_len < = hlen ) {
hlen - = m - > m_len ;
m = m - > m_next ;
}
2001-04-07 22:01:48 +04:00
if ( m - > m_len < ( hlen + hdrsize ) ) {
/*
2002-05-19 02:52:44 +04:00
* protocol header not in a single mbuf .
* We can ' t cope with this situation right
2001-04-07 22:01:48 +04:00
* now ( but it shouldn ' t ever happen , really , anyhow ) .
*/
2002-03-05 07:12:57 +03:00
# ifdef DEBUG
2001-04-11 07:47:24 +04:00
printf ( " altq_etherclassify: headers span multiple mbufs: "
" %d < %d \n " , m - > m_len , ( hlen + hdrsize ) ) ;
2002-03-05 07:12:57 +03:00
# endif
2001-04-07 22:01:48 +04:00
goto bad ;
}
m - > m_data + = hlen ;
m - > m_len - = hlen ;
2007-03-04 08:59:00 +03:00
hdr = mtod ( m , void * ) ;
2001-04-07 22:01:48 +04:00
if ( ALTQ_NEEDS_CLASSIFY ( ifq ) )
pktattr - > pattr_class =
( * ifq - > altq_classify ) ( ifq - > altq_clfier , m , af ) ;
pktattr - > pattr_af = af ;
pktattr - > pattr_hdr = hdr ;
m - > m_data - = hlen ;
m - > m_len + = hlen ;
return ;
bad :
pktattr - > pattr_class = NULL ;
pktattr - > pattr_hdr = NULL ;
pktattr - > pattr_af = AF_UNSPEC ;
}
# endif /* ALTQ */
1993-03-21 12:45:37 +03:00
/*
* Process a received Ethernet packet ;
1999-05-19 03:52:51 +04:00
* the packet is in the mbuf chain m with
* the ether header .
1993-03-21 12:45:37 +03:00
*/
2006-05-18 13:05:49 +04:00
void
2000-06-18 00:57:20 +04:00
ether_input ( struct ifnet * ifp , struct mbuf * m )
1993-03-21 12:45:37 +03:00
{
2002-02-28 22:23:03 +03:00
struct ethercom * ec = ( struct ethercom * ) ifp ;
1998-04-26 10:17:20 +04:00
struct ifqueue * inq ;
2008-02-20 20:05:52 +03:00
uint16_t etype ;
1999-05-19 03:52:51 +04:00
struct ether_header * eh ;
2011-05-24 21:16:43 +04:00
size_t ehlen ;
1997-04-03 01:23:26 +04:00
# if defined (ISO) || defined (LLC) || defined(NETATALK)
1998-04-26 10:17:20 +04:00
struct llc * l ;
1996-02-14 00:59:53 +03:00
# endif
1993-03-21 12:45:37 +03:00
1994-05-13 10:01:27 +04:00
if ( ( ifp - > if_flags & IFF_UP ) = = 0 ) {
m_freem ( m ) ;
return ;
}
1999-05-19 03:52:51 +04:00
2003-02-26 09:31:08 +03:00
# ifdef MBUFTRACE
2004-06-24 08:15:50 +04:00
m_claimm ( m , & ec - > ec_rx_mowner ) ;
2003-02-26 09:31:08 +03:00
# endif
1999-05-19 03:52:51 +04:00
eh = mtod ( m , struct ether_header * ) ;
2000-10-04 03:33:38 +04:00
etype = ntohs ( eh - > ether_type ) ;
2011-05-24 21:16:43 +04:00
ehlen = sizeof ( * eh ) ;
2000-10-04 03:33:38 +04:00
/*
* Determine if the packet is within its size limits .
*/
2010-06-26 18:24:27 +04:00
if ( etype ! = ETHERTYPE_MPLS & & m - > m_pkthdr . len >
2001-06-03 07:24:23 +04:00
ETHER_MAX_FRAME ( ifp , etype , m - > m_flags & M_HASFCS ) ) {
2005-05-03 01:20:27 +04:00
if ( ppsratecheck ( & bigpktppslim_last , & bigpktpps_count ,
bigpktppslim ) ) {
printf ( " %s: discarding oversize frame (len=%d) \n " ,
ifp - > if_xname , m - > m_pkthdr . len ) ;
}
2000-10-04 03:33:38 +04:00
m_freem ( m ) ;
return ;
}
1999-05-19 03:52:51 +04:00
2000-10-02 03:32:39 +04:00
if ( ETHER_IS_MULTICAST ( eh - > ether_dhost ) ) {
2001-06-12 19:03:26 +04:00
/*
* If this is not a simplex interface , drop the packet
* if it came from us .
*/
if ( ( ifp - > if_flags & IFF_SIMPLEX ) = = 0 & &
2007-08-27 02:59:08 +04:00
memcmp ( CLLADDR ( ifp - > if_sadl ) , eh - > ether_shost ,
2001-06-12 19:03:26 +04:00
ETHER_ADDR_LEN ) = = 0 ) {
m_freem ( m ) ;
return ;
}
2000-10-02 03:32:39 +04:00
if ( memcmp ( etherbroadcastaddr ,
eh - > ether_dhost , ETHER_ADDR_LEN ) = = 0 )
1994-05-13 10:01:27 +04:00
m - > m_flags | = M_BCAST ;
else
m - > m_flags | = M_MCAST ;
1993-03-21 12:45:37 +03:00
ifp - > if_imcasts + + ;
2001-04-11 07:47:24 +04:00
}
2001-06-12 19:03:26 +04:00
/* If the CRC is still on the packet, trim it off. */
if ( m - > m_flags & M_HASFCS ) {
m_adj ( m , - ETHER_CRC_LEN ) ;
m - > m_flags & = ~ M_HASFCS ;
}
ifp - > if_ibytes + = m - > m_pkthdr . len ;
2001-04-11 07:47:24 +04:00
# if NBRIDGE > 0
/*
* Tap the packet off here for a bridge . bridge_input ( )
* will return NULL if it has consumed the packet , otherwise
* it gets processed as normal . Note that bridge_input ( )
* will always return the original packet if we need to
* process it locally .
*/
if ( ifp - > if_bridge ) {
2006-11-23 07:07:07 +03:00
/* clear M_PROMISC, in case the packets comes from a vlan */
m - > m_flags & = ~ M_PROMISC ;
m = bridge_input ( ifp , m ) ;
if ( m = = NULL )
return ;
/*
* Bridge has determined that the packet is for us .
* Update our interface pointer - - we may have had
* to " bridge " the packet locally .
*/
ifp = m - > m_pkthdr . rcvif ;
2005-02-27 01:45:09 +03:00
} else
2001-04-11 07:47:24 +04:00
# endif /* NBRIDGE > 0 */
2003-03-25 16:29:39 +03:00
{
2006-05-18 13:05:49 +04:00
# if NCARP > 0
2008-03-15 08:07:34 +03:00
if ( __predict_false ( ifp - > if_carp & & ifp - > if_type ! = IFT_CARP ) ) {
2007-01-30 01:13:14 +03:00
/*
* clear M_PROMISC , in case the packets comes from a
* vlan
*/
m - > m_flags & = ~ M_PROMISC ;
2008-02-20 20:05:52 +03:00
if ( carp_input ( m , ( uint8_t * ) & eh - > ether_shost ,
( uint8_t * ) & eh - > ether_dhost , eh - > ether_type ) = = 0 )
2007-01-30 01:13:14 +03:00
return ;
2006-05-18 13:05:49 +04:00
}
# endif /* NCARP > 0 */
2008-03-15 08:07:34 +03:00
if ( ( m - > m_flags & ( M_BCAST | M_MCAST | M_PROMISC ) ) = = 0 & &
2003-03-25 16:29:39 +03:00
( ifp - > if_flags & IFF_PROMISC ) ! = 0 & &
2007-08-27 02:59:08 +04:00
memcmp ( CLLADDR ( ifp - > if_sadl ) , eh - > ether_dhost ,
2003-03-25 16:29:39 +03:00
ETHER_ADDR_LEN ) ! = 0 ) {
m - > m_flags | = M_PROMISC ;
}
2000-10-02 03:32:39 +04:00
}
2001-04-11 07:47:24 +04:00
# ifdef PFIL_HOOKS
2003-03-25 16:29:39 +03:00
if ( ( m - > m_flags & M_PROMISC ) = = 0 ) {
if ( pfil_run_hooks ( & ifp - > if_pfil , & m , ifp , PFIL_IN ) ! = 0 )
return ;
if ( m = = NULL )
return ;
2001-04-11 07:47:24 +04:00
2003-03-25 16:29:39 +03:00
eh = mtod ( m , struct ether_header * ) ;
etype = ntohs ( eh - > ether_type ) ;
2011-05-24 21:16:43 +04:00
ehlen = sizeof ( * eh ) ;
2003-03-25 16:29:39 +03:00
}
2001-04-11 07:47:24 +04:00
# endif
2009-05-29 08:57:04 +04:00
# if NAGR > 0
if ( ifp - > if_agrprivate & &
__predict_true ( etype ! = ETHERTYPE_SLOWPROTOCOLS ) ) {
m - > m_flags & = ~ M_PROMISC ;
agr_input ( ifp , m ) ;
return ;
}
# endif /* NAGR > 0 */
2002-02-28 22:23:03 +03:00
/*
* If VLANs are configured on the interface , check to
* see if the device performed the decapsulation and
* provided us with the tag .
*/
2003-10-30 04:43:08 +03:00
if ( ec - > ec_nvlans & & m_tag_find ( m , PACKET_TAG_VLAN , NULL ) ! = NULL ) {
2000-11-17 22:21:53 +03:00
# if NVLAN > 0
/*
* vlan_input ( ) will either recursively call ether_input ( )
* or drop the packet .
*/
2002-02-28 22:23:03 +03:00
vlan_input ( ifp , m ) ;
# else
m_freem ( m ) ;
2000-11-17 22:21:53 +03:00
# endif
return ;
}
2000-09-28 02:58:21 +04:00
/*
* Handle protocols that expect to have the Ethernet header
* ( and possibly FCS ) intact .
*/
switch ( etype ) {
2011-05-24 21:16:43 +04:00
case ETHERTYPE_VLAN : {
struct ether_vlan_header * evl = ( void * ) eh ;
/*
* If there is a tag of 0 , then the VLAN header was probably
* just being used to store the priority . Extract the ether
* type , and if IP or IPV6 , let them deal with it .
*/
if ( m - > m_len < = sizeof ( * evl )
& & EVL_VLANOFTAG ( evl - > evl_tag ) = = 0 ) {
etype = ntohs ( evl - > evl_proto ) ;
ehlen = sizeof ( * evl ) ;
if ( ( m - > m_flags & M_PROMISC ) = = 0
& & ( etype = = ETHERTYPE_IP
| | etype = = ETHERTYPE_IPV6 ) )
break ;
}
2000-09-28 02:58:21 +04:00
# if NVLAN > 0
/*
* vlan_input ( ) will either recursively call ether_input ( )
* or drop the packet .
*/
2000-10-04 03:33:38 +04:00
if ( ( ( struct ethercom * ) ifp ) - > ec_nvlans ! = 0 )
vlan_input ( ifp , m ) ;
2000-10-04 11:01:52 +04:00
else
2011-05-24 21:16:43 +04:00
# endif /* NVLAN > 0 */
2000-10-04 11:01:52 +04:00
m_freem ( m ) ;
2000-09-28 02:58:21 +04:00
return ;
2011-05-24 21:16:43 +04:00
}
2001-04-29 13:50:36 +04:00
# if NPPPOE > 0
case ETHERTYPE_PPPOEDISC :
case ETHERTYPE_PPPOE :
2003-03-25 16:29:39 +03:00
if ( m - > m_flags & M_PROMISC ) {
m_freem ( m ) ;
return ;
}
2003-03-02 13:50:14 +03:00
# ifndef PPPOE_SERVER
if ( m - > m_flags & ( M_MCAST | M_BCAST ) ) {
m_freem ( m ) ;
return ;
}
# endif
2005-02-27 01:45:09 +03:00
if ( etype = = ETHERTYPE_PPPOEDISC )
2001-04-29 13:50:36 +04:00
inq = & ppoediscinq ;
else
inq = & ppoeinq ;
if ( IF_QFULL ( inq ) ) {
IF_DROP ( inq ) ;
m_freem ( m ) ;
} else
IF_ENQUEUE ( inq , m ) ;
2007-10-08 20:18:02 +04:00
softint_schedule ( pppoe_softintr ) ;
2001-04-29 13:50:36 +04:00
return ;
# endif /* NPPPOE > 0 */
2005-03-18 14:11:50 +03:00
case ETHERTYPE_SLOWPROTOCOLS : {
uint8_t subtype ;
# if defined(DIAGNOSTIC)
if ( m - > m_pkthdr . len < sizeof ( * eh ) + sizeof ( subtype ) ) {
panic ( " ether_input: too short slow protocol packet " ) ;
}
# endif
m_copydata ( m , sizeof ( * eh ) , sizeof ( subtype ) , & subtype ) ;
switch ( subtype ) {
# if NAGR > 0
case SLOWPROTOCOLS_SUBTYPE_LACP :
if ( ifp - > if_agrprivate ) {
ieee8023ad_lacp_input ( ifp , m ) ;
return ;
}
break ;
case SLOWPROTOCOLS_SUBTYPE_MARKER :
if ( ifp - > if_agrprivate ) {
ieee8023ad_marker_input ( ifp , m ) ;
return ;
}
break ;
# endif /* NAGR > 0 */
default :
if ( subtype = = 0 | | subtype > 10 ) {
/* illegal value */
m_freem ( m ) ;
return ;
}
/* unknown subtype */
break ;
}
/* FALLTHROUGH */
}
2000-09-28 02:58:21 +04:00
default :
2003-03-25 16:29:39 +03:00
if ( m - > m_flags & M_PROMISC ) {
m_freem ( m ) ;
return ;
}
2000-09-28 02:58:21 +04:00
}
1999-08-04 23:29:01 +04:00
/* If the CRC is still on the packet, trim it off. */
2001-04-14 03:29:55 +04:00
if ( m - > m_flags & M_HASFCS ) {
1999-08-04 23:29:01 +04:00
m_adj ( m , - ETHER_CRC_LEN ) ;
2001-04-14 03:29:55 +04:00
m - > m_flags & = ~ M_HASFCS ;
}
1999-08-04 23:29:01 +04:00
2006-12-01 21:43:40 +03:00
if ( etype > ETHERMTU + sizeof ( struct ether_header ) ) {
/* Strip off the Ethernet header. */
2011-05-24 21:16:43 +04:00
m_adj ( m , ehlen ) ;
2006-12-01 21:43:40 +03:00
switch ( etype ) {
1993-03-21 12:45:37 +03:00
# ifdef INET
2006-12-01 21:43:40 +03:00
case ETHERTYPE_IP :
1998-04-30 01:37:52 +04:00
# ifdef GATEWAY
2006-12-01 21:43:40 +03:00
if ( ipflow_fastforward ( m ) )
return ;
1998-04-30 01:37:52 +04:00
# endif
2006-12-01 21:43:40 +03:00
schednetisr ( NETISR_IP ) ;
inq = & ipintrq ;
break ;
1993-03-21 12:45:37 +03:00
2006-12-01 21:43:40 +03:00
case ETHERTYPE_ARP :
schednetisr ( NETISR_ARP ) ;
inq = & arpintrq ;
break ;
1994-04-18 10:18:05 +04:00
2006-12-01 21:43:40 +03:00
case ETHERTYPE_REVARP :
revarpinput ( m ) ; /* XXX queue? */
return ;
1993-03-21 12:45:37 +03:00
# endif
1999-07-01 12:12:45 +04:00
# ifdef INET6
2006-12-01 21:43:40 +03:00
case ETHERTYPE_IPV6 :
2007-03-08 01:20:04 +03:00
# ifdef GATEWAY
if ( ip6flow_fastforward ( m ) )
return ;
# endif
2006-12-01 21:43:40 +03:00
schednetisr ( NETISR_IPV6 ) ;
inq = & ip6intrq ;
break ;
1999-07-01 12:12:45 +04:00
# endif
1998-05-04 16:54:22 +04:00
# ifdef IPX
2006-12-01 21:43:40 +03:00
case ETHERTYPE_IPX :
schednetisr ( NETISR_IPX ) ;
inq = & ipxintrq ;
break ;
1998-05-04 16:54:22 +04:00
# endif
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
2009-11-28 05:58:21 +03:00
case ETHERTYPE_ATALK :
schednetisr ( NETISR_ATALK ) ;
inq = & atintrq1 ;
break ;
case ETHERTYPE_AARP :
2006-12-01 21:43:40 +03:00
/* probably this should be done with a NETISR as well */
2009-11-28 12:20:37 +03:00
aarpinput ( ifp , m ) ; /* XXX */
2009-11-28 05:58:21 +03:00
return ;
1997-04-03 01:23:26 +04:00
# endif /* NETATALK */
2010-06-26 18:24:27 +04:00
# ifdef MPLS
case ETHERTYPE_MPLS :
schednetisr ( NETISR_MPLS ) ;
inq = & mplsintrq ;
break ;
# endif
2006-12-01 21:43:40 +03:00
default :
m_freem ( m ) ;
return ;
}
} else {
1997-04-03 01:23:26 +04:00
# if defined (ISO) || defined (LLC) || defined (NETATALK)
2006-12-01 21:43:40 +03:00
l = ( struct llc * ) ( eh + 1 ) ;
1994-05-13 10:01:27 +04:00
switch ( l - > llc_dsap ) {
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
case LLC_SNAP_LSAP :
switch ( l - > llc_control ) {
case LLC_UI :
if ( l - > llc_ssap ! = LLC_SNAP_LSAP ) {
goto dropanyway ;
}
2005-02-27 01:45:09 +03:00
2008-05-12 00:13:30 +04:00
if ( memcmp ( & ( l - > llc_snap_org_code ) [ 0 ] ,
1997-04-03 01:23:26 +04:00
at_org_code , sizeof ( at_org_code ) ) = = 0 & &
ntohs ( l - > llc_snap_ether_type ) = =
1998-10-13 06:34:31 +04:00
ETHERTYPE_ATALK ) {
1997-04-03 01:23:26 +04:00
inq = & atintrq2 ;
2006-12-01 21:43:40 +03:00
m_adj ( m , sizeof ( struct ether_header )
+ sizeof ( struct llc ) ) ;
1997-04-03 01:23:26 +04:00
schednetisr ( NETISR_ATALK ) ;
break ;
}
2008-05-12 00:13:30 +04:00
if ( memcmp ( & ( l - > llc_snap_org_code ) [ 0 ] ,
1997-04-03 01:23:26 +04:00
aarp_org_code ,
sizeof ( aarp_org_code ) ) = = 0 & &
ntohs ( l - > llc_snap_ether_type ) = =
ETHERTYPE_AARP ) {
2006-12-01 21:43:40 +03:00
m_adj ( m , sizeof ( struct ether_header )
+ sizeof ( struct llc ) ) ;
1997-04-03 01:23:26 +04:00
aarpinput ( ifp , m ) ; /* XXX */
return ;
}
2005-02-27 01:45:09 +03:00
1997-04-03 01:23:26 +04:00
default :
goto dropanyway ;
}
break ;
# endif /* NETATALK */
1994-05-13 10:01:27 +04:00
# ifdef ISO
2005-02-27 01:45:09 +03:00
case LLC_ISO_LSAP :
1994-05-13 10:01:27 +04:00
switch ( l - > llc_control ) {
case LLC_UI :
/* LLC_UI_P forbidden in class 1 service */
2006-12-01 21:43:40 +03:00
if ( ( l - > llc_dsap = = LLC_ISO_LSAP ) & & /* XXX? case tested */
1994-05-13 10:01:27 +04:00
( l - > llc_ssap = = LLC_ISO_LSAP ) ) {
/* LSAP for ISO */
2006-12-01 21:43:40 +03:00
/* XXX length computation?? */
if ( m - > m_pkthdr . len > etype + sizeof ( struct ether_header ) )
1995-04-06 01:38:50 +04:00
m_adj ( m , etype - m - > m_pkthdr . len ) ;
2006-12-01 21:43:40 +03:00
1996-02-14 00:59:53 +03:00
# ifdef ARGO_DEBUG
if ( argo_debug [ D_ETHER ] )
1996-10-13 06:10:01 +04:00
printf ( " clnp packet " ) ;
1996-02-14 00:59:53 +03:00
# endif
1994-05-13 10:01:27 +04:00
schednetisr ( NETISR_ISO ) ;
inq = & clnlintrq ;
break ;
}
goto dropanyway ;
2005-02-27 01:45:09 +03:00
1994-05-13 10:01:27 +04:00
case LLC_XID :
case LLC_XID_P :
2006-12-10 14:39:43 +03:00
if ( m - > m_len < LLC_XID_BASIC_MINLEN + sizeof ( struct ether_header ) )
2006-12-01 21:43:40 +03:00
/* XXX m_pullup? */
1994-05-13 10:01:27 +04:00
goto dropanyway ;
l - > llc_window = 0 ;
2006-12-10 14:39:43 +03:00
l - > llc_fid = LLC_XID_FORMAT_BASIC ;
l - > llc_class = LLC_XID_CLASS_I ;
1994-05-13 10:01:27 +04:00
l - > llc_dsap = l - > llc_ssap = 0 ;
/* Fall through to */
case LLC_TEST :
case LLC_TEST_P :
{
struct sockaddr sa ;
1998-04-26 10:17:20 +04:00
struct ether_header * eh2 ;
1994-05-13 10:01:27 +04:00
int i ;
u_char c = l - > llc_dsap ;
l - > llc_dsap = l - > llc_ssap ;
l - > llc_ssap = c ;
2006-12-01 21:43:40 +03:00
m_adj ( m , sizeof ( struct ether_header ) ) ;
/* XXX we can optimize here? */
1994-05-13 10:01:27 +04:00
if ( m - > m_flags & ( M_BCAST | M_MCAST ) )
2007-02-20 11:55:54 +03:00
memcpy ( eh - > ether_dhost ,
2007-08-27 02:59:08 +04:00
CLLADDR ( ifp - > if_sadl ) ,
2007-02-20 11:55:54 +03:00
ETHER_ADDR_LEN ) ;
1994-05-13 10:01:27 +04:00
sa . sa_family = AF_UNSPEC ;
sa . sa_len = sizeof ( sa ) ;
eh2 = ( struct ether_header * ) sa . sa_data ;
for ( i = 0 ; i < 6 ; i + + ) {
2005-02-27 01:45:09 +03:00
eh2 - > ether_shost [ i ] = c =
1997-03-15 21:09:08 +03:00
eh - > ether_dhost [ i ] ;
2005-02-27 01:45:09 +03:00
eh2 - > ether_dhost [ i ] =
1997-03-15 21:09:08 +03:00
eh - > ether_dhost [ i ] =
eh - > ether_shost [ i ] ;
1994-05-13 10:01:27 +04:00
eh - > ether_shost [ i ] = c ;
}
ifp - > if_output ( ifp , m , & sa , NULL ) ;
return ;
}
default :
m_freem ( m ) ;
1993-03-21 12:45:37 +03:00
return ;
1994-05-13 10:01:27 +04:00
}
1993-03-21 12:45:37 +03:00
break ;
1994-05-13 10:01:27 +04:00
# endif /* ISO */
2007-01-06 23:38:14 +03:00
# if defined (ISO) || defined (NETATALK)
1993-03-21 12:45:37 +03:00
dropanyway :
2007-01-06 23:38:14 +03:00
# endif
1993-03-21 12:45:37 +03:00
default :
1994-05-13 10:01:27 +04:00
m_freem ( m ) ;
return ;
}
2006-12-01 21:43:40 +03:00
# else /* ISO || LLC || NETATALK*/
m_freem ( m ) ;
return ;
1997-04-03 01:23:26 +04:00
# endif /* ISO || LLC || NETATALK*/
1993-03-21 12:45:37 +03:00
}
if ( IF_QFULL ( inq ) ) {
IF_DROP ( inq ) ;
m_freem ( m ) ;
} else
IF_ENQUEUE ( inq , m ) ;
}
/*
* Convert Ethernet address to printable ( loggable ) representation .
*/
char *
2000-06-18 00:57:20 +04:00
ether_sprintf ( const u_char * ap )
1993-03-21 12:45:37 +03:00
{
2006-03-16 18:57:59 +03:00
static char etherbuf [ 3 * ETHER_ADDR_LEN ] ;
return ether_snprintf ( etherbuf , sizeof ( etherbuf ) , ap ) ;
}
char *
ether_snprintf ( char * buf , size_t len , const u_char * ap )
{
char * cp = buf ;
size_t i ;
1993-03-21 12:45:37 +03:00
2006-03-16 18:57:59 +03:00
for ( i = 0 ; i < len / 3 ; i + + ) {
2005-05-17 08:14:57 +04:00
* cp + + = hexdigits [ * ap > > 4 ] ;
* cp + + = hexdigits [ * ap + + & 0xf ] ;
1993-03-21 12:45:37 +03:00
* cp + + = ' : ' ;
}
2006-03-16 18:57:59 +03:00
* - - cp = ' \0 ' ;
return buf ;
1993-03-21 12:45:37 +03:00
}
1994-05-13 10:01:27 +04:00
/*
* Perform common duties while attaching to interface list
*/
void
2008-02-20 20:05:52 +03:00
ether_ifattach ( struct ifnet * ifp , const uint8_t * lla )
1994-05-13 10:01:27 +04:00
{
2003-02-26 09:31:08 +03:00
struct ethercom * ec = ( struct ethercom * ) ifp ;
1994-05-13 10:01:27 +04:00
ifp - > if_type = IFT_ETHER ;
2002-04-27 06:38:47 +04:00
ifp - > if_hdrlen = ETHER_HDR_LEN ;
2000-12-18 22:44:33 +03:00
ifp - > if_dlt = DLT_EN10MB ;
1994-05-13 10:01:27 +04:00
ifp - > if_mtu = ETHERMTU ;
1995-04-08 02:19:29 +04:00
ifp - > if_output = ether_output ;
1999-05-19 03:52:51 +04:00
ifp - > if_input = ether_input ;
2000-03-07 00:03:46 +03:00
if ( ifp - > if_baudrate = = 0 )
ifp - > if_baudrate = IF_Mbps ( 10 ) ; /* just a default */
2001-01-17 03:30:49 +03:00
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
if_set_sadl ( ifp , lla , ETHER_ADDR_LEN , ! ETHER_IS_LOCAL ( lla ) ) ;
2001-01-17 03:30:49 +03:00
2003-02-26 09:31:08 +03:00
LIST_INIT ( & ec - > ec_multiaddrs ) ;
1997-10-02 23:41:56 +04:00
ifp - > if_broadcastaddr = etherbroadcastaddr ;
2010-04-05 11:19:28 +04:00
bpf_attach ( ifp , DLT_EN10MB , sizeof ( struct ether_header ) ) ;
2003-02-26 09:31:08 +03:00
# ifdef MBUFTRACE
2003-05-16 07:56:49 +04:00
strlcpy ( ec - > ec_tx_mowner . mo_name , ifp - > if_xname ,
sizeof ( ec - > ec_tx_mowner . mo_name ) ) ;
strlcpy ( ec - > ec_tx_mowner . mo_descr , " tx " ,
sizeof ( ec - > ec_tx_mowner . mo_descr ) ) ;
strlcpy ( ec - > ec_rx_mowner . mo_name , ifp - > if_xname ,
sizeof ( ec - > ec_rx_mowner . mo_name ) ) ;
strlcpy ( ec - > ec_rx_mowner . mo_descr , " rx " ,
sizeof ( ec - > ec_rx_mowner . mo_descr ) ) ;
2003-02-26 09:31:08 +03:00
MOWNER_ATTACH ( & ec - > ec_tx_mowner ) ;
MOWNER_ATTACH ( & ec - > ec_rx_mowner ) ;
ifp - > if_mowner = & ec - > ec_tx_mowner ;
# endif
1994-05-13 10:01:27 +04:00
}
2000-02-02 01:52:04 +03:00
void
2000-06-18 00:57:20 +04:00
ether_ifdetach ( struct ifnet * ifp )
2000-02-02 01:52:04 +03:00
{
2000-10-04 03:33:38 +04:00
struct ethercom * ec = ( void * ) ifp ;
struct ether_multi * enm ;
int s ;
2004-06-06 08:44:05 +04:00
# if NBRIDGE > 0
if ( ifp - > if_bridge )
bridge_ifdetach ( ifp ) ;
# endif
2010-04-05 11:19:28 +04:00
bpf_detach ( ifp ) ;
2000-11-15 04:02:11 +03:00
2000-10-04 03:50:52 +04:00
# if NVLAN > 0
if ( ec - > ec_nvlans )
vlan_ifdetach ( ifp ) ;
# endif
2001-04-14 03:29:55 +04:00
s = splnet ( ) ;
2000-10-04 03:33:38 +04:00
while ( ( enm = LIST_FIRST ( & ec - > ec_multiaddrs ) ) ! = NULL ) {
LIST_REMOVE ( enm , enm_list ) ;
2003-01-12 15:26:23 +03:00
free ( enm , M_IFMADDR ) ;
2000-10-04 03:33:38 +04:00
ec - > ec_multicnt - - ;
}
splx ( s ) ;
2000-02-02 01:52:04 +03:00
2003-05-23 14:06:17 +04:00
#if 0 /* done in if_detach() */
2001-01-17 03:30:49 +03:00
if_free_sadl ( ifp ) ;
2003-05-23 14:06:17 +04:00
# endif
2003-02-26 09:31:08 +03:00
MOWNER_DETACH ( & ec - > ec_rx_mowner ) ;
MOWNER_DETACH ( & ec - > ec_tx_mowner ) ;
2000-02-02 01:52:04 +03:00
}
2000-05-12 20:22:36 +04:00
#if 0
/*
* This is for reference . We have a table - driven version
* of the little - endian crc32 generator , which is faster
* than the double - loop .
*/
2008-02-20 20:05:52 +03:00
uint32_t
ether_crc32_le ( const uint8_t * buf , size_t len )
2000-03-06 23:54:41 +03:00
{
2008-02-20 20:05:52 +03:00
uint32_t c , crc , carry ;
2000-03-06 23:54:41 +03:00
size_t i , j ;
crc = 0xffffffffU ; /* initial value */
for ( i = 0 ; i < len ; i + + ) {
c = buf [ i ] ;
for ( j = 0 ; j < 8 ; j + + ) {
carry = ( ( crc & 0x01 ) ? 1 : 0 ) ^ ( c & 0x01 ) ;
crc > > = 1 ;
c > > = 1 ;
if ( carry )
2000-05-12 20:22:36 +04:00
crc = ( crc ^ ETHER_CRC_POLY_LE ) ;
2000-03-06 23:54:41 +03:00
}
}
return ( crc ) ;
}
2000-05-12 20:22:36 +04:00
# else
2008-02-20 20:05:52 +03:00
uint32_t
ether_crc32_le ( const uint8_t * buf , size_t len )
2000-05-12 20:22:36 +04:00
{
2008-02-20 20:05:52 +03:00
static const uint32_t crctab [ ] = {
2000-05-12 20:22:36 +04:00
0x00000000 , 0x1db71064 , 0x3b6e20c8 , 0x26d930ac ,
0x76dc4190 , 0x6b6b51f4 , 0x4db26158 , 0x5005713c ,
0xedb88320 , 0xf00f9344 , 0xd6d6a3e8 , 0xcb61b38c ,
0x9b64c2b0 , 0x86d3d2d4 , 0xa00ae278 , 0xbdbdf21c
} ;
2008-02-20 20:05:52 +03:00
uint32_t crc ;
2002-08-26 05:39:39 +04:00
size_t i ;
2000-05-12 20:22:36 +04:00
crc = 0xffffffffU ; /* initial value */
for ( i = 0 ; i < len ; i + + ) {
crc ^ = buf [ i ] ;
crc = ( crc > > 4 ) ^ crctab [ crc & 0xf ] ;
crc = ( crc > > 4 ) ^ crctab [ crc & 0xf ] ;
}
return ( crc ) ;
}
# endif
2000-03-06 23:54:41 +03:00
2008-02-20 20:05:52 +03:00
uint32_t
ether_crc32_be ( const uint8_t * buf , size_t len )
2000-03-06 23:54:41 +03:00
{
2008-02-20 20:05:52 +03:00
uint32_t c , crc , carry ;
2000-03-06 23:54:41 +03:00
size_t i , j ;
crc = 0xffffffffU ; /* initial value */
for ( i = 0 ; i < len ; i + + ) {
c = buf [ i ] ;
for ( j = 0 ; j < 8 ; j + + ) {
carry = ( ( crc & 0x80000000U ) ? 1 : 0 ) ^ ( c & 0x01 ) ;
crc < < = 1 ;
c > > = 1 ;
if ( carry )
crc = ( crc ^ ETHER_CRC_POLY_BE ) | carry ;
}
}
return ( crc ) ;
}
1999-09-16 00:48:19 +04:00
# ifdef INET
2005-01-08 06:18:18 +03:00
const uint8_t ether_ipmulticast_min [ ETHER_ADDR_LEN ] =
{ 0x01 , 0x00 , 0x5e , 0x00 , 0x00 , 0x00 } ;
const uint8_t ether_ipmulticast_max [ ETHER_ADDR_LEN ] =
{ 0x01 , 0x00 , 0x5e , 0x7f , 0xff , 0xff } ;
1999-09-16 00:48:19 +04:00
# endif
1999-07-01 12:12:45 +04:00
# ifdef INET6
2005-01-08 06:18:18 +03:00
const uint8_t ether_ip6multicast_min [ ETHER_ADDR_LEN ] =
{ 0x33 , 0x33 , 0x00 , 0x00 , 0x00 , 0x00 } ;
const uint8_t ether_ip6multicast_max [ ETHER_ADDR_LEN ] =
{ 0x33 , 0x33 , 0xff , 0xff , 0xff , 0xff } ;
1999-07-01 12:12:45 +04:00
# endif
2000-09-28 11:15:27 +04:00
2006-11-24 04:04:30 +03:00
/*
* ether_aton implementation , not using a static buffer .
*/
int
2010-05-20 00:41:59 +04:00
ether_aton_r ( u_char * dest , size_t len , const char * str )
2006-11-24 04:04:30 +03:00
{
2010-05-20 00:41:59 +04:00
const u_char * cp = ( const void * ) str ;
u_char * ep ;
2011-01-12 18:30:40 +03:00
# define atox(c) (((c) <= '9') ? ((c) - '0') : ((toupper(c) - 'A') + 10))
2010-05-20 00:41:59 +04:00
if ( len < ETHER_ADDR_LEN )
return ENOSPC ;
ep = dest + ETHER_ADDR_LEN ;
while ( * cp ) {
if ( ! isxdigit ( * cp ) )
return EINVAL ;
* dest = atox ( * cp ) ;
cp + + ;
if ( isxdigit ( * cp ) ) {
* dest = ( * dest < < 4 ) | atox ( * cp ) ;
dest + + ;
cp + + ;
} else
2010-05-20 00:43:51 +04:00
dest + + ;
2010-05-20 00:41:59 +04:00
if ( dest = = ep )
return * cp = = ' \0 ' ? 0 : ENAMETOOLONG ;
switch ( * cp ) {
case ' : ' :
case ' - ' :
case ' . ' :
2010-05-19 22:58:22 +04:00
cp + + ;
2010-05-20 00:41:59 +04:00
break ;
2010-05-19 22:58:22 +04:00
}
2010-05-20 00:41:59 +04:00
}
return ENOBUFS ;
2006-11-24 04:04:30 +03:00
}
1993-12-06 07:50:19 +03:00
/*
2000-09-28 11:15:27 +04:00
* Convert a sockaddr into an Ethernet address or range of Ethernet
* addresses .
1993-12-06 07:50:19 +03:00
*/
int
2008-02-20 20:05:52 +03:00
ether_multiaddr ( const struct sockaddr * sa , uint8_t addrlo [ ETHER_ADDR_LEN ] ,
uint8_t addrhi [ ETHER_ADDR_LEN ] )
1993-12-06 07:50:19 +03:00
{
1997-04-03 19:25:20 +04:00
# ifdef INET
2007-09-19 09:25:33 +04:00
const struct sockaddr_in * sin ;
1997-04-03 19:25:20 +04:00
# endif /* INET */
1999-07-01 12:12:45 +04:00
# ifdef INET6
2007-09-19 09:25:33 +04:00
const struct sockaddr_in6 * sin6 ;
1999-07-01 12:12:45 +04:00
# endif /* INET6 */
1993-12-06 07:50:19 +03:00
2000-09-28 11:15:27 +04:00
switch ( sa - > sa_family ) {
1993-12-06 07:50:19 +03:00
case AF_UNSPEC :
2007-02-20 11:55:54 +03:00
memcpy ( addrlo , sa - > sa_data , ETHER_ADDR_LEN ) ;
memcpy ( addrhi , addrlo , ETHER_ADDR_LEN ) ;
1993-12-06 07:50:19 +03:00
break ;
# ifdef INET
case AF_INET :
2007-09-19 09:25:33 +04:00
sin = satocsin ( sa ) ;
1993-12-06 07:50:19 +03:00
if ( sin - > sin_addr . s_addr = = INADDR_ANY ) {
/*
2000-09-28 11:15:27 +04:00
* An IP address of INADDR_ANY means listen to
* or stop listening to all of the Ethernet
* multicast addresses used for IP .
1993-12-06 07:50:19 +03:00
* ( This is for the sake of IP multicast routers . )
*/
2007-02-20 11:55:54 +03:00
memcpy ( addrlo , ether_ipmulticast_min , ETHER_ADDR_LEN ) ;
memcpy ( addrhi , ether_ipmulticast_max , ETHER_ADDR_LEN ) ;
1993-12-06 07:50:19 +03:00
}
else {
ETHER_MAP_IP_MULTICAST ( & sin - > sin_addr , addrlo ) ;
2007-02-20 11:55:54 +03:00
memcpy ( addrhi , addrlo , ETHER_ADDR_LEN ) ;
1993-12-06 07:50:19 +03:00
}
break ;
# endif
1999-07-01 12:12:45 +04:00
# ifdef INET6
case AF_INET6 :
2007-09-19 09:25:33 +04:00
sin6 = satocsin6 ( sa ) ;
1999-09-13 16:15:54 +04:00
if ( IN6_IS_ADDR_UNSPECIFIED ( & sin6 - > sin6_addr ) ) {
1999-07-01 12:12:45 +04:00
/*
2000-09-28 11:15:27 +04:00
* An IP6 address of 0 means listen to or stop
* listening to all of the Ethernet multicast
* address used for IP6 .
1999-07-01 12:12:45 +04:00
* ( This is used for multicast routers . )
*/
2007-02-20 11:55:54 +03:00
memcpy ( addrlo , ether_ip6multicast_min , ETHER_ADDR_LEN ) ;
memcpy ( addrhi , ether_ip6multicast_max , ETHER_ADDR_LEN ) ;
1999-07-01 12:12:45 +04:00
} else {
ETHER_MAP_IPV6_MULTICAST ( & sin6 - > sin6_addr , addrlo ) ;
2007-02-20 11:55:54 +03:00
memcpy ( addrhi , addrlo , ETHER_ADDR_LEN ) ;
1999-07-01 12:12:45 +04:00
}
break ;
# endif
1993-12-06 07:50:19 +03:00
default :
2007-02-20 11:55:54 +03:00
return EAFNOSUPPORT ;
1993-12-06 07:50:19 +03:00
}
2007-02-20 11:55:54 +03:00
return 0 ;
2000-09-28 11:15:27 +04:00
}
/*
* Add an Ethernet multicast address or range of addresses to the list for a
* given interface .
*/
int
2007-09-19 09:25:33 +04:00
ether_addmulti ( const struct sockaddr * sa , struct ethercom * ec )
2000-09-28 11:15:27 +04:00
{
struct ether_multi * enm ;
u_char addrlo [ ETHER_ADDR_LEN ] ;
u_char addrhi [ ETHER_ADDR_LEN ] ;
2001-04-14 03:29:55 +04:00
int s = splnet ( ) , error ;
2000-09-28 11:15:27 +04:00
2007-09-19 09:25:33 +04:00
error = ether_multiaddr ( sa , addrlo , addrhi ) ;
2000-09-28 11:15:27 +04:00
if ( error ! = 0 ) {
splx ( s ) ;
2007-02-20 11:55:54 +03:00
return error ;
2000-09-28 11:15:27 +04:00
}
1993-12-06 07:50:19 +03:00
/*
* Verify that we have valid Ethernet multicast addresses .
*/
2011-04-26 02:14:45 +04:00
if ( ! ETHER_IS_MULTICAST ( addrlo ) | | ! ETHER_IS_MULTICAST ( addrhi ) ) {
1993-12-06 07:50:19 +03:00
splx ( s ) ;
2007-02-20 11:55:54 +03:00
return EINVAL ;
1993-12-06 07:50:19 +03:00
}
/*
* See if the address range is already in the list .
*/
1997-03-15 21:09:08 +03:00
ETHER_LOOKUP_MULTI ( addrlo , addrhi , ec , enm ) ;
1993-12-06 07:50:19 +03:00
if ( enm ! = NULL ) {
/*
* Found it ; just increment the reference count .
*/
+ + enm - > enm_refcount ;
splx ( s ) ;
2007-02-20 11:55:54 +03:00
return 0 ;
1993-12-06 07:50:19 +03:00
}
/*
* New address or range ; malloc a new multicast record
* and link it into the interface ' s multicast list .
*/
enm = ( struct ether_multi * ) malloc ( sizeof ( * enm ) , M_IFMADDR , M_NOWAIT ) ;
if ( enm = = NULL ) {
splx ( s ) ;
2007-02-20 11:55:54 +03:00
return ENOBUFS ;
1993-12-06 07:50:19 +03:00
}
2007-02-20 11:55:54 +03:00
memcpy ( enm - > enm_addrlo , addrlo , 6 ) ;
memcpy ( enm - > enm_addrhi , addrhi , 6 ) ;
1993-12-06 07:50:19 +03:00
enm - > enm_refcount = 1 ;
1997-03-15 21:09:08 +03:00
LIST_INSERT_HEAD ( & ec - > ec_multiaddrs , enm , enm_list ) ;
ec - > ec_multicnt + + ;
1993-12-06 07:50:19 +03:00
splx ( s ) ;
/*
* Return ENETRESET to inform the driver that the list has changed
* and its reception filter should be adjusted accordingly .
*/
2007-02-20 11:55:54 +03:00
return ENETRESET ;
1993-12-06 07:50:19 +03:00
}
/*
* Delete a multicast address record .
*/
int
2007-09-19 09:25:33 +04:00
ether_delmulti ( const struct sockaddr * sa , struct ethercom * ec )
1993-12-06 07:50:19 +03:00
{
1998-04-26 10:17:20 +04:00
struct ether_multi * enm ;
2000-09-28 11:15:27 +04:00
u_char addrlo [ ETHER_ADDR_LEN ] ;
u_char addrhi [ ETHER_ADDR_LEN ] ;
2001-04-14 03:29:55 +04:00
int s = splnet ( ) , error ;
1993-12-06 07:50:19 +03:00
2007-09-19 09:25:33 +04:00
error = ether_multiaddr ( sa , addrlo , addrhi ) ;
2000-09-28 11:15:27 +04:00
if ( error ! = 0 ) {
1993-12-06 07:50:19 +03:00
splx ( s ) ;
2000-09-28 11:15:27 +04:00
return ( error ) ;
1993-12-06 07:50:19 +03:00
}
/*
2000-10-11 20:53:41 +04:00
* Look ur the address in our list .
1993-12-06 07:50:19 +03:00
*/
1997-03-15 21:09:08 +03:00
ETHER_LOOKUP_MULTI ( addrlo , addrhi , ec , enm ) ;
1993-12-06 07:50:19 +03:00
if ( enm = = NULL ) {
splx ( s ) ;
return ( ENXIO ) ;
}
if ( - - enm - > enm_refcount ! = 0 ) {
/*
* Still some claims to this record .
*/
splx ( s ) ;
return ( 0 ) ;
}
/*
* No remaining claims to this record ; unlink and free it .
*/
1995-06-12 04:46:47 +04:00
LIST_REMOVE ( enm , enm_list ) ;
1993-12-06 07:50:19 +03:00
free ( enm , M_IFMADDR ) ;
1997-03-15 21:09:08 +03:00
ec - > ec_multicnt - - ;
1993-12-06 07:50:19 +03:00
splx ( s ) ;
/*
* Return ENETRESET to inform the driver that the list has changed
* and its reception filter should be adjusted accordingly .
*/
return ( ENETRESET ) ;
}
2000-10-11 20:53:41 +04:00
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
void
ether_set_ifflags_cb ( struct ethercom * ec , ether_cb_t cb )
{
ec - > ec_ifflags_cb = cb ;
}
2000-10-11 20:53:41 +04:00
/*
* Common ioctls for Ethernet interfaces . Note , we must be
* called at splnet ( ) .
*/
int
2007-03-04 08:59:00 +03:00
ether_ioctl ( struct ifnet * ifp , u_long cmd , void * data )
2000-10-11 20:53:41 +04:00
{
struct ethercom * ec = ( void * ) ifp ;
struct ifreq * ifr = ( struct ifreq * ) data ;
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
struct if_laddrreq * iflr = data ;
const struct sockaddr_dl * sdl ;
static const uint8_t zero [ ETHER_ADDR_LEN ] ;
2008-07-23 10:34:31 +04:00
int error ;
2000-10-11 20:53:41 +04:00
switch ( cmd ) {
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
case SIOCINITIFADDR :
if ( ( ifp - > if_flags & ( IFF_UP | IFF_RUNNING ) ) ! =
( IFF_UP | IFF_RUNNING ) ) {
ifp - > if_flags | = IFF_UP ;
if ( ( error = ( * ifp - > if_init ) ( ifp ) ) ! = 0 )
2008-07-23 10:34:31 +04:00
return error ;
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
}
# ifdef INET
2009-04-29 01:26:51 +04:00
{
struct ifaddr * ifa = ( struct ifaddr * ) data ;
if ( ifa - > ifa_addr - > sa_family = = AF_INET )
arp_ifinit ( ifp , ifa ) ;
}
2000-10-11 20:53:41 +04:00
# endif /* INET */
2008-07-23 10:34:31 +04:00
return 0 ;
2000-10-11 20:53:41 +04:00
case SIOCSIFMTU :
2001-06-03 07:07:39 +04:00
{
int maxmtu ;
if ( ec - > ec_capabilities & ETHERCAP_JUMBO_MTU )
maxmtu = ETHERMTU_JUMBO ;
else
maxmtu = ETHERMTU ;
if ( ifr - > ifr_mtu < ETHERMIN | | ifr - > ifr_mtu > maxmtu )
2008-07-23 10:34:31 +04:00
return EINVAL ;
else if ( ( error = ifioctl_common ( ifp , cmd , data ) ) ! = ENETRESET )
return error ;
else if ( ifp - > if_flags & IFF_UP ) {
2001-07-25 07:18:46 +04:00
/* Make sure the device notices the MTU change. */
2008-07-23 10:34:31 +04:00
return ( * ifp - > if_init ) ( ifp ) ;
} else
return 0 ;
2001-06-03 07:07:39 +04:00
}
2000-10-11 20:53:41 +04:00
case SIOCSIFFLAGS :
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
if ( ( error = ifioctl_common ( ifp , cmd , data ) ) ! = 0 )
return error ;
2008-07-23 10:34:31 +04:00
switch ( ifp - > if_flags & ( IFF_UP | IFF_RUNNING ) ) {
case IFF_RUNNING :
2000-10-11 20:53:41 +04:00
/*
* If interface is marked down and it is running ,
* then stop and disable it .
*/
( * ifp - > if_stop ) ( ifp , 1 ) ;
2008-07-23 10:34:31 +04:00
break ;
case IFF_UP :
2000-10-11 20:53:41 +04:00
/*
* If interface is marked up and it is stopped , then
* start it .
*/
2008-07-23 10:34:31 +04:00
return ( * ifp - > if_init ) ( ifp ) ;
case IFF_UP | IFF_RUNNING :
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
error = 0 ;
if ( ec - > ec_ifflags_cb = = NULL | |
( error = ( * ec - > ec_ifflags_cb ) ( ec ) ) = = ENETRESET ) {
/*
* Reset the interface to pick up
* changes in any other flags that
* affect the hardware state .
*/
return ( * ifp - > if_init ) ( ifp ) ;
} else
return error ;
2008-07-23 10:34:31 +04:00
case 0 :
break ;
2000-10-11 20:53:41 +04:00
}
2008-07-23 10:34:31 +04:00
return 0 ;
2000-10-11 20:53:41 +04:00
case SIOCADDMULTI :
2008-07-23 10:34:31 +04:00
return ether_addmulti ( ifreq_getaddr ( cmd , ifr ) , ec ) ;
2000-10-11 20:53:41 +04:00
case SIOCDELMULTI :
2008-07-23 10:34:31 +04:00
return ether_delmulti ( ifreq_getaddr ( cmd , ifr ) , ec ) ;
2008-01-19 23:11:52 +03:00
case SIOCSIFMEDIA :
case SIOCGIFMEDIA :
if ( ec - > ec_mii = = NULL )
2008-07-23 10:34:31 +04:00
return ENOTTY ;
return ifmedia_ioctl ( ifp , ifr , & ec - > ec_mii - > mii_media , cmd ) ;
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
case SIOCALIFADDR :
sdl = satocsdl ( sstocsa ( & iflr - > addr ) ) ;
if ( sdl - > sdl_family ! = AF_LINK )
;
else if ( ETHER_IS_MULTICAST ( CLLADDR ( sdl ) ) )
return EINVAL ;
else if ( memcmp ( zero , CLLADDR ( sdl ) , sizeof ( zero ) ) = = 0 )
return EINVAL ;
/*FALLTHROUGH*/
2000-10-11 20:53:41 +04:00
default :
*** Summary ***
When a link-layer address changes (e.g., ifconfig ex0 link
02:de:ad:be:ef:02 active), send a gratuitous ARP and/or a Neighbor
Advertisement to update the network-/link-layer address bindings
on our LAN peers.
Refuse a change of ethernet address to the address 00:00:00:00:00:00
or to any multicast/broadcast address. (Thanks matt@.)
Reorder ifnet ioctl operations so that driver ioctls may inherit
the functions of their "class"---ether_ioctl(), fddi_ioctl(), et
cetera---and the class ioctls may inherit from the generic ioctl,
ifioctl_common(), but both driver- and class-ioctls may override
the generic behavior. Make network drivers share more code.
Distinguish a "factory" link-layer address from others for the
purposes of both protecting that address from deletion and computing
EUI64.
Return consistent, appropriate error codes from network drivers.
Improve readability. KNF.
*** Details ***
In if_attach(), always initialize the interface ioctl routine,
ifnet->if_ioctl, if the driver has not already initialized it.
Delete if_ioctl == NULL tests everywhere else, because it cannot
happen.
In the ioctl routines of network interfaces, inherit common ioctl
behaviors by calling either ifioctl_common() or whichever ioctl
routine is appropriate for the class of interface---e.g., ether_ioctl()
for ethernets.
Stop (ab)using SIOCSIFADDR and start to use SIOCINITIFADDR. In
the user->kernel interface, SIOCSIFADDR's argument was an ifreq,
but on the protocol->ifnet interface, SIOCSIFADDR's argument was
an ifaddr. That was confusing, and it would work against me as I
make it possible for a network interface to overload most ioctls.
On the protocol->ifnet interface, replace SIOCSIFADDR with
SIOCINITIFADDR. In ifioctl(), return EPERM if userland tries to
invoke SIOCINITIFADDR.
In ifioctl(), give the interface the first shot at handling most
interface ioctls, and give the protocol the second shot, instead
of the other way around. Finally, let compatibility code (COMPAT_OSOCK)
take a shot.
Pull device initialization out of switch statements under
SIOCINITIFADDR. For example, pull ..._init() out of any switch
statement that looks like this:
switch (...->sa_family) {
case ...:
..._init();
...
break;
...
default:
..._init();
...
break;
}
Rewrite many if-else clauses that handle all permutations of IFF_UP
and IFF_RUNNING to use a switch statement,
switch (x & (IFF_UP|IFF_RUNNING)) {
case 0:
...
break;
case IFF_RUNNING:
...
break;
case IFF_UP:
...
break;
case IFF_UP|IFF_RUNNING:
...
break;
}
unifdef lots of code containing #ifdef FreeBSD, #ifdef NetBSD, and
#ifdef SIOCSIFMTU, especially in fwip(4) and in ndis(4).
In ipw(4), remove an if_set_sadl() call that is out of place.
In nfe(4), reuse the jumbo MTU logic in ether_ioctl().
Let ethernets register a callback for setting h/w state such as
promiscuous mode and the multicast filter in accord with a change
in the if_flags: ether_set_ifflags_cb() registers a callback that
returns ENETRESET if the caller should reset the ethernet by calling
if_init(), 0 on success, != 0 on failure. Pull common code from
ex(4), gem(4), nfe(4), sip(4), tlp(4), vge(4) into ether_ioctl(),
and register if_flags callbacks for those drivers.
Return ENOTTY instead of EINVAL for inappropriate ioctls. In
zyd(4), use ENXIO instead of ENOTTY to indicate that the device is
not any longer attached.
Add to if_set_sadl() a boolean 'factory' argument that indicates
whether a link-layer address was assigned by the factory or some
other source. In a comment, recommend using the factory address
for generating an EUI64, and update in6_get_hw_ifid() to prefer a
factory address to any other link-layer address.
Add a routing message, RTM_LLINFO_UPD, that tells protocols to
update the binding of network-layer addresses to link-layer addresses.
Implement this message in IPv4 and IPv6 by sending a gratuitous
ARP or a neighbor advertisement, respectively. Generate RTM_LLINFO_UPD
messages on a change of an interface's link-layer address.
In ether_ioctl(), do not let SIOCALIFADDR set a link-layer address
that is broadcast/multicast or equal to 00:00:00:00:00:00.
Make ether_ioctl() call ifioctl_common() to handle ioctls that it
does not understand.
In gif(4), initialize if_softc and use it, instead of assuming that
the gif_softc and ifp overlap.
Let ifioctl_common() handle SIOCGIFADDR.
Sprinkle rtcache_invariants(), which checks on DIAGNOSTIC kernels
that certain invariants on a struct route are satisfied.
In agr(4), rewrite agr_ioctl_filter() to be a bit more explicit
about the ioctls that we do not allow on an agr(4) member interface.
bzero -> memset. Delete unnecessary casts to void *. Use
sockaddr_in_init() and sockaddr_in6_init(). Compare pointers with
NULL instead of "testing truth". Replace some instances of (type
*)0 with NULL. Change some K&R prototypes to ANSI C, and join
lines.
2008-11-07 03:20:01 +03:00
return ifioctl_common ( ifp , cmd , data ) ;
2000-10-11 20:53:41 +04:00
}
2008-07-23 10:34:31 +04:00
return 0 ;
2000-10-11 20:53:41 +04:00
}