⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 if_bridge.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
//==========================================================================
//
//      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          55

extern 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_CODE
void 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));
#endif

void
bridgeattach(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
	}
}

int
bridge_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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -