if_bridge.c

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

C
2,353
字号
		break;	case SIOCBRDGSTO:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		sc->sc_brttimeout = (bcacheto->ifbct_time * hz) / 2;		untimeout(bridge_rtage, sc);		if (bcacheto->ifbct_time != 0)			timeout(bridge_rtage, sc, sc->sc_brttimeout);		break;	case SIOCBRDGGTO:		bcacheto->ifbct_time = (2 * sc->sc_brttimeout) / hz;		break;	case SIOCSIFFLAGS:		if ((ifp->if_flags & IFF_UP) == IFF_UP)			bridge_init(sc);		if ((ifp->if_flags & IFF_UP) == 0)			bridge_stop(sc);		break;	case SIOCBRDGARL:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		ifs = ifunit(brlreq->ifbr_ifsname);		if (ifs == NULL) {			error = ENOENT;			break;		}		if (ifs->if_bridge == NULL ||		    ifs->if_bridge != (caddr_t)sc) {			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;		}		if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&		    brlreq->ifbr_action != BRL_ACTION_PASS) ||		    (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {			error = EINVAL;			break;		}		if (brlreq->ifbr_flags & BRL_FLAG_IN) {			error = bridge_addrule(p, brlreq, 0);			if (error)				break;		}		if (brlreq->ifbr_flags & BRL_FLAG_OUT) {			error = bridge_addrule(p, brlreq, 1);			if (error)				break;		}		break;	case SIOCBRDGFRL:#ifndef __ECOS		if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)			break;#endif		ifs = ifunit(brlreq->ifbr_ifsname);		if (ifs == NULL) {			error = ENOENT;			break;		}		if (ifs->if_bridge == NULL ||		    ifs->if_bridge != (caddr_t)sc) {			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;		}		error = bridge_flushrule(p);		break;	case SIOCBRDGGRL:		error = bridge_brlconf(sc, brlconf);		break;        case SIOCBRDGGPRI:        case SIOCBRDGGMA:        case SIOCBRDGGHT:        case SIOCBRDGGFD:                break;        case SIOCBRDGSPRI:        case SIOCBRDGSFD:        case SIOCBRDGSMA:        case SIOCBRDGSHT:#ifndef __ECOS                error = suser(prc->p_ucred, &prc->p_acflag);#endif                break;	default:		error = EINVAL;	}#ifdef CYGPKG_NET_BRIDGE_STP_CODE        if (!error)                error = bstp_ioctl(ifp, cmd, data);#endif	splx(s);	return (error);}/* Detach an interface from a bridge.  */voidbridge_ifdetach(ifp)	struct ifnet *ifp;{	struct bridge_softc *bsc = (struct bridge_softc *)ifp->if_bridge;	struct bridge_iflist *bif;	for (bif = LIST_FIRST(&bsc->sc_iflist); bif;	    bif = LIST_NEXT(bif, next))		if (bif->ifp == ifp) {			LIST_REMOVE(bif, next);			bridge_rtdelete(bsc, ifp, 0);			bridge_flushrule(bif);			free(bif, M_DEVBUF);			ifp->if_bridge = NULL;			break;		}}intbridge_bifconf(sc, bifc)	struct bridge_softc *sc;	struct ifbifconf *bifc;{	struct bridge_iflist *p;	u_int32_t total = 0, i;#ifdef CYGPKG_NET_BRIDGE_STP_CODE        u_int32_t j;#endif	int error = 0;	struct ifbreq breq;	p = LIST_FIRST(&sc->sc_iflist);	while (p != NULL) {		total++;		p = LIST_NEXT(p, next);	}#ifdef CYGPKG_NET_BRIDGE_STP_CODE        p = LIST_FIRST(&sc->sc_spanlist);        while (p != NULL) {                total++;                p = LIST_NEXT(p, next);        }#endif	if (bifc->ifbic_len == 0) {		i = total;		goto done;	}	p = LIST_FIRST(&sc->sc_iflist);	i = 0;	while (p != NULL && bifc->ifbic_len > i * sizeof(breq)) {		strncpy(breq.ifbr_name, sc->sc_if.if_xname,		    sizeof(breq.ifbr_name)-1);		breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';		strncpy(breq.ifbr_ifsname, p->ifp->if_xname,		    sizeof(breq.ifbr_ifsname)-1);		breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';		breq.ifbr_ifsflags = p->bif_flags;                breq.ifbr_state = p->bif_state;                breq.ifbr_priority = p->bif_priority;                breq.ifbr_path_cost = p->bif_path_cost;                breq.ifbr_portno = p->ifp->if_index & 0xff;		error = copyout((caddr_t)&breq,		    (caddr_t)(bifc->ifbic_req + i), sizeof(breq));		if (error)			goto done;		p = LIST_NEXT(p, next);		i++;		bifc->ifbic_len -= sizeof(breq);	}#ifdef CYGPKG_NET_BRIDGE_STP_CODE        p = LIST_FIRST(&sc->sc_spanlist);        j = 0;        while (p != NULL && bifc->ifbic_len > j * sizeof(breq)) {                strncpy(breq.ifbr_name, sc->sc_if.if_xname,                        sizeof(breq.ifbr_name)-1);                breq.ifbr_name[sizeof(breq.ifbr_name) - 1] = '\0';                strncpy(breq.ifbr_ifsname, p->ifp->if_xname,                    sizeof(breq.ifbr_ifsname)-1);                breq.ifbr_ifsname[sizeof(breq.ifbr_ifsname) - 1] = '\0';                 breq.ifbr_ifsflags = p->bif_flags | IFBIF_SPAN;                breq.ifbr_state = p->bif_state;                breq.ifbr_priority = p->bif_priority;                breq.ifbr_path_cost = p->bif_path_cost;                breq.ifbr_portno = p->ifp->if_index & 0xff;                error = copyout((caddr_t)&breq,                    (caddr_t)(bifc->ifbic_req + j), sizeof(breq));                if (error)                        goto done;                p = LIST_NEXT(p, next);                j++;                bifc->ifbic_len -= sizeof(breq);        }#endifdone:	bifc->ifbic_len = i * sizeof(breq);	return (error);}intbridge_brlconf(sc, bc)	struct bridge_softc *sc;	struct ifbrlconf *bc;{	struct ifnet *ifp;	struct bridge_iflist *ifl;	struct brl_node *n;	struct ifbrlreq req;	int error = 0;	u_int32_t i, total=0;	ifp = ifunit(bc->ifbrl_ifsname);	if (ifp == NULL)		return (ENOENT);	if (ifp->if_bridge == NULL || ifp->if_bridge != (caddr_t)sc)		return (ESRCH);	ifl = LIST_FIRST(&sc->sc_iflist);	while (ifl != NULL && ifl->ifp != ifp)		ifl = LIST_NEXT(ifl, next);	if (ifl == NULL)		return (ESRCH);	n = SIMPLEQ_FIRST(&ifl->bif_brlin);	while (n != NULL) {		total++;		n = SIMPLEQ_NEXT(n, brl_next);	}	n = SIMPLEQ_FIRST(&ifl->bif_brlout);	while (n != NULL) {		total++;		n = SIMPLEQ_NEXT(n, brl_next);	}	if (bc->ifbrl_len == 0) {		i = total;		goto done;	}	i = 0;	n = SIMPLEQ_FIRST(&ifl->bif_brlin);	while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {		strncpy(req.ifbr_name, sc->sc_if.if_xname,		    sizeof(req.ifbr_name) - 1);		req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';		strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,		    sizeof(req.ifbr_ifsname) - 1);		req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';		req.ifbr_action = n->brl_action;		req.ifbr_flags = n->brl_flags;		req.ifbr_src = n->brl_src;		req.ifbr_dst = n->brl_dst;		error = copyout((caddr_t)&req,		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));		if (error)			goto done;		n = SIMPLEQ_NEXT(n, brl_next);		i++;		bc->ifbrl_len -= sizeof(req);	}	n = SIMPLEQ_FIRST(&ifl->bif_brlout);	while (n != NULL && bc->ifbrl_len > i * sizeof(req)) {		strncpy(req.ifbr_name, sc->sc_if.if_xname,		    sizeof(req.ifbr_name) - 1);		req.ifbr_name[sizeof(req.ifbr_name) - 1] = '\0';		strncpy(req.ifbr_ifsname, ifl->ifp->if_xname,		    sizeof(req.ifbr_ifsname) - 1);		req.ifbr_ifsname[sizeof(req.ifbr_ifsname) - 1] = '\0';		req.ifbr_action = n->brl_action;		req.ifbr_flags = n->brl_flags;		req.ifbr_src = n->brl_src;		req.ifbr_dst = n->brl_dst;		error = copyout((caddr_t)&req,		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));		if (error)			goto done;		n = SIMPLEQ_NEXT(n, brl_next);		i++;		bc->ifbrl_len -= sizeof(req);	}done:	bc->ifbrl_len = i * sizeof(req);	return (error);}voidbridge_init(sc)	struct bridge_softc *sc;{	struct ifnet *ifp = &sc->sc_if;	int i, s;	if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)		return;	s = splhigh();	if (sc->sc_rts == NULL) {		sc->sc_rts = (struct bridge_rthead *)malloc(		    BRIDGE_RTABLE_SIZE * (sizeof(struct bridge_rthead)),		    M_DEVBUF, M_NOWAIT);		if (sc->sc_rts == NULL) {			splx(s);			return;		}		for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {			LIST_INIT(&sc->sc_rts[i]);		}	}	ifp->if_flags |= IFF_RUNNING;	splx(s);	if (sc->sc_brttimeout != 0) 		timeout(bridge_rtage, sc, sc->sc_brttimeout);}/* * Stop the bridge and deallocate the routing table. */voidbridge_stop(sc)	struct bridge_softc *sc;{	struct ifnet *ifp = &sc->sc_if;	/*	 * If we're not running, there's nothing to do.	 */	if ((ifp->if_flags & IFF_RUNNING) == 0)		return;	untimeout(bridge_rtage, sc);	bridge_rtflush(sc, IFBF_FLUSHDYN);	ifp->if_flags &= ~IFF_RUNNING;}/* * Send output from the bridge.  The mbuf has the ethernet header * already attached.  We must enqueue or free the mbuf before exiting. */intbridge_output(ifp, m, sa, rt)	struct ifnet *ifp;	struct mbuf *m;	struct sockaddr *sa;	struct rtentry *rt;{	struct ether_header *eh;	struct ifnet *dst_if;	struct ether_addr *src, *dst;	struct bridge_softc *sc;	int s;	if (m->m_len < sizeof(*eh)) {		m = m_pullup(m, sizeof(*eh));		if (m == NULL)			return (0);	}	eh = mtod(m, struct ether_header *);	dst = (struct ether_addr *)&eh->ether_dhost[0];	src = (struct ether_addr *)&eh->ether_shost[0];	sc = (struct bridge_softc *)ifp->if_bridge;	s = splimp();	/*	 * If bridge is down, but original output interface is up,	 * go ahead and send out that interface.  Otherwise the packet	 * is dropped below.	 */	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {		dst_if = ifp;		goto sendunicast;	}	/*	 * If the packet is a broadcast or we don't know a better way to	 * get there, send to all interfaces.	 */	dst_if = bridge_rtlookup(sc, dst);	if (dst_if == NULL || eh->ether_dhost[0] & 1) {		struct bridge_iflist *p;		struct mbuf *mc;		int used = 0;#ifdef CYGPKG_NET_BRIDGE_STP_CODE                bridge_span(sc, NULL, m);#endif		for (p = LIST_FIRST(&sc->sc_iflist); p != NULL;		     p = LIST_NEXT(p, next)) {			if ((p->ifp->if_flags & IFF_RUNNING) == 0)				continue;			if (IF_QFULL(&p->ifp->if_snd)) {				sc->sc_if.if_oerrors++;				continue;			}			if (LIST_NEXT(p, next) == NULL) {				used = 1;				mc = m;			} else {				mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);				if (mc == NULL) {					sc->sc_if.if_oerrors++;					continue;				}			}			sc->sc_if.if_opackets++;			sc->sc_if.if_obytes += m->m_pkthdr.len;                        // Also count the bytes in the outgoing interface; normally                        // done in if_ethersubr.c but here we bypass that route.                        p->ifp->if_obytes += m->m_pkthdr.len;			IF_ENQUEUE(&p->ifp->if_snd, mc);			if ((p->ifp->if_flags & IFF_OACTIVE) == 0)				(*p->ifp->if_start)(p->ifp);		}		if (!used)			m_freem(m);		splx(s);		return (0);	}sendunicast:	if ((dst_if->if_flags & IFF_RUNNING) == 0) {		m_freem(m);		splx(s);		return (0);	}	if (IF_QFULL(&dst_if->if_snd)) {		sc->sc_if.if_oerrors++;		m_freem(m);		splx(s);		return (0);	}	sc->sc_if.if_opackets++;	sc->sc_if.if_obytes += m->m_pkthdr.len;        // Also count the bytes in the outgoing interface; normally        // done in if_ethersubr.c but here we bypass that route.        dst_if->if_obytes += m->m_pkthdr.len;	IF_ENQUEUE(&dst_if->if_snd, m);	if ((dst_if->if_flags & IFF_OACTIVE) == 0)		(*dst_if->if_start)(dst_if);	splx(s);	return (0);}/* * Start output on the bridge.  This function should never be called. */voidbridge_start(ifp)	struct ifnet *ifp;{}voidbridgeintr(void){	struct bridge_softc *sc;	struct mbuf *m;	int i, s;	for (i = 0; i < CYGNUM_NET_BRIDGES; i++) {		sc = &bridgectl[i];		for (;;) {			s = splimp();			IF_DEQUEUE(&sc->sc_if.if_snd, m);			splx(s);			if (m == NULL)				break;			bridgeintr_frame(sc, m);		}	}}/* * Loop through each bridge interface and process their input queues. */voidbridgeintr_frame(sc, m)	struct bridge_softc *sc;	struct mbuf *m;{	int s;	struct ifnet *src_if, *dst_if;	struct bridge_iflist *ifl;	struct ether_addr *dst, *src;	struct ether_header eh;	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {		m_freem(m);		return;	}	src_if = m->m_pkthdr.rcvif;        /*          * Pick out 802.1D packets.         *                   */#ifdef CYGPKG_NET_BRIDGE_STP_CODE#ifdef __ECOS        if (m->m_flags & (M_BCAST | M_MCAST)) {                if (bcmp (mtod(m,struct ether_header *), bstp_etheraddr, ETHER_ADDR_LEN) == 0) {                        m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);                        m_adj (m, sizeof(struct ether_header));                        m = bstp_input(sc, src_if, &eh, m);                        if (m == NULL)                                return;                 }        }#endif   // __ECOS#endif#if NBPFILTER > 0	if (sc->sc_if.if_bpf)		bpf_mtap(sc->sc_if.if_bpf, m);#endif	sc->sc_if.if_lastchange = time;	sc->sc_if.if_ipackets++;	sc->sc_if.if_ibytes += m->m_pkthdr.len;	ifl = LIST_FIRST(&sc->sc_iflist);	while (ifl != NULL && ifl->ifp != src_if) {		ifl = LIST_NEXT(ifl, next);	}	if (ifl == NULL) {		m_freem(m);		return;	}#ifdef CYGPKG_NET_BRIDGE_STP_CODE        if ((ifl->bif_flags & IFBIF_STP) &&            (ifl->bif_state == BSTP_IFSTATE_BLOCKING ||            ifl->bif_state == BSTP_IFSTATE_LISTENING ||            ifl->bif_state == BSTP_IFSTATE_DISABLED)) {                m_freem(m);                return;        }#endif	if (m->m_pkthdr.len < sizeof(eh)) {		m_freem(m);		return;	}	m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&eh);	dst = (struct ether_addr *)&eh.ether_dhost[0];	src = (struct ether_addr *)&eh.ether_shost[0];	/*	 * If interface is learning, and if source address	 * is not broadcast or multicast, record it's address.	 */	if ((ifl->bif_flags & IFBIF_LEARNING) &&	    (eh.ether_shost[0] & 1) == 0 &&	    !(eh.ether_shost[0] == 0 &&	      eh.ether_shost[1] == 0 &&	      eh.ether_shost[2] == 0 &&	      eh.ether_shost[3] == 0 &&	      eh.ether_shost[4] == 0 &&	      eh.ether_shost[5] == 0))		bridge_rtupdate(sc, src, src_if, 0, IFBAF_DYNAMIC);#ifdef CYGPKG_NET_BRIDGE_STP_CODE        if ((ifl->bif_flags & IFBIF_STP) &&

⌨️ 快捷键说明

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