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

📄 if_an.c

📁 linux 下通过802.1认证的安装包
💻 C
📖 第 1 页 / 共 4 页
字号:
		MGETHDR(m, M_DONTWAIT, MT_DATA);
		if (m == NULL) {
			ifp->if_ierrors++;
			return;
		}
		MCLGET(m, M_DONTWAIT);
		if (!(m->m_flags & M_EXT)) {
			m_freem(m);
			ifp->if_ierrors++;
			return;
		}
		m->m_pkthdr.rcvif = ifp;
		/* Read Ethenet encapsulated packet */

#ifdef ANCACHE
		/* Read NIC frame header */
		if (an_read_data(sc, id, 0, (caddr_t) & rx_frame, sizeof(rx_frame))) {
			ifp->if_ierrors++;
			return;
		}
#endif
		/* Read in the 802_3 frame header */
		if (an_read_data(sc, id, 0x34, (caddr_t) & rx_frame_802_3,
				 sizeof(rx_frame_802_3))) {
			ifp->if_ierrors++;
			return;
		}
		if (rx_frame_802_3.an_rx_802_3_status != 0) {
			ifp->if_ierrors++;
			return;
		}
		/* Check for insane frame length */
		if (rx_frame_802_3.an_rx_802_3_payload_len > MCLBYTES) {
			ifp->if_ierrors++;
			return;
		}
		m->m_pkthdr.len = m->m_len =
			rx_frame_802_3.an_rx_802_3_payload_len + 12;

		eh = mtod(m, struct ether_header *);

		bcopy((char *)&rx_frame_802_3.an_rx_dst_addr,
		      (char *)&eh->ether_dhost, ETHER_ADDR_LEN);
		bcopy((char *)&rx_frame_802_3.an_rx_src_addr,
		      (char *)&eh->ether_shost, ETHER_ADDR_LEN);

		/* in mbuf header type is just before payload */
		error = an_read_data(sc, id, 0x44, (caddr_t)&(eh->ether_type),
				     rx_frame_802_3.an_rx_802_3_payload_len);

		if (error) {
			m_freem(m);
			ifp->if_ierrors++;
			return;
		}
		ifp->if_ipackets++;

		/* Receive packet. */
		m_adj(m, sizeof(struct ether_header));
#ifdef ANCACHE
		an_cache_store(sc, eh, m, rx_frame.an_rx_signal_strength);
#endif
		ether_input(ifp, eh, m);
	}
}

static void
an_txeof(sc, status)
	struct an_softc		*sc;
	int			status;
{
	struct ifnet		*ifp;
	int			id, i;

	ifp = &sc->arpcom.ac_if;

	ifp->if_timer = 0;
	ifp->if_flags &= ~IFF_OACTIVE;

	id = CSR_READ_2(sc, AN_TX_CMP_FID);

	if (status & AN_EV_TX_EXC) {
		ifp->if_oerrors++;
	} else
		ifp->if_opackets++;

	for (i = 0; i < AN_TX_RING_CNT; i++) {
		if (id == sc->an_rdata.an_tx_ring[i]) {
			sc->an_rdata.an_tx_ring[i] = 0;
			break;
		}
	}

	AN_INC(sc->an_rdata.an_tx_cons, AN_TX_RING_CNT);

	return;
}

/*
 * We abuse the stats updater to check the current NIC status. This
 * is important because we don't want to allow transmissions until
 * the NIC has synchronized to the current cell (either as the master
 * in an ad-hoc group, or as a station connected to an access point).
 */
void
an_stats_update(xsc)
	void			*xsc;
{
	struct an_softc		*sc;
	struct ifnet		*ifp;
	int			s;

	s = splimp();

	sc = xsc;
	ifp = &sc->arpcom.ac_if;

	sc->an_status.an_type = AN_RID_STATUS;
	sc->an_status.an_len = sizeof(struct an_ltv_status);
	an_read_record(sc, (struct an_ltv_gen *)&sc->an_status);

	if (sc->an_status.an_opmode & AN_STATUS_OPMODE_IN_SYNC)
		sc->an_associated = 1;
	else
		sc->an_associated = 0;

	/* Don't do this while we're transmitting */
	if (ifp->if_flags & IFF_OACTIVE) {
		sc->an_stat_ch = timeout(an_stats_update, sc, hz);
		splx(s);
		return;
	}

	sc->an_stats.an_len = sizeof(struct an_ltv_stats);
	sc->an_stats.an_type = AN_RID_32BITS_CUM;
	an_read_record(sc, (struct an_ltv_gen *)&sc->an_stats.an_len);

	sc->an_stat_ch = timeout(an_stats_update, sc, hz);
	splx(s);

	return;
}

void
an_intr(xsc)
	void			*xsc;
{
	struct an_softc		*sc;
	struct ifnet		*ifp;
	u_int16_t		status;

	sc = (struct an_softc*)xsc;

	if (sc->an_gone)
		return;

	ifp = &sc->arpcom.ac_if;

	/* Disable interrupts. */
	CSR_WRITE_2(sc, AN_INT_EN, 0);

	status = CSR_READ_2(sc, AN_EVENT_STAT);
	CSR_WRITE_2(sc, AN_EVENT_ACK, ~AN_INTRS);

	if (status & AN_EV_AWAKE) {
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_AWAKE);
	}

	if (status & AN_EV_LINKSTAT) {
		if (CSR_READ_2(sc, AN_LINKSTAT) == AN_LINKSTAT_ASSOCIATED)
			sc->an_associated = 1;
		else
			sc->an_associated = 0;
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_LINKSTAT);
	}

	if (status & AN_EV_RX) {
		an_rxeof(sc);
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
	}

	if (status & AN_EV_TX) {
		an_txeof(sc, status);
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX);
	}

	if (status & AN_EV_TX_EXC) {
		an_txeof(sc, status);
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_TX_EXC);
	}

	if (status & AN_EV_ALLOC)
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);

	/* Re-enable interrupts. */
	CSR_WRITE_2(sc, AN_INT_EN, AN_INTRS);

	if ((ifp->if_flags & IFF_UP) && (ifp->if_snd.ifq_head != NULL))
		an_start(ifp);

	return;
}

static int
an_cmd(sc, cmd, val)
	struct an_softc		*sc;
	int			cmd;
	int			val;
{
	int			i, s = 0;

	CSR_WRITE_2(sc, AN_PARAM0, val);
	CSR_WRITE_2(sc, AN_PARAM1, 0);
	CSR_WRITE_2(sc, AN_PARAM2, 0);
	CSR_WRITE_2(sc, AN_COMMAND, cmd);

	for (i = 0; i < AN_TIMEOUT; i++) {
		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
			break;
		else {
			if (CSR_READ_2(sc, AN_COMMAND) == cmd)
				CSR_WRITE_2(sc, AN_COMMAND, cmd);
		}
	}

	for (i = 0; i < AN_TIMEOUT; i++) {
		CSR_READ_2(sc, AN_RESP0);
		CSR_READ_2(sc, AN_RESP1);
		CSR_READ_2(sc, AN_RESP2);
		s = CSR_READ_2(sc, AN_STATUS);
		if ((s & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
			break;
	}

	/* Ack the command */
	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CMD);

	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY)
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);

	if (i == AN_TIMEOUT)
		return(ETIMEDOUT);

	return(0);
}

/*
 * This reset sequence may look a little strange, but this is the
 * most reliable method I've found to really kick the NIC in the
 * head and force it to reboot correctly.
 */
static void
an_reset(sc)
	struct an_softc		*sc;
{
	if (sc->an_gone)
		return;

	an_cmd(sc, AN_CMD_ENABLE, 0);
	an_cmd(sc, AN_CMD_FW_RESTART, 0);
	an_cmd(sc, AN_CMD_NOOP2, 0);

	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
		printf("an%d: reset failed\n", sc->an_unit);

	an_cmd(sc, AN_CMD_DISABLE, 0);

	return;
}

/*
 * Read an LTV record from the NIC.
 */
static int
an_read_record(sc, ltv)
	struct an_softc		*sc;
	struct an_ltv_gen	*ltv;
{
	u_int16_t		*ptr;
	u_int8_t		*ptr2;
	int			i, len;

	if (ltv->an_len < 4 || ltv->an_type == 0)
		return(EINVAL);

	/* Tell the NIC to enter record read mode. */
	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type)) {
		printf("an%d: RID access failed\n", sc->an_unit);
		return(EIO);
	}

	/* Seek to the record. */
	if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
		printf("an%d: seek to record failed\n", sc->an_unit);
		return(EIO);
	}

	/*
	 * Read the length and record type and make sure they
	 * match what we expect (this verifies that we have enough
	 * room to hold all of the returned data).
	 * Length includes type but not length.
	 */
	len = CSR_READ_2(sc, AN_DATA1);
	if (len > (ltv->an_len - 2)) {
		printf("an%d: record length mismatch -- expected %d, "
		    "got %d for Rid %x\n", sc->an_unit,
		    ltv->an_len - 2, len, ltv->an_type);
		len = ltv->an_len - 2;
	} else {
		ltv->an_len = len + 2;
	}

	/* Now read the data. */
	len -= 2;	/* skip the type */
	ptr = &ltv->an_val;
	for (i = len; i > 1; i -= 2)
		*ptr++ = CSR_READ_2(sc, AN_DATA1);
	if (i) {
		ptr2 = (u_int8_t *)ptr;
		*ptr2 = CSR_READ_1(sc, AN_DATA1);
	}
	if (an_dump)
		an_dump_record(sc, ltv, "Read");

	return(0);
}

/*
 * Same as read, except we inject data instead of reading it.
 */
static int
an_write_record(sc, ltv)
	struct an_softc		*sc;
	struct an_ltv_gen	*ltv;
{
	u_int16_t		*ptr;
	u_int8_t		*ptr2;
	int			i, len;

	if (an_dump)
		an_dump_record(sc, ltv, "Write");

	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_READ, ltv->an_type))
		return(EIO);

	if (an_seek(sc, ltv->an_type, 0, AN_BAP1))
		return(EIO);

	/*
	 * Length includes type but not length.
	 */
	len = ltv->an_len - 2;
	CSR_WRITE_2(sc, AN_DATA1, len);

	len -= 2;	/* skip the type */
	ptr = &ltv->an_val;
	for (i = len; i > 1; i -= 2)
		CSR_WRITE_2(sc, AN_DATA1, *ptr++);
	if (i) {
		ptr2 = (u_int8_t *)ptr;
		CSR_WRITE_1(sc, AN_DATA0, *ptr2);
	}

	if (an_cmd(sc, AN_CMD_ACCESS|AN_ACCESS_WRITE, ltv->an_type))
		return(EIO);

	return(0);
}

static void
an_dump_record(sc, ltv, string)
	struct an_softc		*sc;
	struct an_ltv_gen	*ltv;
	char			*string;
{
	u_int8_t		*ptr2;
	int			len;
	int			i;
	int			count = 0;
	char			buf[17], temp;

	len = ltv->an_len - 4;
	printf("an%d: RID %4x, Length %4d, Mode %s\n",
		sc->an_unit, ltv->an_type, ltv->an_len - 4, string);

	if (an_dump == 1 || (an_dump == ltv->an_type)) {
		printf("an%d:\t", sc->an_unit);
		bzero(buf,sizeof(buf));

		ptr2 = (u_int8_t *)&ltv->an_val;
		for (i = len; i > 0; i--) {
			printf("%02x ", *ptr2);

			temp = *ptr2++;
			if (temp >= ' ' && temp <= '~')
				buf[count] = temp;
			else if (temp >= 'A' && temp <= 'Z')
				buf[count] = temp;
			else
				buf[count] = '.';
			if (++count == 16) {
				count = 0;
				printf("%s\n",buf);
				printf("an%d:\t", sc->an_unit);
				bzero(buf,sizeof(buf));
			}
		}
		for (; count != 16; count++) {
			printf("   ");
		}
		printf(" %s\n",buf);
	}
}

static int
an_seek(sc, id, off, chan)
	struct an_softc		*sc;
	int			id, off, chan;
{
	int			i;
	int			selreg, offreg;

	switch (chan) {
	case AN_BAP0:
		selreg = AN_SEL0;
		offreg = AN_OFF0;
		break;
	case AN_BAP1:
		selreg = AN_SEL1;
		offreg = AN_OFF1;
		break;
	default:
		printf("an%d: invalid data path: %x\n", sc->an_unit, chan);
		return(EIO);
	}

	CSR_WRITE_2(sc, selreg, id);
	CSR_WRITE_2(sc, offreg, off);

	for (i = 0; i < AN_TIMEOUT; i++) {
		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
			break;
	}

	if (i == AN_TIMEOUT)
		return(ETIMEDOUT);

	return(0);
}

static int
an_read_data(sc, id, off, buf, len)
	struct an_softc		*sc;
	int			id, off;
	caddr_t			buf;
	int			len;
{
	int			i;
	u_int16_t		*ptr;
	u_int8_t		*ptr2;

	if (off != -1) {
		if (an_seek(sc, id, off, AN_BAP1))
			return(EIO);
	}

	ptr = (u_int16_t *)buf;
	for (i = len; i > 1; i -= 2)
		*ptr++ = CSR_READ_2(sc, AN_DATA1);
	if (i) {
		ptr2 = (u_int8_t *)ptr;
		*ptr2 = CSR_READ_1(sc, AN_DATA1);
	}

	return(0);
}

static int
an_write_data(sc, id, off, buf, len)
	struct an_softc		*sc;
	int			id, off;
	caddr_t			buf;
	int			len;
{
	int			i;
	u_int16_t		*ptr;
	u_int8_t		*ptr2;

	if (off != -1) {
		if (an_seek(sc, id, off, AN_BAP0))
			return(EIO);
	}

	ptr = (u_int16_t *)buf;
	for (i = len; i > 1; i -= 2)
		CSR_WRITE_2(sc, AN_DATA0, *ptr++);
	if (i) {
	        ptr2 = (u_int8_t *)ptr;
	        CSR_WRITE_1(sc, AN_DATA0, *ptr2);
	}

	return(0);
}

/*
 * Allocate a region of memory inside the NIC and zero
 * it out.
 */
static int
an_alloc_nicmem(sc, len, id)
	struct an_softc		*sc;
	int			len;
	int			*id;
{
	int			i;

	if (an_cmd(sc, AN_CMD_ALLOC_MEM, len)) {
		printf("an%d: failed to allocate %d bytes on NIC\n",
		    sc->an_unit, len);
		return(ENOMEM);
	}

	for (i = 0; i < AN_TIMEOUT; i++) {
		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
			break;
	}

	if (i == AN_TIMEOUT)
		return(ETIMEDOUT);

	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_ALLOC);
	*id = CSR_READ_2(sc, AN_ALLOC_FID);

	if (an_seek(sc, *id, 0, AN_BAP0))
		return(EIO);

	for (i = 0; i < len / 2; i++)
		CSR_WRITE_2(sc, AN_DATA0, 0);

	return(0);
}

static void
an_setdef(sc, areq)
	struct an_softc		*sc;
	struct an_req		*areq;
{
	struct sockaddr_dl	*sdl;
	struct ifaddr		*ifa;
	struct ifnet		*ifp;
	struct an_ltv_genconfig	*cfg;
	struct an_ltv_ssidlist	*ssid;
	struct an_ltv_aplist	*ap;
	struct an_ltv_gen	*sp;

	ifp = &sc->arpcom.ac_if;

	switch (areq->an_type) {
	case AN_RID_GENCONFIG:
		cfg = (struct an_ltv_genconfig *)areq;

		ifa = ifnet_addrs[ifp->if_index - 1];
		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
		bcopy((char *)&cfg->an_macaddr, (char *)&sc->arpcom.ac_enaddr,
		    ETHER_ADDR_LEN);
		bcopy((char *)&cfg->an_macaddr, LLADDR(sdl), ETHER_ADDR_LEN);

		bcopy((char *)cfg, (char *)&sc->an_config,
			sizeof(struct an_ltv_genconfig));
		break;

⌨️ 快捷键说明

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