2003-10-30 04:43:08 +03:00
/* $NetBSD: if_ethersubr.c,v 1.114 2003/10/30 01:43:08 simonb Exp $ */
1999-07-01 12:12:45 +04:00
/*
* Copyright ( C ) 1995 , 1996 , 1997 , and 1998 WIDE Project .
* All rights reserved .
*
* 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 .
*
* 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>
2003-10-30 04:43:08 +03:00
__KERNEL_RCSID ( 0 , " $NetBSD: if_ethersubr.c,v 1.114 2003/10/30 01:43:08 simonb 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 06:12:22 +04:00
# include "opt_ccitt.h"
1998-07-05 07:14:41 +04:00
# include "opt_llc.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"
1998-07-05 10:49:00 +04:00
# include "opt_ns.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"
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"
2000-11-15 04:02:11 +03:00
# include "bpfilter.h"
2002-04-07 11:05:37 +04:00
# include "arp.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>
1993-03-21 12:45:37 +03:00
1994-05-13 10:01:27 +04:00
# include <machine/cpu.h>
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
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
# if NBPFILTER > 0
# include <net/bpf.h>
# endif
1997-03-15 21:09:08 +03:00
# include <net/if_ether.h>
2000-09-28 02:58:21 +04:00
# if NVLAN > 0
# include <net/if_vlanvar.h>
# endif
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
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
# ifdef NS
1993-12-17 03:10:06 +03:00
# include <netns/ns.h>
# include <netns/ns_if.h>
1993-03-21 12:45:37 +03:00
# 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
# ifdef LLC
# include <netccitt/dll.h>
# include <netccitt/llc_var.h>
# endif
# if defined(LLC) && defined(CCITT)
extern struct ifqueue pkintrq ;
# endif
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 */
1993-03-21 12:45:37 +03:00
u_char etherbroadcastaddr [ 6 ] = { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ;
1994-05-13 10:01:27 +04:00
# define senderr(e) { error = (e); goto bad;}
1993-03-21 12:45:37 +03:00
1997-03-15 21:09:08 +03:00
# define SIN(x) ((struct sockaddr_in *)x)
1999-05-19 03:52:51 +04:00
static int ether_output __P ( ( struct ifnet * , struct mbuf * ,
struct sockaddr * , struct rtentry * ) ) ;
static void ether_input __P ( ( struct ifnet * , struct mbuf * ) ) ;
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
2000-06-18 00:57:20 +04:00
ether_output ( struct ifnet * ifp , struct mbuf * m0 , struct sockaddr * dst ,
struct rtentry * rt0 )
1993-03-21 12:45:37 +03:00
{
1999-09-22 02:18:51 +04:00
u_int16_t etype = 0 ;
2000-12-14 01:07:50 +03:00
int s , len , error = 0 , hdrcmplt = 0 ;
1998-04-30 04:05:41 +04:00
u_char esrc [ 6 ] , edst [ 6 ] ;
1998-04-26 10:17:20 +04:00
struct mbuf * m = m0 ;
struct rtentry * rt ;
1993-03-21 12:45:37 +03:00
struct mbuf * mcopy = ( struct mbuf * ) 0 ;
1998-04-26 10:17:20 +04:00
struct ether_header * eh ;
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 */
2000-12-14 01:07:50 +03:00
short mflags ;
1993-03-21 12:45:37 +03:00
2003-02-26 09:31:08 +03:00
# ifdef MBUFTRACE
m_claim ( m , ifp - > if_mowner ) ;
# endif
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 ) ;
} 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 ) {
1994-05-13 10:01:27 +04:00
if ( rt - > rt_gwroute = = 0 )
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 ) ;
if ( ( rt = rt - > rt_gwroute ) = = 0 )
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 - - ;
rt0 - > rt_gwroute = 0 ;
senderr ( EHOSTUNREACH ) ;
}
1994-05-13 10:01:27 +04:00
}
}
if ( rt - > rt_flags & RTF_REJECT )
if ( rt - > rt_rmx . rmx_expire = = 0 | |
2002-08-26 05:39:39 +04:00
( u_long ) time . tv_sec < 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 )
bcopy ( ( caddr_t ) etherbroadcastaddr , ( caddr_t ) edst ,
sizeof ( edst ) ) ;
else if ( m - > m_flags & M_MCAST ) {
ETHER_MAP_IP_MULTICAST ( & SIN ( dst ) - > sin_addr ,
( caddr_t ) 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 )
bcopy ( ( caddr_t ) etherbroadcastaddr , ( caddr_t ) edst ,
sizeof ( edst ) ) ;
else
bcopy ( ( caddr_t ) ar_tha ( ah ) ,
( caddr_t ) edst , sizeof ( edst ) ) ;
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 :
1999-12-13 18:17:17 +03:00
if ( ! nd6_storelladdr ( ifp , rt , m , dst , ( u_char * ) 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 :
if ( ! aarpresolve ( ifp , m , ( struct sockaddr_at * ) dst , edst ) ) {
# ifdef NETATALKDEBUG
printf ( " aarpresolv failed \n " ) ;
# endif /* NETATALKDEBUG */
return ( 0 ) ;
}
/*
* ifaddr is the first thing in at_ifaddr
*/
aa = ( struct at_ifaddr * ) at_ifawithnet (
1997-04-03 22:48:28 +04:00
( struct sockaddr_at * ) dst , ifp ) ;
1997-04-03 01:23:26 +04:00
if ( aa = = NULL )
goto bad ;
/*
* 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 ;
bcopy ( at_org_code , llc . llc_snap_org_code ,
sizeof ( llc . llc_snap_org_code ) ) ;
1998-10-13 06:34:31 +04:00
llc . llc_snap_ether_type = htons ( ETHERTYPE_ATALK ) ;
1997-04-03 01:23:26 +04:00
bcopy ( & llc , mtod ( m , caddr_t ) , sizeof ( struct llc ) ) ;
} else {
1998-10-13 06:34:31 +04:00
etype = htons ( ETHERTYPE_ATALK ) ;
1997-04-03 01:23:26 +04:00
}
break ;
# endif /* NETATALK */
1993-03-21 12:45:37 +03:00
# ifdef NS
case AF_NS :
1995-12-24 06:33:43 +03:00
etype = htons ( ETHERTYPE_NS ) ;
1993-03-21 12:45:37 +03:00
bcopy ( ( caddr_t ) & ( ( ( struct sockaddr_ns * ) dst ) - > sns_addr . x_host ) ,
( caddr_t ) edst , sizeof ( edst ) ) ;
if ( ! bcmp ( ( caddr_t ) edst , ( caddr_t ) & ns_thishost , sizeof ( edst ) ) )
return ( looutput ( ifp , m , dst , rt ) ) ;
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 ) ;
1994-05-13 10:01:27 +04:00
break ;
1993-03-21 12:45:37 +03:00
# endif
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 ) ;
bcopy ( ( caddr_t ) & ( ( ( struct sockaddr_ipx * ) dst ) - > sipx_addr . x_host ) ,
1998-05-04 16:54:22 +04:00
( caddr_t ) edst , sizeof ( edst ) ) ;
/* 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 ;
1998-04-26 10:17:20 +04:00
struct sockaddr_dl * sdl ;
1993-03-21 12:45:37 +03:00
1994-05-13 10:01:27 +04:00
if ( rt & & ( sdl = ( struct sockaddr_dl * ) rt - > rt_gateway ) & &
sdl - > sdl_family = = AF_LINK & & sdl - > sdl_alen > 0 ) {
bcopy ( LLADDR ( sdl ) , ( caddr_t ) edst , sizeof ( edst ) ) ;
1996-02-14 00:59:53 +03:00
} else {
error = iso_snparesolve ( ifp , ( struct sockaddr_iso * ) dst ,
( 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 * ) ;
bcopy ( ( caddr_t ) edst ,
( caddr_t ) eh - > ether_dhost , sizeof ( edst ) ) ;
1997-03-15 21:09:08 +03:00
bcopy ( LLADDR ( ifp - > if_sadl ) ,
1993-03-21 12:45:37 +03:00
( caddr_t ) eh - > ether_shost , sizeof ( edst ) ) ;
}
}
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 */
# ifdef LLC
/* case AF_NSAP: */
case AF_CCITT : {
1998-04-26 10:17:20 +04:00
struct sockaddr_dl * sdl =
1994-05-13 10:01:27 +04:00
( struct sockaddr_dl * ) rt - > rt_gateway ;
if ( sdl & & sdl - > sdl_family = = AF_LINK
& & sdl - > sdl_alen > 0 ) {
bcopy ( LLADDR ( sdl ) , ( char * ) edst ,
sizeof ( edst ) ) ;
} else goto bad ; /* Not a link interface ? Funny ... */
if ( ( ifp - > if_flags & IFF_SIMPLEX ) & & ( * edst & 1 ) & &
( mcopy = m_copy ( m , 0 , ( int ) M_COPYALL ) ) ) {
M_PREPEND ( mcopy , sizeof ( * eh ) , M_DONTWAIT ) ;
if ( mcopy ) {
eh = mtod ( mcopy , struct ether_header * ) ;
bcopy ( ( caddr_t ) edst ,
( caddr_t ) eh - > ether_dhost , sizeof ( edst ) ) ;
1997-03-15 21:09:08 +03:00
bcopy ( LLADDR ( ifp - > if_sadl ) ,
1994-05-13 10:01:27 +04:00
( caddr_t ) eh - > ether_shost , sizeof ( edst ) ) ;
}
1993-12-06 07:50:19 +03:00
}
1994-05-13 10:01:27 +04:00
# ifdef LLC_DEBUG
{
int i ;
1998-04-26 10:17:20 +04:00
struct llc * l = mtod ( m , struct llc * ) ;
1994-05-13 10:01:27 +04:00
1996-10-13 06:10:01 +04:00
printf ( " ether_output: sending LLC2 pkt to: " ) ;
1994-05-13 10:01:27 +04:00
for ( i = 0 ; i < 6 ; i + + )
1996-10-13 06:10:01 +04:00
printf ( " %x " , edst [ i ] & 0xff ) ;
printf ( " len 0x%x dsap 0x%x ssap 0x%x control 0x%x \n " ,
1995-12-24 06:33:43 +03:00
m - > m_pkthdr . len , l - > llc_dsap & 0xff , l - > llc_ssap & 0xff ,
l - > llc_control & 0xff ) ;
1994-05-13 10:01:27 +04:00
}
# endif /* LLC_DEBUG */
} break ;
# endif /* LLC */
1993-03-21 12:45:37 +03:00
1998-04-30 04:05:41 +04:00
case pseudo_AF_HDRCMPLT :
hdrcmplt = 1 ;
eh = ( struct ether_header * ) dst - > sa_data ;
bcopy ( ( caddr_t ) eh - > ether_shost , ( caddr_t ) esrc , sizeof ( esrc ) ) ;
/* FALLTHROUGH */
1993-03-21 12:45:37 +03:00
case AF_UNSPEC :
eh = ( struct ether_header * ) dst - > sa_data ;
bcopy ( ( caddr_t ) eh - > ether_dhost , ( caddr_t ) edst , sizeof ( edst ) ) ;
1994-05-13 10:01:27 +04:00
/* AF_UNSPEC doesn't swap the byte order of the ether_type. */
1995-12-24 06:33:43 +03:00
etype = eh - > 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
}
if ( mcopy )
( 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. */
# ifdef __NO_STRICT_ALIGNMENT
2002-08-20 07:32:08 +04:00
eh - > ether_type = etype ;
2002-08-19 22:58:50 +04:00
# else
{
uint8_t * dstp = ( uint8_t * ) & eh - > ether_type ;
# if BYTE_ORDER == BIG_ENDIAN
dstp [ 0 ] = etype > > 8 ;
dstp [ 1 ] = etype ;
# else
dstp [ 0 ] = etype ;
dstp [ 1 ] = etype > > 8 ;
# endif /* BYTE_ORDER == BIG_ENDIAN */
}
# endif /* __NO_STRICT_ALIGNMENT */
1993-03-21 12:45:37 +03:00
bcopy ( ( caddr_t ) edst , ( caddr_t ) eh - > ether_dhost , sizeof ( edst ) ) ;
1998-04-30 04:05:41 +04:00
if ( hdrcmplt )
bcopy ( ( caddr_t ) esrc , ( caddr_t ) eh - > ether_shost ,
sizeof ( eh - > ether_shost ) ) ;
else
bcopy ( LLADDR ( ifp - > if_sadl ) , ( caddr_t ) eh - > ether_shost ,
sizeof ( eh - > ether_shost ) ) ;
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
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
2000-12-14 01:07:50 +03:00
mflags = m - > m_flags ;
len = m - > m_pkthdr . len ;
2001-04-14 03:29:55 +04:00
s = splnet ( ) ;
1993-03-21 12:45:37 +03:00
/*
* Queue message on interface , and start output if interface
* not yet active .
*/
2000-12-14 01:07:50 +03:00
IFQ_ENQUEUE ( & ifp - > if_snd , m , & pktattr , error ) ;
if ( error ) {
/* mbuf is already freed */
1993-03-21 12:45:37 +03:00
splx ( s ) ;
2000-12-14 01:07:50 +03:00
return ( error ) ;
1993-03-21 12:45:37 +03:00
}
2000-12-14 01:07:50 +03:00
ifp - > if_obytes + = len ;
if ( mflags & M_MCAST )
2000-06-14 09:10:27 +04:00
ifp - > if_omcasts + + ;
1993-03-21 12:45:37 +03:00
if ( ( ifp - > if_flags & IFF_OACTIVE ) = = 0 )
( * ifp - > if_start ) ( ifp ) ;
splx ( s ) ;
return ( error ) ;
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 ;
u_int16_t ether_type ;
int hlen , af , hdrsize ;
caddr_t hdr ;
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 ;
hdr = mtod ( m , caddr_t ) ;
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
*/
1999-05-19 03:52:51 +04:00
static 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 ;
1995-03-08 05:56:49 +03:00
u_int16_t etype ;
1993-03-21 12:45:37 +03:00
int s ;
1999-05-19 03:52:51 +04:00
struct ether_header * eh ;
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
m_claim ( m , & ec - > ec_rx_mowner ) ;
# 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 ) ;
/*
* Determine if the packet is within its size limits .
*/
2001-06-03 07:24:23 +04:00
if ( m - > m_pkthdr . len >
ETHER_MAX_FRAME ( ifp , etype , m - > m_flags & M_HASFCS ) ) {
2000-10-15 23:49:55 +04:00
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 & &
memcmp ( LLADDR ( ifp - > if_sadl ) , eh - > ether_shost ,
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 ) {
2003-03-25 16:29:39 +03:00
/* clear M_PROMISC, in case the packets comes from a vlan */
m - > m_flags & = ~ M_PROMISC ;
2001-04-11 07:47:24 +04:00
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 ;
2003-03-25 16:29:39 +03:00
} else
2001-04-11 07:47:24 +04:00
# endif /* NBRIDGE > 0 */
2003-03-25 16:29:39 +03:00
{
if ( ( m - > m_flags & ( M_BCAST | M_MCAST ) ) = = 0 & &
( ifp - > if_flags & IFF_PROMISC ) ! = 0 & &
memcmp ( LLADDR ( ifp - > if_sadl ) , eh - > ether_dhost ,
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 ) ;
}
2001-04-11 07:47:24 +04:00
# endif
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 ) {
# if NVLAN > 0
case ETHERTYPE_VLAN :
/*
* 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
m_freem ( m ) ;
2000-09-28 02:58:21 +04:00
return ;
# endif /* NVLAN > 0 */
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
2001-04-29 13:50:36 +04:00
if ( etype = = ETHERTYPE_PPPOEDISC )
inq = & ppoediscinq ;
else
inq = & ppoeinq ;
s = splnet ( ) ;
if ( IF_QFULL ( inq ) ) {
IF_DROP ( inq ) ;
m_freem ( m ) ;
} else
IF_ENQUEUE ( inq , m ) ;
splx ( s ) ;
# ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
2003-02-04 02:50:59 +03:00
if ( ! callout_pending ( & pppoe_softintr ) )
2001-04-29 13:50:36 +04:00
callout_reset ( & pppoe_softintr , 1 , pppoe_softintr_handler , NULL ) ;
# else
softintr_schedule ( pppoe_softintr ) ;
# endif
return ;
# endif /* NPPPOE > 0 */
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-05-19 03:52:51 +04:00
/* Strip off the Ethernet header. */
m_adj ( m , sizeof ( struct ether_header ) ) ;
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
1994-01-24 02:41:14 +03:00
switch ( etype ) {
1993-03-21 12:45:37 +03:00
# ifdef INET
case ETHERTYPE_IP :
1998-04-30 01:37:52 +04:00
# ifdef GATEWAY
if ( ipflow_fastforward ( m ) )
return ;
# endif
1993-03-21 12:45:37 +03:00
schednetisr ( NETISR_IP ) ;
inq = & ipintrq ;
break ;
case ETHERTYPE_ARP :
1994-05-13 10:01:27 +04:00
schednetisr ( NETISR_ARP ) ;
inq = & arpintrq ;
break ;
1994-04-18 10:18:05 +04:00
case ETHERTYPE_REVARP :
1994-05-13 10:01:27 +04:00
revarpinput ( m ) ; /* XXX queue? */
1994-04-18 10:18:05 +04:00
return ;
1993-03-21 12:45:37 +03:00
# endif
1999-07-01 12:12:45 +04:00
# ifdef INET6
case ETHERTYPE_IPV6 :
schednetisr ( NETISR_IPV6 ) ;
inq = & ip6intrq ;
break ;
# endif
1993-03-21 12:45:37 +03:00
# ifdef NS
case ETHERTYPE_NS :
schednetisr ( NETISR_NS ) ;
inq = & nsintrq ;
break ;
# endif
1998-05-04 16:54:22 +04:00
# ifdef IPX
case ETHERTYPE_IPX :
schednetisr ( NETISR_IPX ) ;
inq = & ipxintrq ;
break ;
# endif
1997-04-03 01:23:26 +04:00
# ifdef NETATALK
1998-10-13 06:34:31 +04:00
case ETHERTYPE_ATALK :
1997-04-03 01:23:26 +04:00
schednetisr ( NETISR_ATALK ) ;
inq = & atintrq1 ;
break ;
case ETHERTYPE_AARP :
/* probably this should be done with a NETISR as well */
aarpinput ( ifp , m ) ; /* XXX */
return ;
# endif /* NETATALK */
1993-03-21 12:45:37 +03:00
default :
1997-04-03 01:23:26 +04:00
# if defined (ISO) || defined (LLC) || defined (NETATALK)
1995-04-06 01:38:50 +04:00
if ( etype > ETHERMTU )
1993-03-21 12:45:37 +03:00
goto dropanyway ;
l = mtod ( m , struct llc * ) ;
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 ;
}
if ( Bcmp ( & ( l - > llc_snap_org_code ) [ 0 ] ,
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 ;
m_adj ( m , sizeof ( struct llc ) ) ;
schednetisr ( NETISR_ATALK ) ;
break ;
}
if ( Bcmp ( & ( l - > llc_snap_org_code ) [ 0 ] ,
aarp_org_code ,
sizeof ( aarp_org_code ) ) = = 0 & &
ntohs ( l - > llc_snap_ether_type ) = =
ETHERTYPE_AARP ) {
m_adj ( m , sizeof ( struct llc ) ) ;
aarpinput ( ifp , m ) ; /* XXX */
return ;
}
default :
goto dropanyway ;
}
break ;
# endif /* NETATALK */
1994-05-13 10:01:27 +04:00
# ifdef ISO
case LLC_ISO_LSAP :
switch ( l - > llc_control ) {
case LLC_UI :
/* LLC_UI_P forbidden in class 1 service */
if ( ( l - > llc_dsap = = LLC_ISO_LSAP ) & &
( l - > llc_ssap = = LLC_ISO_LSAP ) ) {
/* LSAP for ISO */
1995-04-06 01:38:50 +04:00
if ( m - > m_pkthdr . len > etype )
m_adj ( m , etype - m - > m_pkthdr . len ) ;
1994-05-13 10:01:27 +04:00
m - > m_data + = 3 ; /* XXX */
m - > m_len - = 3 ; /* XXX */
m - > m_pkthdr . len - = 3 ; /* XXX */
M_PREPEND ( m , sizeof * eh , M_DONTWAIT ) ;
if ( m = = 0 )
return ;
* mtod ( m , struct ether_header * ) = * eh ;
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 ;
case LLC_XID :
case LLC_XID_P :
if ( m - > m_len < 6 )
goto dropanyway ;
l - > llc_window = 0 ;
l - > llc_fid = 9 ;
l - > llc_class = 1 ;
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 ;
if ( m - > m_flags & ( M_BCAST | M_MCAST ) )
1997-03-15 21:09:08 +03:00
bcopy ( LLADDR ( ifp - > if_sadl ) ,
1994-05-13 10:01:27 +04:00
( caddr_t ) eh - > ether_dhost , 6 ) ;
sa . sa_family = AF_UNSPEC ;
sa . sa_len = sizeof ( sa ) ;
eh2 = ( struct ether_header * ) sa . sa_data ;
for ( i = 0 ; i < 6 ; i + + ) {
1997-03-15 21:09:08 +03:00
eh2 - > ether_shost [ i ] = c =
eh - > ether_dhost [ i ] ;
1994-05-13 10:01:27 +04: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 */
# ifdef LLC
case LLC_X25_LSAP :
1993-03-21 12:45:37 +03:00
{
1995-04-06 01:38:50 +04:00
if ( m - > m_pkthdr . len > etype )
m_adj ( m , etype - m - > m_pkthdr . len ) ;
1994-05-13 10:01:27 +04:00
M_PREPEND ( m , sizeof ( struct sdl_hdr ) , M_DONTWAIT ) ;
if ( m = = 0 )
return ;
if ( ! sdl_sethdrif ( ifp , eh - > ether_shost , LLC_X25_LSAP ,
eh - > ether_dhost , LLC_X25_LSAP , 6 ,
mtod ( m , struct sdl_hdr * ) ) )
panic ( " ETHER cons addr failure " ) ;
1995-04-06 01:38:50 +04:00
mtod ( m , struct sdl_hdr * ) - > sdlhdr_len = etype ;
1994-05-13 10:01:27 +04:00
# ifdef LLC_DEBUG
1996-10-13 06:10:01 +04:00
printf ( " llc packet \n " ) ;
1994-05-13 10:01:27 +04:00
# endif /* LLC_DEBUG */
schednetisr ( NETISR_CCITT ) ;
inq = & llcintrq ;
break ;
1993-03-21 12:45:37 +03:00
}
1994-05-13 10:01:27 +04:00
# endif /* LLC */
1993-03-21 12:45:37 +03:00
dropanyway :
default :
1994-05-13 10:01:27 +04:00
m_freem ( m ) ;
return ;
}
1997-04-03 01:23:26 +04:00
# else /* ISO || LLC || NETATALK*/
1993-03-21 12:45:37 +03:00
m_freem ( m ) ;
return ;
1997-04-03 01:23:26 +04:00
# endif /* ISO || LLC || NETATALK*/
1993-03-21 12:45:37 +03:00
}
2001-04-14 03:29:55 +04:00
s = splnet ( ) ;
1993-03-21 12:45:37 +03:00
if ( IF_QFULL ( inq ) ) {
IF_DROP ( inq ) ;
m_freem ( m ) ;
} else
IF_ENQUEUE ( inq , m ) ;
splx ( s ) ;
}
/*
* Convert Ethernet address to printable ( loggable ) representation .
*/
static char digits [ ] = " 0123456789abcdef " ;
char *
2000-06-18 00:57:20 +04:00
ether_sprintf ( const u_char * ap )
1993-03-21 12:45:37 +03:00
{
static char etherbuf [ 18 ] ;
1998-04-26 10:17:20 +04:00
char * cp = etherbuf ;
int i ;
1993-03-21 12:45:37 +03:00
for ( i = 0 ; i < 6 ; i + + ) {
* cp + + = digits [ * ap > > 4 ] ;
* cp + + = digits [ * ap + + & 0xf ] ;
* cp + + = ' : ' ;
}
* - - cp = 0 ;
return ( etherbuf ) ;
}
1994-05-13 10:01:27 +04:00
/*
* Perform common duties while attaching to interface list
*/
void
2000-06-18 00:57:20 +04:00
ether_ifattach ( struct ifnet * ifp , const u_int8_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 ;
2001-01-17 03:30:49 +03:00
ifp - > if_addrlen = ETHER_ADDR_LEN ;
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
if_alloc_sadl ( ifp ) ;
memcpy ( LLADDR ( ifp - > if_sadl ) , lla , ifp - > if_addrlen ) ;
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 ;
2000-11-15 04:02:11 +03:00
# if NBPFILTER > 0
2000-12-12 21:00:22 +03:00
bpfattach ( ifp , DLT_EN10MB , sizeof ( struct ether_header ) ) ;
2000-11-15 04:02:11 +03:00
# endif
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 ;
2000-11-15 04:02:11 +03:00
# if NBPFILTER > 0
bpfdetach ( ifp ) ;
# endif
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 .
*/
2000-03-06 23:54:41 +03:00
u_int32_t
2000-06-18 00:57:20 +04:00
ether_crc32_le ( const u_int8_t * buf , size_t len )
2000-03-06 23:54:41 +03:00
{
u_int32_t c , crc , carry ;
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
u_int32_t
2000-06-18 00:57:20 +04:00
ether_crc32_le ( const u_int8_t * buf , size_t len )
2000-05-12 20:22:36 +04:00
{
static const u_int32_t crctab [ ] = {
0x00000000 , 0x1db71064 , 0x3b6e20c8 , 0x26d930ac ,
0x76dc4190 , 0x6b6b51f4 , 0x4db26158 , 0x5005713c ,
0xedb88320 , 0xf00f9344 , 0xd6d6a3e8 , 0xcb61b38c ,
0x9b64c2b0 , 0x86d3d2d4 , 0xa00ae278 , 0xbdbdf21c
} ;
u_int32_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
u_int32_t
2000-06-18 00:57:20 +04:00
ether_crc32_be ( const u_int8_t * buf , size_t len )
2000-03-06 23:54:41 +03:00
{
u_int32_t c , crc , carry ;
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
1993-12-06 07:50:19 +03:00
u_char ether_ipmulticast_min [ 6 ] = { 0x01 , 0x00 , 0x5e , 0x00 , 0x00 , 0x00 } ;
u_char ether_ipmulticast_max [ 6 ] = { 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
u_char ether_ip6multicast_min [ 6 ] = { 0x33 , 0x33 , 0x00 , 0x00 , 0x00 , 0x00 } ;
u_char ether_ip6multicast_max [ 6 ] = { 0x33 , 0x33 , 0xff , 0xff , 0xff , 0xff } ;
# endif
2000-09-28 11:15:27 +04: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
2000-09-28 11:15:27 +04:00
ether_multiaddr ( struct sockaddr * sa , u_int8_t addrlo [ ETHER_ADDR_LEN ] ,
u_int8_t addrhi [ ETHER_ADDR_LEN ] )
1993-12-06 07:50:19 +03:00
{
1997-04-03 19:25:20 +04:00
# ifdef INET
1993-12-06 07:50:19 +03:00
struct sockaddr_in * sin ;
1997-04-03 19:25:20 +04:00
# endif /* INET */
1999-07-01 12:12:45 +04:00
# ifdef INET6
struct sockaddr_in6 * sin6 ;
# 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 :
2000-09-28 11:15:27 +04:00
bcopy ( sa - > sa_data , addrlo , ETHER_ADDR_LEN ) ;
bcopy ( addrlo , addrhi , ETHER_ADDR_LEN ) ;
1993-12-06 07:50:19 +03:00
break ;
# ifdef INET
case AF_INET :
2000-09-28 11:15:27 +04:00
sin = satosin ( 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 . )
*/
2000-09-28 11:15:27 +04:00
bcopy ( ether_ipmulticast_min , addrlo , ETHER_ADDR_LEN ) ;
bcopy ( ether_ipmulticast_max , addrhi , ETHER_ADDR_LEN ) ;
1993-12-06 07:50:19 +03:00
}
else {
ETHER_MAP_IP_MULTICAST ( & sin - > sin_addr , addrlo ) ;
2000-09-28 11:15:27 +04:00
bcopy ( addrlo , addrhi , 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 :
2000-09-28 11:15:27 +04:00
sin6 = satosin6 ( 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 . )
*/
bcopy ( ether_ip6multicast_min , addrlo , ETHER_ADDR_LEN ) ;
bcopy ( ether_ip6multicast_max , addrhi , ETHER_ADDR_LEN ) ;
} else {
ETHER_MAP_IPV6_MULTICAST ( & sin6 - > sin6_addr , addrlo ) ;
bcopy ( addrlo , addrhi , ETHER_ADDR_LEN ) ;
}
break ;
# endif
1993-12-06 07:50:19 +03:00
default :
return ( EAFNOSUPPORT ) ;
}
2000-09-28 11:15:27 +04:00
return ( 0 ) ;
}
/*
* Add an Ethernet multicast address or range of addresses to the list for a
* given interface .
*/
int
ether_addmulti ( struct ifreq * ifr , struct ethercom * ec )
{
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
error = ether_multiaddr ( & ifr - > ifr_addr , addrlo , addrhi ) ;
if ( error ! = 0 ) {
splx ( s ) ;
return ( error ) ;
}
1993-12-06 07:50:19 +03:00
/*
* Verify that we have valid Ethernet multicast addresses .
*/
if ( ( addrlo [ 0 ] & 0x01 ) ! = 1 | | ( addrhi [ 0 ] & 0x01 ) ! = 1 ) {
splx ( s ) ;
return ( EINVAL ) ;
}
/*
* 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 ) ;
return ( 0 ) ;
}
/*
* 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 ) ;
return ( ENOBUFS ) ;
}
bcopy ( addrlo , enm - > enm_addrlo , 6 ) ;
bcopy ( addrhi , enm - > enm_addrhi , 6 ) ;
1997-03-15 21:09:08 +03:00
enm - > enm_ec = ec ;
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 .
*/
return ( ENETRESET ) ;
}
/*
* Delete a multicast address record .
*/
int
2000-06-18 00:57:20 +04:00
ether_delmulti ( struct ifreq * ifr , 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
2000-09-28 11:15:27 +04:00
error = ether_multiaddr ( & ifr - > ifr_addr , addrlo , addrhi ) ;
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
/*
* Common ioctls for Ethernet interfaces . Note , we must be
* called at splnet ( ) .
*/
int
ether_ioctl ( struct ifnet * ifp , u_long cmd , caddr_t data )
{
struct ethercom * ec = ( void * ) ifp ;
struct ifreq * ifr = ( struct ifreq * ) data ;
struct ifaddr * ifa = ( struct ifaddr * ) data ;
int error = 0 ;
switch ( cmd ) {
case SIOCSIFADDR :
ifp - > if_flags | = IFF_UP ;
switch ( ifa - > ifa_addr - > sa_family ) {
2001-01-17 03:30:49 +03:00
case AF_LINK :
{
struct sockaddr_dl * sdl =
( struct sockaddr_dl * ) ifa - > ifa_addr ;
if ( sdl - > sdl_type ! = IFT_ETHER | |
sdl - > sdl_alen ! = ifp - > if_addrlen ) {
error = EINVAL ;
break ;
}
memcpy ( LLADDR ( ifp - > if_sadl ) , LLADDR ( sdl ) ,
ifp - > if_addrlen ) ;
/* Set new address. */
error = ( * ifp - > if_init ) ( ifp ) ;
break ;
}
2000-10-11 20:53:41 +04:00
# ifdef INET
case AF_INET :
2001-06-29 22:12:09 +04:00
if ( ( ifp - > if_flags & IFF_RUNNING ) = = 0 & &
( error = ( * ifp - > if_init ) ( ifp ) ) ! = 0 )
2000-10-11 20:53:41 +04:00
break ;
arp_ifinit ( ifp , ifa ) ;
break ;
# endif /* INET */
# ifdef NS
case AF_NS :
{
struct ns_addr * ina = & IA_SNS ( ifa ) - > sns_addr ;
if ( ns_nullhost ( * ina ) )
ina - > x_host = * ( union ns_host * )
LLADDR ( ifp - > if_sadl ) ;
else
memcpy ( LLADDR ( ifp - > if_sadl ) ,
ina - > x_host . c_host , ifp - > if_addrlen ) ;
/* Set new address. */
error = ( * ifp - > if_init ) ( ifp ) ;
break ;
}
# endif /* NS */
default :
2001-06-29 22:12:09 +04:00
if ( ( ifp - > if_flags & IFF_RUNNING ) = = 0 )
error = ( * ifp - > if_init ) ( ifp ) ;
2000-10-11 20:53:41 +04:00
break ;
}
break ;
case SIOCGIFADDR :
memcpy ( ( ( struct sockaddr * ) & ifr - > ifr_data ) - > sa_data ,
LLADDR ( ifp - > if_sadl ) , ETHER_ADDR_LEN ) ;
break ;
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 )
2000-10-11 20:53:41 +04:00
error = EINVAL ;
2001-07-25 07:18:46 +04:00
else {
2000-10-11 20:53:41 +04:00
ifp - > if_mtu = ifr - > ifr_mtu ;
2001-07-25 07:05:33 +04:00
2001-07-25 07:18:46 +04:00
/* Make sure the device notices the MTU change. */
if ( ifp - > if_flags & IFF_UP )
error = ( * ifp - > if_init ) ( ifp ) ;
}
2000-10-11 20:53:41 +04:00
break ;
2001-06-03 07:07:39 +04:00
}
2000-10-11 20:53:41 +04:00
case SIOCSIFFLAGS :
if ( ( ifp - > if_flags & ( IFF_UP | IFF_RUNNING ) ) = = IFF_RUNNING ) {
/*
* If interface is marked down and it is running ,
* then stop and disable it .
*/
( * ifp - > if_stop ) ( ifp , 1 ) ;
} else if ( ( ifp - > if_flags & ( IFF_UP | IFF_RUNNING ) ) = = IFF_UP ) {
/*
* If interface is marked up and it is stopped , then
* start it .
*/
error = ( * ifp - > if_init ) ( ifp ) ;
} else if ( ( ifp - > if_flags & IFF_UP ) ! = 0 ) {
/*
* Reset the interface to pick up changes in any other
* flags that affect the hardware state .
*/
error = ( * ifp - > if_init ) ( ifp ) ;
}
break ;
case SIOCADDMULTI :
2000-12-27 02:54:34 +03:00
error = ether_addmulti ( ifr , ec ) ;
break ;
2000-10-11 20:53:41 +04:00
case SIOCDELMULTI :
2000-12-27 02:54:34 +03:00
error = ether_delmulti ( ifr , ec ) ;
2000-10-11 20:53:41 +04:00
break ;
default :
error = ENOTTY ;
}
return ( error ) ;
}