Beispiel #1
0
mblk_t *
vsw_get_same_dest_list(struct ether_header *ehp, mblk_t **mpp)
{
	mblk_t			*bp;
	mblk_t			*nbp;
	mblk_t			*head = NULL;
	mblk_t			*tail = NULL;
	mblk_t			*prev = NULL;
	struct ether_header	*behp;

	/* process the chain of packets */
	bp = *mpp;
	while (bp) {
		nbp = bp->b_next;
		behp = (struct ether_header *)bp->b_rptr;
		bp->b_prev = NULL;
		if (ether_cmp(&ehp->ether_dhost, &behp->ether_dhost) == 0) {
			if (prev == NULL) {
				*mpp = nbp;
			} else {
				prev->b_next = nbp;
			}
			bp->b_next =  NULL;
			if (head == NULL) {
				head = tail = bp;
			} else {
				tail->b_next = bp;
				tail = bp;
			}
		} else {
			prev = bp;
		}
		bp = nbp;
	}
	return (head);
}
Beispiel #2
0
static void
am7990_rint(struct lance_softc *sc)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m;
	struct lermd rmd;
	int bix, rp;
#if defined(LANCE_REVC_BUG)
	struct ether_header *eh;
	/* Make sure this is short-aligned, for ether_cmp(). */
	static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
#endif

	bix = sc->sc_last_rd;

	/* Process all buffers with valid data. */
	for (;;) {
		rp = LE_RMDADDR(sc, bix);
		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));

		if (rmd.rmd1_bits & LE_R1_OWN)
			break;

		m = NULL;
		if ((rmd.rmd1_bits & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
		    (LE_R1_STP | LE_R1_ENP)) {
			if (rmd.rmd1_bits & LE_R1_ERR) {
#ifdef LEDEBUG
				if (rmd.rmd1_bits & LE_R1_ENP) {
					if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
						if (rmd.rmd1_bits & LE_R1_FRAM)
							if_printf(ifp,
							    "framing error\n");
						if (rmd.rmd1_bits & LE_R1_CRC)
							if_printf(ifp,
							    "crc mismatch\n");
					}
				} else
					if (rmd.rmd1_bits & LE_R1_OFLO)
						if_printf(ifp, "overflow\n");
#endif
				if (rmd.rmd1_bits & LE_R1_BUFF)
					if_printf(ifp,
					    "receive buffer error\n");
			} else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
			    (LE_R1_STP | LE_R1_ENP))
				if_printf(ifp, "dropping chained buffer\n");
		} else {
#ifdef LEDEBUG
			if (sc->sc_flags & LE_DEBUG)
				am7990_recv_print(sc, bix);
#endif
			/* Pull the packet off the interface. */
			m = lance_get(sc, LE_RBUFADDR(sc, bix),
			    (int)rmd.rmd3 - ETHER_CRC_LEN);
		}

		rmd.rmd1_bits = LE_R1_OWN;
		rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
		rmd.rmd3 = 0;
		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));

		if (++bix == sc->sc_nrbuf)
			bix = 0;

		if (m != NULL) {
			ifp->if_ipackets++;

#ifdef LANCE_REVC_BUG
			/*
			 * The old LANCE (Rev. C) chips have a bug which
			 * causes garbage to be inserted in front of the
			 * received packet. The workaround is to ignore
			 * packets with an invalid destination address
			 * (garbage will usually not match).
			 * Of course, this precludes multicast support...
			 */
			eh = mtod(m, struct ether_header *);
			if (ether_cmp(eh->ether_dhost, sc->sc_enaddr) &&
			    ether_cmp(eh->ether_dhost, bcast_enaddr)) {
				m_freem(m);
				continue;
			}
#endif

			/* Pass the packet up. */
			LE_UNLOCK(sc);
			(*ifp->if_input)(ifp, m);
			LE_LOCK(sc);
		} else
Beispiel #3
0
/*
 * Program the macaddress and vlans of a port.
 *
 * Returns 0 on sucess, 1 on failure.
 */
static int
vsw_set_if_hw_addr(vsw_t *vswp)
{
	mac_diag_t		diag;
	uint8_t			*macaddr;
	uint8_t			primary_addr[ETHERADDRL];
	uint16_t		vid = VLAN_ID_NONE;
	int			rv;
	uint16_t		mac_flags = MAC_UNICAST_TAG_DISABLE |
	    MAC_UNICAST_STRIP_DISABLE;

	D1(vswp, "%s: enter", __func__);

	ASSERT(RW_WRITE_HELD(&vswp->maccl_rwlock));
	if (vswp->mch == NULL)
		return (0);

	macaddr = (uint8_t *)vswp->if_addr.ether_addr_octet;

	/* check if it is the primary macaddr of the card. */
	mac_unicast_primary_get(vswp->mh, primary_addr);
	if (ether_cmp((void *)primary_addr, (void*)macaddr) == 0) {
		mac_flags |= MAC_UNICAST_PRIMARY;
	}

	/*
	 * If the interface has a specific 'pvid', then
	 * register with that vlan-id, otherwise register
	 * with VLAN_ID_NONE.
	 */
	if (vswp->pvid != vswp->default_vlan_id) {
		vid = vswp->pvid;
	}

	if (!(vswp->smode & VSW_LAYER2_PROMISC)) {
		mac_flags |= MAC_UNICAST_HW;
	}

	if (vswp->addr_set == B_FALSE) {
		vswp->muh = NULL;
		rv = mac_unicast_add(vswp->mch, macaddr, mac_flags,
		    &vswp->muh, vid, &diag);

		if (rv != 0) {
			cmn_err(CE_WARN, "vsw%d: Failed to program"
			    "macaddr,vid(%s, %d) err=%d",
			    vswp->instance, ether_sprintf((void *)macaddr),
			    vid, rv);
			return (rv);
		}
		vswp->addr_set = B_TRUE;

		D2(vswp, "%s:programmed macaddr(%s) vid(%d) into device %s",
		    __func__, ether_sprintf((void *)macaddr), vid,
		    vswp->physname);
	}

	vsw_mac_add_vlans(vswp, vswp->mch, macaddr, mac_flags,
	    vswp->vids, vswp->nvids);

	vsw_maccl_set_bandwidth(vswp, NULL, VSW_LOCALDEV, vswp->bandwidth);

	mac_rx_set(vswp->mch, vsw_if_rx_cb, (void *)vswp);

	D1(vswp, "%s: exit", __func__);
	return (rv);
}
Beispiel #4
0
static inline void
am79900_rint(struct lance_softc *sc)
{
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m;
	struct lermd rmd;
	uint32_t rmd1;
	int bix, rp;
#if defined(__i386__) && !defined(PC98)
	struct ether_header *eh;
#endif

	bix = sc->sc_last_rd;

	/* Process all buffers with valid data. */
	for (;;) {
		rp = LE_RMDADDR(sc, bix);
		(*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));

		rmd1 = LE_LE32TOH(rmd.rmd1);
		if (rmd1 & LE_R1_OWN)
			break;

		m = NULL;
		if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
		    (LE_R1_STP | LE_R1_ENP)){
			if (rmd1 & LE_R1_ERR) {
#ifdef LEDEBUG
				if (rmd1 & LE_R1_ENP) {
					if ((rmd1 & LE_R1_OFLO) == 0) {
						if (rmd1 & LE_R1_FRAM)
							if_printf(ifp,
							    "framing error\n");
						if (rmd1 & LE_R1_CRC)
							if_printf(ifp,
							    "crc mismatch\n");
					}
				} else
					if (rmd1 & LE_R1_OFLO)
						if_printf(ifp, "overflow\n");
#endif
				if (rmd1 & LE_R1_BUFF)
					if_printf(ifp,
					    "receive buffer error\n");
			} else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
			    (LE_R1_STP | LE_R1_ENP))
				if_printf(ifp, "dropping chained buffer\n");
		} else {
#ifdef LEDEBUG
			if (sc->sc_flags & LE_DEBUG)
				am79900_recv_print(sc, bix);
#endif
			/* Pull the packet off the interface. */
			m = lance_get(sc, LE_RBUFADDR(sc, bix),
			    (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN);
		}

		rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
		    (-LEBLEN & 0xfff));
		rmd.rmd2 = 0;
		rmd.rmd3 = 0;
		(*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));

		if (++bix == sc->sc_nrbuf)
			bix = 0;

		if (m != NULL) {
			ifp->if_ipackets++;

#if defined(__i386__) && !defined(PC98)
			/*
			 * The VMware LANCE does not present IFF_SIMPLEX
			 * behavior on multicast packets. Thus drop the
			 * packet if it is from ourselves.
			 */
			eh = mtod(m, struct ether_header *);
			if (!ether_cmp(eh->ether_shost, sc->sc_enaddr)) {
				m_freem(m);
				continue;
			}
#endif

			/* Pass the packet up. */
			LE_UNLOCK(sc);
			(*ifp->if_input)(ifp, m);
			LE_LOCK(sc);
		} else
Beispiel #5
0
/*
 * Switch the given ethernet frame when operating in layer 2 mode.
 *
 * vswp: pointer to the vsw instance
 * mp: pointer to chain of ethernet frame(s) to be switched
 * caller: identifies the source of this frame as:
 * 		1. VSW_VNETPORT - a vsw port (connected to a vnet).
 *		2. VSW_PHYSDEV - the physical ethernet device
 *		3. VSW_LOCALDEV - vsw configured as a virtual interface
 * arg: argument provided by the caller.
 *		1. for VNETPORT - pointer to the corresponding vsw_port_t.
 *		2. for PHYSDEV - NULL
 *		3. for LOCALDEV - pointer to to this vsw_t(self)
 */
void
vsw_switch_l2_frame(vsw_t *vswp, mblk_t *mp, int caller,
			vsw_port_t *arg, mac_resource_handle_t mrh)
{
	struct ether_header	*ehp;
	mblk_t			*bp, *ret_m;
	vsw_fdbe_t		*fp;

	D1(vswp, "%s: enter (caller %d)", __func__, caller);

	/*
	 * PERF: rather than breaking up the chain here, scan it
	 * to find all mblks heading to same destination and then
	 * pass that sub-chain to the lower transmit functions.
	 */

	/* process the chain of packets */
	bp = mp;
	while (bp) {
		ehp = (struct ether_header *)bp->b_rptr;
		mp = vsw_get_same_dest_list(ehp, &bp);
		ASSERT(mp != NULL);

		D2(vswp, "%s: mblk data buffer %lld : actual data size %lld",
		    __func__, MBLKSIZE(mp), MBLKL(mp));

		if (ether_cmp(&ehp->ether_dhost, &vswp->if_addr) == 0) {
			/*
			 * If destination is VSW_LOCALDEV (vsw as an eth
			 * interface) and if the device is up & running,
			 * send the packet up the stack on this host.
			 * If the virtual interface is down, drop the packet.
			 */
			if (caller != VSW_LOCALDEV) {
				vsw_mac_rx(vswp, mrh, mp, VSW_MACRX_FREEMSG);
			} else {
				freemsgchain(mp);
			}
			continue;
		}

		/*
		 * Find fdb entry for the destination
		 * and hold a reference to it.
		 */
		fp = vsw_fdbe_find(vswp, &ehp->ether_dhost);
		if (fp != NULL) {

			/*
			 * If plumbed and in promisc mode then copy msg
			 * and send up the stack.
			 */
			vsw_mac_rx(vswp, mrh, mp,
			    VSW_MACRX_PROMISC | VSW_MACRX_COPYMSG);

			/*
			 * If the destination is in FDB, the packet
			 * should be forwarded to the correponding
			 * vsw_port (connected to a vnet device -
			 * VSW_VNETPORT)
			 */
			(void) vsw_portsend(fp->portp, mp);

			/* Release the reference on the fdb entry */
			VSW_FDBE_REFRELE(fp);
		} else {
			/*
			 * Destination not in FDB.
			 *
			 * If the destination is broadcast or
			 * multicast forward the packet to all
			 * (VNETPORTs, PHYSDEV, LOCALDEV),
			 * except the caller.
			 */
			if (IS_BROADCAST(ehp)) {
				D2(vswp, "%s: BROADCAST pkt", __func__);
				(void) vsw_forward_all(vswp, mp, caller, arg);
			} else if (IS_MULTICAST(ehp)) {
				D2(vswp, "%s: MULTICAST pkt", __func__);
				(void) vsw_forward_grp(vswp, mp, caller, arg);
			} else {
				/*
				 * If the destination is unicast, and came
				 * from either a logical network device or
				 * the switch itself when it is plumbed, then
				 * send it out on the physical device and also
				 * up the stack if the logical interface is
				 * in promiscious mode.
				 *
				 * NOTE:  The assumption here is that if we
				 * cannot find the destination in our fdb, its
				 * a unicast address, and came from either a
				 * vnet or down the stack (when plumbed) it
				 * must be destinded for an ethernet device
				 * outside our ldoms.
				 */
				if (caller == VSW_VNETPORT) {
					/* promisc check copy etc */
					vsw_mac_rx(vswp, mrh, mp,
					    VSW_MACRX_PROMISC |
					    VSW_MACRX_COPYMSG);

					if ((ret_m = vsw_tx_msg(vswp, mp,
					    caller, arg)) != NULL) {
						DERR(vswp, "%s: drop mblks to "
						    "phys dev", __func__);
						freemsgchain(ret_m);
					}

				} else if (caller == VSW_PHYSDEV) {
					/*
					 * Pkt seen because card in promisc
					 * mode. Send up stack if plumbed in
					 * promisc mode, else drop it.
					 */
					vsw_mac_rx(vswp, mrh, mp,
					    VSW_MACRX_PROMISC |
					    VSW_MACRX_FREEMSG);

				} else if (caller == VSW_LOCALDEV) {
					/*
					 * Pkt came down the stack, send out
					 * over physical device.
					 */
					if ((ret_m = vsw_tx_msg(vswp, mp,
					    caller, NULL)) != NULL) {
						DERR(vswp, "%s: drop mblks to "
						    "phys dev", __func__);
						freemsgchain(ret_m);
					}
				}
			}
		}
	}
	D1(vswp, "%s: exit\n", __func__);
}