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

📄 if_bridge.c

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

int
bridge_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);
        }
#endif
done:
	bifc->ifbic_len = i * sizeof(breq);
	return (error);
}

int
bridge_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);
}

void
bridge_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.
 */
void
bridge_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.
 */
int
bridge_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.
 */
void
bridge_start(ifp)
	struct ifnet *ifp;
{
}

void
bridgeintr(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.
 */
void
bridgeintr_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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -