if_bridge.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,353 行 · 第 1/4 页

C
2,353
字号
//==========================================================================////      sys/net/if_bridge.c////     ////==========================================================================//####BSDCOPYRIGHTBEGIN####//// -------------------------------------------//// Portions of this software may have been derived from OpenBSD or other sources,// and are covered by the appropriate copyright disclaimers included herein.//// -------------------------------------------////####BSDCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    Jason L. Wright (jason@thought.net)  // Contributors: andrew.lunn@ascom.ch (Andrew Lunn), hmt, manu.sharma@ascom.com// Date:         2000-07-18// Purpose:      Ethernet bridge// Description:  //              ////####DESCRIPTIONEND####////==========================================================================/*	$OpenBSD: if_bridge.c,v 1.33 2000/06/20 05:50:16 jason Exp $	*//* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) * 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. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by Jason L. Wright * 4. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. */#ifdef __ECOS#include <pkgconf/net.h>#else#include "bridge.h"#include "bpfilter.h"#include "enc.h"#endif#include <sys/param.h>#ifndef __ECOS#include <sys/proc.h>#include <sys/systm.h>#endif#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/errno.h>#ifndef __ECOS#include <sys/device.h>#endif#include <sys/kernel.h>#include <machine/cpu.h>#include <net/if.h>#include <net/if_types.h>#include <net/if_llc.h>#include <net/route.h>#include <net/netisr.h>#ifdef INET#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#include <netinet/ip_ipsp.h>#ifndef __ECOS#include <net/if_enc.h>#endif#ifdef IPFILTER#include <netinet/ip_fil_compat.h>#include <netinet/ip_fil.h>#endif#endif#if NBPFILTER > 0#include <net/bpf.h>#endif#include <net/if_bridge.h>#ifdef __ECOS#include <stdio.h> /* for sprintf */#endif #ifndef	BRIDGE_RTABLE_SIZE#define	BRIDGE_RTABLE_SIZE	1024#endif#define	BRIDGE_RTABLE_MASK	(BRIDGE_RTABLE_SIZE - 1)/* * Maximum number of addresses to cache */#ifndef BRIDGE_RTABLE_MAX#define BRIDGE_RTABLE_MAX	100#endif/* * Timeout (in seconds) for entries learned dynamically */#ifndef BRIDGE_RTABLE_TIMEOUT#define BRIDGE_RTABLE_TIMEOUT	300#endif/* Spanning tree defaults */#define BSTP_DEFAULT_MAX_AGE            (20 * 256)#define BSTP_DEFAULT_HELLO_TIME         (2 * 256)#define BSTP_DEFAULT_FORWARD_DELAY      (15 * 256)#define BSTP_DEFAULT_HOLD_TIME          (1 * 256)#define BSTP_DEFAULT_BRIDGE_PRIORITY    0x8000#define BSTP_DEFAULT_PORT_PRIORITY      0x80#define BSTP_DEFAULT_PATH_COST          55extern int ifqmaxlen;/* SNAP LLC header */struct snap {	u_int8_t dsap;	u_int8_t ssap;	u_int8_t control;	u_int8_t org[3];	u_int16_t type;};struct bridge_softc bridgectl[CYGNUM_NET_BRIDGES];void	bridgeattach __P((int));int	bridge_ioctl __P((struct ifnet *, u_long, caddr_t));void	bridge_start __P((struct ifnet *));void	bridgeintr_frame __P((struct bridge_softc *, struct mbuf *));void	bridge_broadcast __P((struct bridge_softc *, struct ifnet *,    struct ether_header *, struct mbuf *)) __attribute ((weak));void	bridge_stop __P((struct bridge_softc *));void	bridge_init __P((struct bridge_softc *));int	bridge_bifconf __P((struct bridge_softc *, struct ifbifconf *));int	bridge_rtfind __P((struct bridge_softc *, struct ifbaconf *));void	bridge_rtage __P((void *));void	bridge_rttrim __P((struct bridge_softc *));int	bridge_rtdaddr __P((struct bridge_softc *, struct ether_addr *));int	bridge_rtflush __P((struct bridge_softc *, int));struct ifnet *	bridge_rtupdate __P((struct bridge_softc *,    struct ether_addr *, struct ifnet *ifp, int, u_int8_t));struct ifnet *	bridge_rtlookup __P((struct bridge_softc *,    struct ether_addr *));u_int32_t	bridge_hash __P((struct ether_addr *));int bridge_blocknonip __P((struct ether_header *, struct mbuf *));int		bridge_addrule __P((struct bridge_iflist *,    struct ifbrlreq *, int out));int		bridge_flushrule __P((struct bridge_iflist *));int	bridge_brlconf __P((struct bridge_softc *, struct ifbrlconf *));u_int8_t bridge_filterrule __P((struct brl_node *, struct ether_header *));int     bridge_ifenqueue __P((struct bridge_softc *, struct ifnet *, struct mbuf *));#ifdef CYGPKG_NET_BRIDGE_STP_CODEvoid bridge_span (struct bridge_softc *, struct ether_header *, struct mbuf *);#endif#define	ETHERADDR_IS_IP_MCAST(a) \	/* struct etheraddr *a;	*/				\	((a)->ether_addr_octet[0] == 0x01 &&			\	 (a)->ether_addr_octet[1] == 0x00 &&			\	 (a)->ether_addr_octet[2] == 0x5e)#if defined(INET) && (defined(IPFILTER) || defined(IPFILTER_LKM))/* * Filter hooks */struct mbuf *bridge_filter __P((struct bridge_softc *, struct ifnet *,    struct ether_header *, struct mbuf *m));#endifvoidbridgeattach(unused)	int unused;{	int i;	struct ifnet *ifp;	for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {		bridgectl[i].sc_brtmax = BRIDGE_RTABLE_MAX;		bridgectl[i].sc_brttimeout = (BRIDGE_RTABLE_TIMEOUT * hz) / 2;                bridgectl[i].sc_bridge_max_age = BSTP_DEFAULT_MAX_AGE;                bridgectl[i].sc_bridge_hello_time = BSTP_DEFAULT_HELLO_TIME;                bridgectl[i].sc_bridge_forward_delay= BSTP_DEFAULT_FORWARD_DELAY;                bridgectl[i].sc_bridge_priority = BSTP_DEFAULT_BRIDGE_PRIORITY;                bridgectl[i].sc_hold_time = BSTP_DEFAULT_HOLD_TIME;		LIST_INIT(&bridgectl[i].sc_iflist);		LIST_INIT(&bridgectl[i].sc_spanlist);		ifp = &bridgectl[i].sc_if;		sprintf(ifp->if_xname, "bridge%d", i);		ifp->if_softc = &bridgectl[i];		ifp->if_mtu = ETHERMTU;		ifp->if_ioctl = bridge_ioctl;		ifp->if_output = bridge_output;		ifp->if_start = bridge_start;		ifp->if_type = IFT_PROPVIRTUAL;		ifp->if_snd.ifq_maxlen = ifqmaxlen;		ifp->if_hdrlen = sizeof(struct ether_header);		if_attach(ifp);#if NBPFILTER > 0		bpfattach(&bridgectl[i].sc_if.if_bpf, ifp,		    DLT_EN10MB, sizeof(struct ether_header));#endif	}}intbridge_ioctl(ifp, cmd, data)	struct ifnet *ifp;	u_long cmd;	caddr_t	data;{#ifndef __ECOS	struct proc *prc = curproc;		/* XXX */#endif	struct ifnet *ifs;	struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;	struct ifbreq *req = (struct ifbreq *)data;	struct ifbaconf *baconf = (struct ifbaconf *)data;	struct ifbareq *bareq = (struct ifbareq *)data;	struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;	struct ifbifconf *bifconf = (struct ifbifconf *)data;	struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;	struct ifbrlreq *brlreq = (struct ifbrlreq *)data;	struct ifbrlconf *brlconf = (struct ifbrlconf *)data;	struct ifreq ifreq;	int error = 0, s;	struct bridge_iflist *p;	s = splimp();	switch (cmd) {	case SIOCBRDGADD:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		ifs = ifunit(req->ifbr_ifsname);		if (ifs == NULL) {			/* no such interface */			error = ENOENT;			break;		}		if (ifs->if_bridge == (caddr_t)sc) {			error = EEXIST;			break;		}		if (ifs->if_bridge != NULL) {			error = EBUSY;			break;		}#ifdef CYGPKG_NET_BRIDGE_STP_CODE                /* If it's in the span list, it can't be a member. */                LIST_FOREACH(p, &sc->sc_spanlist, next) {                        if (p->ifp == ifs)                                break;                }                if (p != LIST_END(&sc->sc_spanlist)) {                        error = EBUSY;                        break;                }#endif		if (ifs->if_type == IFT_ETHER) {			if ((ifs->if_flags & IFF_UP) == 0) {				/*				 * Bring interface up long enough to set				 * promiscuous flag, then shut it down again.				 */				strncpy(ifreq.ifr_name, req->ifbr_ifsname,				    sizeof(ifreq.ifr_name) - 1);				ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';				ifs->if_flags |= IFF_UP;				ifreq.ifr_flags = ifs->if_flags;				error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,				    (caddr_t)&ifreq);				if (error != 0)					break;				error = ifpromisc(ifs, 1);				if (error != 0)					break;				strncpy(ifreq.ifr_name, req->ifbr_ifsname,				    sizeof(ifreq.ifr_name) - 1);				ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0';				ifs->if_flags &= ~IFF_UP;				ifreq.ifr_flags = ifs->if_flags;				error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS,				    (caddr_t)&ifreq);				if (error != 0) {					ifpromisc(ifs, 0);					break;				}			} else {				error = ifpromisc(ifs, 1);				if (error != 0)					break;			}		}#ifndef __ECOS#if NENC > 0		else if (ifs->if_type == IFT_ENC) {			/* Can't bind enc0 to a bridge */			if (ifs->if_softc == &encif[0]) {				error = EINVAL;				break;			}		}#endif /* NENC */#endif		else {			error = EINVAL;			break;		}		p = (struct bridge_iflist *) malloc(		    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);		if (p == NULL && ifs->if_type == IFT_ETHER) {			error = ENOMEM;			ifpromisc(ifs, 0);			break;		}		p->ifp = ifs;		p->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;                p->bif_priority = BSTP_DEFAULT_PORT_PRIORITY;                p->bif_path_cost = BSTP_DEFAULT_PATH_COST;		SIMPLEQ_INIT(&p->bif_brlin);		SIMPLEQ_INIT(&p->bif_brlout);		LIST_INSERT_HEAD(&sc->sc_iflist, p, next);		ifs->if_bridge = (caddr_t)sc;		break;	case SIOCBRDGDEL:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		p = LIST_FIRST(&sc->sc_iflist);		while (p != NULL) {			if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,			    sizeof(p->ifp->if_xname)) == 0) {				p->ifp->if_bridge = NULL;				error = ifpromisc(p->ifp, 0);				LIST_REMOVE(p, next);				bridge_rtdelete(sc, p->ifp, 0);				bridge_flushrule(p);				free(p, M_DEVBUF);				break;			}			p = LIST_NEXT(p, next);		}		if (p == NULL) {			error = ENOENT;			break;		}		break;	case SIOCBRDGIFS:		error = bridge_bifconf(sc, bifconf);		break;#ifdef CYGPKG_NET_BRIDGE_STP_CODE        case SIOCBRDGADDS:#ifndef __ECOS                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)                        break;#endif                ifs = ifunit(req->ifbr_ifsname);                if (ifs == NULL) {                      /* no such interface */                        error = ENOENT;                        break;                }                if (ifs->if_bridge == (caddr_t)sc) {                        error = EEXIST;                        break;                }                if (ifs->if_bridge != NULL) {                        error = EBUSY;                        break;                }                LIST_FOREACH(p, &sc->sc_spanlist, next) {                        if (p->ifp == ifs)                        break;                }                if (p != LIST_END(&sc->sc_spanlist)) {                        error = EBUSY;                        break;                }                p = (struct bridge_iflist *)malloc(                    sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);                if (p == NULL) {                       error = ENOMEM;                       break;                }                bzero(p, sizeof(struct bridge_iflist));                p->ifp = ifs;                SIMPLEQ_INIT(&p->bif_brlin);                SIMPLEQ_INIT(&p->bif_brlout);                LIST_INSERT_HEAD(&sc->sc_spanlist, p, next);                break;                                                                                                                                                                                                           case SIOCBRDGDELS:#ifndef __ECOS                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)                       break;#endif                LIST_FOREACH(p, &sc->sc_spanlist, next) {                       if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,                          sizeof(p->ifp->if_xname)) == 0) {                              LIST_REMOVE(p, next);                              free(p, M_DEVBUF);                              break;                       }                }                if (p == LIST_END(&sc->sc_spanlist)) {                       error = ENOENT;                       break;                }                break;#endif	case SIOCBRDGGIFFLGS:		ifs = ifunit(req->ifbr_ifsname);		if (ifs == NULL) {			error = ENOENT;			break;		}		if ((caddr_t)sc != ifs->if_bridge) {			error = ESRCH;			break;		}		p = LIST_FIRST(&sc->sc_iflist);		while (p != NULL && p->ifp != ifs) {			p = LIST_NEXT(p, next);		}		if (p == NULL) {			error = ESRCH;			break;		}		req->ifbr_ifsflags = p->bif_flags;                req->ifbr_state = p->bif_state;                req->ifbr_priority = p->bif_priority;                req->ifbr_path_cost = p->bif_path_cost;                req->ifbr_portno = p->ifp->if_index & 0xff;		break;	case SIOCBRDGSIFFLGS:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		ifs = ifunit(req->ifbr_ifsname);		if (ifs == NULL) {			error = ENOENT;			break;		}		if ((caddr_t)sc != ifs->if_bridge) {			error = ESRCH;			break;		}		p = LIST_FIRST(&sc->sc_iflist);		while (p != NULL && p->ifp != ifs) {			p = LIST_NEXT(p, next);		}		if (p == NULL) {			error = ESRCH;			break;		}		p->bif_flags = req->ifbr_ifsflags;		break;        case SIOCBRDGSIFPRIO:        case SIOCBRDGSIFCOST:#ifndef __ECOS                if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)                        break;#endif                ifs = ifunit(req->ifbr_ifsname);                if (ifs == NULL) {                        error = ENOENT;                        break;                }                if ((caddr_t)sc != ifs->if_bridge) {                        error = ESRCH;                        break;                }                LIST_FOREACH(p, &sc->sc_iflist, next) {                        if (p->ifp == ifs)                        break;                }                if (p == LIST_END(&sc->sc_iflist)) {                        error = ESRCH;                        break;                }                if (cmd == SIOCBRDGSIFPRIO)                        p->bif_priority = req->ifbr_priority;                else {                        if (req->ifbr_path_cost < 1)                                error = EINVAL;                        else                                p->bif_path_cost = req->ifbr_path_cost;                }                break;	case SIOCBRDGRTS:		error = bridge_rtfind(sc, baconf);		break;	case SIOCBRDGFLUSH:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		error = bridge_rtflush(sc, req->ifbr_ifsflags);		break;	case SIOCBRDGSADDR:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		ifs = ifunit(bareq->ifba_ifsname);		if (ifs == NULL) {			/* no such interface */			error = ENOENT;			break;		}		if (ifs->if_bridge == NULL ||		    ifs->if_bridge != (caddr_t)sc) {			error = ESRCH;			break;		}		ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,		    bareq->ifba_flags);		if (ifs == NULL)			error = ENOMEM;		break;	case SIOCBRDGDADDR:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		error = bridge_rtdaddr(sc, &bareq->ifba_dst);		break;	case SIOCBRDGGCACHE:		bcachereq->ifbc_size = sc->sc_brtmax;		break;	case SIOCBRDGSCACHE:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		sc->sc_brtmax = bcachereq->ifbc_size;		bridge_rttrim(sc);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?