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

📄 an.c

📁 linux 下通过802.1认证的安装包
💻 C
📖 第 1 页 / 共 3 页
字号:

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

	for (i = AN_TIMEOUT; i--; DELAY(10)) {
		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_CMD)
			break;
		else {
			if (CSR_READ_2(sc, AN_COMMAND) == cmd) {
				DELAY(10);
				CSR_WRITE_2(sc, AN_COMMAND, cmd);
			}
		}
	}

	stat = CSR_READ_2(sc, AN_STATUS);

	/* clear stuck command busy if needed */
	if (CSR_READ_2(sc, AN_COMMAND) & AN_CMD_BUSY) {
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_CLR_STUCK_BUSY);
	}

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

	if (i <= 0)
		return(ETIMEDOUT);

	if (stat & AN_STAT_CMD_RESULT)
		return(EIO);

	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.
 */
void
an_reset(sc)
	struct an_softc		*sc;
{
	if (sc->an_gone)
		return;
/*printf("ena ");*/
	an_cmd(sc, AN_CMD_ENABLE, 0);
/* printf("rst ");*/
	an_cmd(sc, AN_CMD_FW_RESTART, 0);
/*printf("nop ");*/
	an_cmd(sc, AN_CMD_NOOP2, 0);

	if (an_cmd(sc, AN_CMD_FORCE_SYNCLOSS, 0) == ETIMEDOUT)
		printf("%s: reset failed\n", sc->sc_dev.dv_xname);

	an_cmd(sc, AN_CMD_DISABLE, 0);
}

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

	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("%s: RID 0x%04x access failed\n",
		    sc->sc_dev.dv_xname, ltv->an_type);
		return(EIO);
	}

	/* Seek to the record. */
	if (an_seek(sc, ltv->an_type, 0, AN_BAP1)) {
		printf("%s: RID 0x%04x seek to record failed\n",
		    sc->sc_dev.dv_xname, ltv->an_type);
		return(EIO);
	}

	/*
	 * Read the length to make sure it
	 * matches what we expect (this verifies that we have enough
	 * room to hold all of the returned data).
	 */
	len = CSR_READ_2(sc, AN_DATA1);

	/*
	 * Work out record's data length, which is struct length - type word
	 * as we have just read the length.
	 */
	ltv_data_length = ltv->an_len - sizeof(u_int16_t);

	if (len > ltv_data_length) {
		printf("%s: RID 0x%04x record length mismatch -- expected %d, "
		    "got %d\n", sc->sc_dev.dv_xname, ltv->an_type,
		    ltv_data_length, len);
		return(ENOSPC);
	}

	/* Now read the data. */
	ptr = ltv->an_val;
	for (i = 0; i < (len - 1) >> 1; i++)
		ptr[i] = CSR_READ_2(sc, AN_DATA1);

#if BYTE_ORDER == BIG_ENDIAN
	switch (ltv->an_type) {
	case AN_RID_GENCONFIG:
		an_swap16(&ltv->an_val[4], 7); /* an_macaddr, an_rates */
		an_swap16(&ltv->an_val[63], 8);  /* an_nodename */
		break;
	case AN_RID_SSIDLIST:
		an_swap16(&ltv->an_val[1], 16); /* an_ssid1 */
		an_swap16(&ltv->an_val[18], 16); /* an_ssid2 */
		an_swap16(&ltv->an_val[35], 16); /* an_ssid3 */
		break;
	case AN_RID_APLIST:
		an_swap16(ltv->an_val, 12);
		break;
	case AN_RID_DRVNAME:
		an_swap16(ltv->an_val, 8);
		break;
	case AN_RID_CAPABILITIES:
		an_swap16(ltv->an_val, 2);	/* an_oui */
		an_swap16(&ltv->an_val[3], 34); /* an_manufname .. an_aironetaddr */
		an_swap16(&ltv->an_val[39], 8); /* an_callid .. an_tx_diversity */
		break;
	case AN_RID_STATUS:
		an_swap16(&ltv->an_val[0], 3);	/* an_macaddr */
		an_swap16(&ltv->an_val[7], 36);	/* an_ssid .. an_prev_bssid3 */
		an_swap16(&ltv->an_val[0x74/2], 2);	/* an_ap_ip_addr */
		break;
	case AN_RID_WEP_VOLATILE:
	case AN_RID_WEP_PERMANENT:
		an_swap16(&ltv->an_val[1], 3);	/* an_mac_addr */
		an_swap16(&ltv->an_val[5], 6);
		break;
	case AN_RID_32BITS_CUM:
		for (i = 0x60; i--; ) {
			u_int16_t t = ltv->an_val[i * 2] ^ ltv->an_val[i * 2 + 1];
			ltv->an_val[i * 2] ^= t;
			ltv->an_val[i * 2 + 1] ^= t;
		}
		break;
	}
#endif
	return(0);
}

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

	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);

#if BYTE_ORDER == BIG_ENDIAN
	switch (ltv->an_type) {
	case AN_RID_GENCONFIG:
		an_swap16(&ltv->an_val[4], 7); /* an_macaddr, an_rates */
		an_swap16(&ltv->an_val[63], 8);  /* an_nodename */
		break;
	case AN_RID_SSIDLIST:
		an_swap16(&ltv->an_val[1], 16); /* an_ssid1 */
		an_swap16(&ltv->an_val[18], 16); /* an_ssid2 */
		an_swap16(&ltv->an_val[35], 16); /* an_ssid3 */
		break;
	case AN_RID_APLIST:
		an_swap16(ltv->an_val, 12);
		break;
	case AN_RID_DRVNAME:
		an_swap16(ltv->an_val, 8);
		break;
	case AN_RID_CAPABILITIES:
		an_swap16(ltv->an_val, 2);	/* an_oui */
		an_swap16(&ltv->an_val[3], 34); /* an_manufname .. an_aironetaddr */
		an_swap16(&ltv->an_val[39], 8); /* an_callid .. an_tx_diversity */
		break;
	case AN_RID_STATUS:
		an_swap16(&ltv->an_val[0], 3);	/* an_macaddr */
		an_swap16(&ltv->an_val[7], 36);	/* an_ssid .. an_prev_bssid3 */
		an_swap16(&ltv->an_val[0x74/2], 2);	/* an_ap_ip_addr */
		break;
	case AN_RID_WEP_VOLATILE:
	case AN_RID_WEP_PERMANENT:
		an_swap16(&ltv->an_val[1], 3);	/* an_mac_addr */
		an_swap16(&ltv->an_val[5], 6);
		break;
	}
#endif

	CSR_WRITE_2(sc, AN_DATA1, ltv->an_len);

	ptr = ltv->an_val;
	for (i = 0; i < (ltv->an_len - 1) >> 1; i++)
		CSR_WRITE_2(sc, AN_DATA1, ptr[i]);

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

	return(0);
}

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("%s: invalid data path: %x\n",
		    sc->sc_dev.dv_xname, chan);
		return (EIO);
	}

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

	for (i = AN_TIMEOUT; i--; DELAY(10)) {
		if (!(CSR_READ_2(sc, offreg) & (AN_OFF_BUSY|AN_OFF_ERR)))
			break;
	}

	if (i <= 0)
		return(ETIMEDOUT);

	return (0);
}

int
an_read_data(sc, id, off, buf, len)
	struct an_softc		*sc;
	int			id, off;
	caddr_t			buf;
	int			len;
{
	if (off != -1 && an_seek(sc, id, off, AN_BAP1))
		return(EIO);

	bus_space_read_raw_multi_2(sc->an_btag, sc->an_bhandle,
	    AN_DATA1, buf, len & ~1);
	if (len & 1)
	        ((u_int8_t *)buf)[len - 1] = CSR_READ_1(sc, AN_DATA1);

	return (0);
}

int
an_write_data(sc, id, off, buf, len)
	struct an_softc		*sc;
	int			id, off;
	caddr_t			buf;
	int			len;
{
	if (off != -1 && an_seek(sc, id, off, AN_BAP0))
		return(EIO);

	bus_space_write_raw_multi_2(sc->an_btag, sc->an_bhandle,
	    AN_DATA0, buf, len & ~1);
	if (len & 1)
	        CSR_WRITE_1(sc, AN_DATA0, ((u_int8_t *)buf)[len - 1]);

	return (0);
}

/*
 * Allocate a region of memory inside the NIC and zero
 * it out.
 */
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("%s: failed to allocate %d bytes on NIC\n",
		    sc->sc_dev.dv_xname, len);
		return(ENOMEM);
	}

	for (i = AN_TIMEOUT; i--; DELAY(10)) {
		if (CSR_READ_2(sc, AN_EVENT_STAT) & AN_EV_ALLOC)
			break;
	}

	if (i <= 0)
		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);

	bus_space_set_multi_2(sc->an_btag, sc->an_bhandle,
	    AN_DATA0, 0, len / 2);
	CSR_WRITE_1(sc, AN_DATA0, 0);

	return(0);
}

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;
	extern struct ifaddr	**ifnet_addrs;

	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];
		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;
	case AN_RID_SSIDLIST:
		ssid = (struct an_ltv_ssidlist *)areq;
		bcopy((char *)ssid, (char *)&sc->an_ssidlist,
			sizeof(struct an_ltv_ssidlist));
		break;
	case AN_RID_APLIST:
		ap = (struct an_ltv_aplist *)areq;
		bcopy((char *)ap, (char *)&sc->an_aplist,
			sizeof(struct an_ltv_aplist));
		break;
	case AN_RID_TX_SPEED:
		sp = (struct an_ltv_gen *)areq;
		sc->an_tx_rate = sp->an_val[0];
		break;
	case AN_RID_WEP_VOLATILE:
		/* Disable the MAC */
		an_cmd(sc, AN_CMD_DISABLE, 0);

		/* Just write the key, we dont' want to save it */
		an_write_record(sc, (struct an_ltv_gen *)areq);

		/* Turn the MAC back on */
		an_cmd(sc, AN_CMD_ENABLE, 0);

		break;
	case AN_RID_WEP_PERMANENT:
		/* Disable the MAC */
	  //		an_cmd(sc, AN_CMD_DISABLE, 0);
		/* Just write the key, the card will save it in this mode */
		an_write_record(sc, (struct an_ltv_gen *)areq);

		/* Turn the MAC back on */
		//		an_cmd(sc, AN_CMD_ENABLE, 0);
		return;
		break;
	default:
		printf("%s: unknown RID: %x\n",
		    sc->sc_dev.dv_xname, areq->an_type);
		return;
	}

	/* Reinitialize the card. */
	if (ifp->if_flags & IFF_UP)                
		an_init(sc);
}

/*
 * We can't change the NIC configuration while the MAC is enabled,
 * so in order to turn on RX monitor mode, we have to turn the MAC
 * off first.
 */
void
an_promisc(sc, promisc)
	struct an_softc		*sc;
	int			promisc;
{
	struct an_ltv_genconfig genconf;

	/* Disable the MAC. */
	an_cmd(sc, AN_CMD_DISABLE, 0);

	/* Set RX mode. */
	if (promisc &&
	    !(sc->an_config.an_rxmode & AN_RXMODE_LAN_MONITOR_CURBSS) ) {
		sc->an_rxmode = sc->an_config.an_rxmode;
		sc->an_config.an_rxmode |=
		    AN_RXMODE_LAN_MONITOR_CURBSS;
	} else {
		sc->an_config.an_rxmode = sc->an_rxmode;
	}

	/* Transfer the configuration to the NIC */
	genconf = sc->an_config;
	genconf.an_len = sizeof(struct an_ltv_genconfig);
	genconf.an_type = AN_RID_GENCONFIG;
	if (an_write_record(sc, (struct an_ltv_gen *)&genconf)) {
		printf("%s: failed to set configuration\n",
		    sc->sc_dev.dv_xname);
		return;
	}
	/* Turn the MAC back on. */
	an_cmd(sc, AN_CMD_ENABLE, 0);
}

int
an_ioctl(ifp, command, data)
	struct ifnet		*ifp;
	u_long			command;
	caddr_t			data;
{
	int			s, error = 0;
	struct an_softc		*sc;
	struct an_req		areq;
	struct ifreq		*ifr;
	struct proc		*p = curproc;
	struct ifaddr		*ifa = (struct ifaddr *)data;

	s = splimp();

	sc = ifp->if_softc;
	ifr = (struct ifreq *)data;

	if (sc->an_gone) {
		splx(s);
		return(ENODEV);
	}

	if ((error = ether_ioctl(ifp, &sc->arpcom, command, data)) > 0) {
		splx(s);
		return error;
	}

	switch(command) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		switch (ifa->ifa_addr->sa_family) {
#ifdef INET
		case AF_INET:
			an_init(sc);
			arp_ifinit(&sc->arpcom, ifa);
			break;
#endif
		default:
			an_init(sc);
			break;
		}
		break;
	case SIOCSIFFLAGS:
		if (ifp->if_flags & IFF_UP) {
			if (ifp->if_flags & IFF_RUNNING &&
			    ifp->if_flags & IFF_PROMISC &&
			    !(sc->an_if_flags & IFF_PROMISC)) {
				an_promisc(sc, 1);
			} else if (ifp->if_flags & IFF_RUNNING &&
			    !(ifp->if_flags & IFF_PROMISC) &&
			    sc->an_if_flags & IFF_PROMISC) {
				an_promisc(sc, 0);
				an_reset(sc);
			}
			an_init(sc);
		} else {
			if (ifp->if_flags & IFF_RUNNING)
				an_stop(sc);
		}
		sc->an_if_flags = ifp->if_flags;
		error = 0;
		break;
	case SIOCSIFMEDIA:
	case SIOCGIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->an_ifmedia, command);
		break;
	case SIOCADDMULTI:
	case SIOCDELMULTI:
		/* The Aironet has no multicast filter. */
		error = 0;
		break;
	case SIOCGAIRONET:
		error = copyin(ifr->ifr_data, &areq, sizeof(areq));
		if (error)
			break;
#ifdef ANCACHE
		if (areq.an_type == AN_RID_ZERO_CACHE) {
			error = suser(p->p_ucred, &p->p_acflag);
			if (error)
				break;
			sc->an_sigitems = sc->an_nextitem = 0;
			break;
		} else if (areq.an_type == AN_RID_READ_CACHE) {
			char *pt = (char *)&areq.an_val;
			bcopy((char *)&sc->an_sigitems, (char *)pt,
			    sizeof(int));
			pt += sizeof(int);
			areq.an_len = sizeof(int) / 2;
			bcopy((char *)&sc->an_sigcache, (char *)pt,
			    sizeof(struct an_sigcache) * sc->an_sigitems);

⌨️ 快捷键说明

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