示例#1
0
文件: if_rtwn.c 项目: mosconi/openbsd
void
rtwn_reset_tx_list(struct rtwn_pci_softc *sc, int qid)
{
	struct ieee80211com *ic = &sc->sc_sc.sc_ic;
	struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
	int i;

	for (i = 0; i < RTWN_TX_LIST_COUNT; i++) {
		struct r92c_tx_desc_pci *desc = &tx_ring->desc[i];
		struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i];

		memset(desc, 0, sizeof(*desc) -
		    (sizeof(desc->reserved) + sizeof(desc->nextdescaddr64) +
		    sizeof(desc->nextdescaddr)));

		if (tx_data->m != NULL) {
			bus_dmamap_unload(sc->sc_dmat, tx_data->map);
			m_freem(tx_data->m);
			tx_data->m = NULL;
			ieee80211_release_node(ic, tx_data->ni);
			tx_data->ni = NULL;
		}
	}

	bus_dmamap_sync(sc->sc_dmat, tx_ring->map, 0, MCLBYTES,
	    BUS_DMASYNC_POSTWRITE);

	sc->qfullmsk &= ~(1 << qid);
	tx_ring->queued = 0;
	tx_ring->cur = 0;
}
UInt32 VoodooIntel3945::outputPacket( mbuf_t m, void* param ) {
	struct wpi_softc* sc = &fSelfData;
	struct ieee80211com* ic = &sc->sc_ic;
	struct ieee80211_node *ni;
	
	DPRINTF(("TX: mbuf len=%u\n", mbuf_len(m)));
	
	if (m == 0)
		return kIOReturnOutputDropped; // ???
	
	ExtraMbufParams* p = (ExtraMbufParams*)param;
	if (p->is80211ManagementFrame) {
		ni = (struct ieee80211_node *)mbuf_pkthdr_rcvif(m);
	} else {
		if (sc->qfullmsk != 0) {
			freePacket(m);
			return kIOReturnOutputDropped;
		}
		
		if (ic->ic_state != IEEE80211_S_RUN) {
			freePacket(m);
			return kIOReturnOutputDropped;
		}
		
		/* Encapsulate and send data frames. */
		if ((m = ieee80211_encap(ic, m, &ni)) == NULL)
			return kIOReturnOutputDropped;
	}
				
	if (wpi_tx(sc, m, ni) != 0) {
		ieee80211_release_node(ic, ni);
		if (m) freePacket(m);
		return kIOReturnOutputDropped;
	} else {
		DPRINTF(("(prev tx success)\n"));
		sc->sc_tx_timer = 5;
		return kIOReturnOutputSuccess;
	}
}
int
ieee80211_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct ieee80211com *ic = (void *)ifp;
	struct ifreq *ifr = (struct ifreq *)data;
	int i, error = 0;
	struct ieee80211_nwid nwid;
	struct ieee80211_wpapsk *psk;
	struct ieee80211_wmmparams *wmm;
	struct ieee80211_power *power;
	struct ieee80211_bssid *bssid;
	struct ieee80211chanreq *chanreq;
	struct ieee80211_channel *chan;
	struct ieee80211_txpower *txpower;
	static const u_int8_t empty_macaddr[IEEE80211_ADDR_LEN] = {
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	struct ieee80211_nodereq *nr, nrbuf;
	struct ieee80211_nodereq_all *na;
	struct ieee80211_node *ni;
	u_int32_t flags;

	switch (cmd) {
	case SIOCSIFADDR:
	case SIOCGIFADDR:
		error = ether_ioctl(ifp, &ic->ic_ac, cmd, data);
		break;
	case SIOCSIFMEDIA:
	case SIOCGIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
		break;
	case SIOCS80211NWID:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if ((error = copyin(ifr->ifr_data, &nwid, sizeof(nwid))) != 0)
			break;
		if (nwid.i_len > IEEE80211_NWID_LEN) {
			error = EINVAL;
			break;
		}
		memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
		ic->ic_des_esslen = nwid.i_len;
		memcpy(ic->ic_des_essid, nwid.i_nwid, nwid.i_len);
		error = ENETRESET;
		break;
	case SIOCG80211NWID:
		memset(&nwid, 0, sizeof(nwid));
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			nwid.i_len = ic->ic_des_esslen;
			memcpy(nwid.i_nwid, ic->ic_des_essid, nwid.i_len);
			break;
		default:
			nwid.i_len = ic->ic_bss->ni_esslen;
			memcpy(nwid.i_nwid, ic->ic_bss->ni_essid, nwid.i_len);
			break;
		}
		error = copyout(&nwid, ifr->ifr_data, sizeof(nwid));
		break;
	case SIOCS80211NWKEY:
		if ((error = suser(curproc, 0)) != 0)
			break;
		error = ieee80211_ioctl_setnwkeys(ic, (void *)data);
		break;
	case SIOCG80211NWKEY:
		error = ieee80211_ioctl_getnwkeys(ic, (void *)data);
		break;
	case SIOCS80211WMMPARMS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (!(ic->ic_flags & IEEE80211_C_QOS)) {
			error = ENODEV;
			break;
		}
		wmm = (struct ieee80211_wmmparams *)data;
		if (wmm->i_enabled)
			ic->ic_flags |= IEEE80211_F_QOS;
		else
			ic->ic_flags &= ~IEEE80211_F_QOS;
		error = ENETRESET;
		break;
	case SIOCG80211WMMPARMS:
		wmm = (struct ieee80211_wmmparams *)data;
		wmm->i_enabled = (ic->ic_flags & IEEE80211_F_QOS) ? 1 : 0;
		break;
	case SIOCS80211WPAPARMS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		error = ieee80211_ioctl_setwpaparms(ic, (void *)data);
		break;
	case SIOCG80211WPAPARMS:
		error = ieee80211_ioctl_getwpaparms(ic, (void *)data);
		break;
	case SIOCS80211WPAPSK:
		if ((error = suser(curproc, 0)) != 0)
			break;
		psk = (struct ieee80211_wpapsk *)data;
		if (psk->i_enabled) {
			ic->ic_flags |= IEEE80211_F_PSK;
			memcpy(ic->ic_psk, psk->i_psk, sizeof(ic->ic_psk));
		} else {
			ic->ic_flags &= ~IEEE80211_F_PSK;
			memset(ic->ic_psk, 0, sizeof(ic->ic_psk));
		}
		error = ENETRESET;
		break;
	case SIOCG80211WPAPSK:
		psk = (struct ieee80211_wpapsk *)data;
		if (ic->ic_flags & IEEE80211_F_PSK) {
			psk->i_enabled = 1;
			/* do not show any keys to non-root user */
			if (suser(curproc, 0) != 0) {
				psk->i_enabled = 2;
				memset(psk->i_psk, 0, sizeof(psk->i_psk));
				break;	/* return ok but w/o key */
			}
			memcpy(psk->i_psk, ic->ic_psk, sizeof(psk->i_psk));
		} else
			psk->i_enabled = 0;
		break;
	case SIOCS80211POWER:
		if ((error = suser(curproc, 0)) != 0)
			break;
		power = (struct ieee80211_power *)data;
		ic->ic_lintval = power->i_maxsleep;
		if (power->i_enabled != 0) {
			if ((ic->ic_caps & IEEE80211_C_PMGT) == 0)
				error = EINVAL;
			else if ((ic->ic_flags & IEEE80211_F_PMGTON) == 0) {
				ic->ic_flags |= IEEE80211_F_PMGTON;
				error = ENETRESET;
			}
		} else {
			if (ic->ic_flags & IEEE80211_F_PMGTON) {
				ic->ic_flags &= ~IEEE80211_F_PMGTON;
				error = ENETRESET;
			}
		}
		break;
	case SIOCG80211POWER:
		power = (struct ieee80211_power *)data;
		power->i_enabled = (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0;
		power->i_maxsleep = ic->ic_lintval;
		break;
	case SIOCS80211BSSID:
		if ((error = suser(curproc, 0)) != 0)
			break;
		bssid = (struct ieee80211_bssid *)data;
		if (IEEE80211_ADDR_EQ(bssid->i_bssid, empty_macaddr))
			ic->ic_flags &= ~IEEE80211_F_DESBSSID;
		else {
			ic->ic_flags |= IEEE80211_F_DESBSSID;
			IEEE80211_ADDR_COPY(ic->ic_des_bssid, bssid->i_bssid);
		}
		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
			break;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			error = ENETRESET;
			break;
		default:
			if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
			    !IEEE80211_ADDR_EQ(ic->ic_des_bssid,
			    ic->ic_bss->ni_bssid))
				error = ENETRESET;
			break;
		}
		break;
	case SIOCG80211BSSID:
		bssid = (struct ieee80211_bssid *)data;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			if (ic->ic_opmode == IEEE80211_M_HOSTAP)
				IEEE80211_ADDR_COPY(bssid->i_bssid,
				    ic->ic_myaddr);
			else if (ic->ic_flags & IEEE80211_F_DESBSSID)
				IEEE80211_ADDR_COPY(bssid->i_bssid,
				    ic->ic_des_bssid);
			else
				memset(bssid->i_bssid, 0, IEEE80211_ADDR_LEN);
			break;
		default:
			IEEE80211_ADDR_COPY(bssid->i_bssid,
			    ic->ic_bss->ni_bssid);
			break;
		}
		break;
	case SIOCS80211CHANNEL:
		if ((error = suser(curproc, 0)) != 0)
			break;
		chanreq = (struct ieee80211chanreq *)data;
		if (chanreq->i_channel == IEEE80211_CHAN_ANY)
			ic->ic_des_chan = IEEE80211_CHAN_ANYC;
		else if (chanreq->i_channel > IEEE80211_CHAN_MAX ||
		    isclr(ic->ic_chan_active, chanreq->i_channel)) {
			error = EINVAL;
			break;
		} else
			ic->ic_ibss_chan = ic->ic_des_chan =
			    &ic->ic_channels[chanreq->i_channel];
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			error = ENETRESET;
			break;
		default:
			if (ic->ic_opmode == IEEE80211_M_STA) {
				if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
				    ic->ic_bss->ni_chan != ic->ic_des_chan)
					error = ENETRESET;
			} else {
				if (ic->ic_bss->ni_chan != ic->ic_ibss_chan)
					error = ENETRESET;
			}
			break;
		}
		break;
	case SIOCG80211CHANNEL:
		chanreq = (struct ieee80211chanreq *)data;
		switch (ic->ic_state) {
		case IEEE80211_S_INIT:
		case IEEE80211_S_SCAN:
			if (ic->ic_opmode == IEEE80211_M_STA)
				chan = ic->ic_des_chan;
			else
				chan = ic->ic_ibss_chan;
			break;
		default:
			chan = ic->ic_bss->ni_chan;
			break;
		}
		chanreq->i_channel = ieee80211_chan2ieee(ic, chan);
		break;
#if 0
	case SIOCG80211ZSTATS:
#endif
	case SIOCG80211STATS:
		ifr = (struct ifreq *)data;
		copyout(&ic->ic_stats, ifr->ifr_data, sizeof (ic->ic_stats));
#if 0
		if (cmd == SIOCG80211ZSTATS)
			memset(&ic->ic_stats, 0, sizeof(ic->ic_stats));
#endif
		break;
	case SIOCS80211TXPOWER:
		if ((error = suser(curproc, 0)) != 0)
			break;
		txpower = (struct ieee80211_txpower *)data;
		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) {
			error = EINVAL;
			break;
		}
		if (IEEE80211_TXPOWER_MIN > txpower->i_val ||
		    txpower->i_val > IEEE80211_TXPOWER_MAX) {
			error = EINVAL;
			break;
		}
		ic->ic_txpower = txpower->i_val;
		error = ENETRESET;
		break;
	case SIOCG80211TXPOWER:
		txpower = (struct ieee80211_txpower *)data;
		if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
			error = EINVAL;
		else
			txpower->i_val = ic->ic_txpower;
		break;
	case SIOCSIFMTU:
		ifr = (struct ifreq *)data;
		if (!(IEEE80211_MTU_MIN <= ifr->ifr_mtu &&
		    ifr->ifr_mtu <= IEEE80211_MTU_MAX))
			error = EINVAL;
		else
			ifp->if_mtu = ifr->ifr_mtu;
		break;
	case SIOCS80211SCAN:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (ic->ic_opmode == IEEE80211_M_HOSTAP)
			break;
		if ((ifp->if_flags & IFF_UP) == 0) {
			error = ENETDOWN;
			break;
		}
		if ((ic->ic_scan_lock & IEEE80211_SCAN_REQUEST) == 0) {
			if (ic->ic_scan_lock & IEEE80211_SCAN_LOCKED)
				ic->ic_scan_lock |= IEEE80211_SCAN_RESUME;
			ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
			if (ic->ic_state != IEEE80211_S_SCAN)
				ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
		}
		/* Let the userspace process wait for completion */
		error = tsleep(&ic->ic_scan_lock, PCATCH, "80211scan",
		    hz * IEEE80211_SCAN_TIMEOUT);
		break;
	case SIOCG80211NODE:
		nr = (struct ieee80211_nodereq *)data;
		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL) {
			error = ENOENT;
			break;
		}
		ieee80211_node2req(ic, ni, nr);
		break;
	case SIOCS80211NODE:
		if ((error = suser(curproc, 0)) != 0)
			break;
		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
			error = EINVAL;
			break;
		}
		nr = (struct ieee80211_nodereq *)data;

		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL)
			ni = ieee80211_alloc_node(ic, nr->nr_macaddr);
		if (ni == NULL) {
			error = ENOENT;
			break;
		}

		if (nr->nr_flags & IEEE80211_NODEREQ_COPY)
			ieee80211_req2node(ic, nr, ni);
		break;
	case SIOCS80211DELNODE:
		if ((error = suser(curproc, 0)) != 0)
			break;
		nr = (struct ieee80211_nodereq *)data;
		ni = ieee80211_find_node(ic, nr->nr_macaddr);
		if (ni == NULL)
			error = ENOENT;
		else if (ni == ic->ic_bss)
			error = EPERM;
		else {
			if (ni->ni_state == IEEE80211_STA_COLLECT)
				break;

			/* Disassociate station. */
			if (ni->ni_state == IEEE80211_STA_ASSOC)
				IEEE80211_SEND_MGMT(ic, ni,
				    IEEE80211_FC0_SUBTYPE_DISASSOC,
				    IEEE80211_REASON_ASSOC_LEAVE);

			/* Deauth station. */
			if (ni->ni_state >= IEEE80211_STA_AUTH)
				IEEE80211_SEND_MGMT(ic, ni,
				    IEEE80211_FC0_SUBTYPE_DEAUTH,
				    IEEE80211_REASON_AUTH_LEAVE);

			ieee80211_release_node(ic, ni);
		}
		break;
	case SIOCG80211ALLNODES:
		na = (struct ieee80211_nodereq_all *)data;
		na->na_nodes = i = 0;
		ni = RB_MIN(ieee80211_tree, &ic->ic_tree);
		while (ni && na->na_size >=
		    i + sizeof(struct ieee80211_nodereq)) {
			ieee80211_node2req(ic, ni, &nrbuf);
			error = copyout(&nrbuf, (caddr_t)na->na_node + i,
			    sizeof(struct ieee80211_nodereq));
			if (error)
				break;
			i += sizeof(struct ieee80211_nodereq);
			na->na_nodes++;
			ni = RB_NEXT(ieee80211_tree, &ic->ic_tree, ni);
		}
		break;
	case SIOCG80211FLAGS:
		flags = ic->ic_flags;
		if (ic->ic_opmode != IEEE80211_M_HOSTAP)
			flags &= ~IEEE80211_F_HOSTAPMASK;
		ifr->ifr_flags = flags >> IEEE80211_F_USERSHIFT;
		break;
	case SIOCS80211FLAGS:
		if ((error = suser(curproc, 0)) != 0)
			break;
		flags = (u_int32_t)ifr->ifr_flags << IEEE80211_F_USERSHIFT;
		if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
		    (flags & IEEE80211_F_HOSTAPMASK)) {
			error = EINVAL;
			break;
		}
		ic->ic_flags = (ic->ic_flags & ~IEEE80211_F_USERMASK) | flags;
		error = ENETRESET;
		break;
	default:
		error = ENOTTY;
		break;
	}
	return error;
}
示例#4
0
文件: an.c 项目: ajinkya93/OpenBSD
void
an_rxeof(struct an_softc *sc)
{
	struct ieee80211com *ic = &sc->sc_ic;
	struct ifnet *ifp = &ic->ic_if;
	struct ieee80211_frame *wh;
	struct ieee80211_rxinfo rxi;
	struct ieee80211_node *ni;
	struct an_rxframe frmhdr;
	struct mbuf *m;
	u_int16_t status;
	int fid, gaplen, len, off;
	uint8_t *gap;

	fid = CSR_READ_2(sc, AN_RX_FID);

	/* First read in the frame header */
	if (an_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr), sizeof(frmhdr)) != 0) {
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
		ifp->if_ierrors++;
		DPRINTF(("an_rxeof: read fid %x failed\n", fid));
		return;
	}
	an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);

	status = frmhdr.an_rx_status;
	if ((status & AN_STAT_ERRSTAT) != 0 &&
	    ic->ic_opmode != IEEE80211_M_MONITOR) {
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
		ifp->if_ierrors++;
		DPRINTF(("an_rxeof: fid %x status %x\n", fid, status));
		return;
	}

	/* the payload length field includes a 16-bit "mystery field" */
	len = frmhdr.an_rx_payload_len - sizeof(uint16_t);
	off = ALIGN(sizeof(struct ieee80211_frame));

	if (off + len > MCLBYTES) {
		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
			ifp->if_ierrors++;
			DPRINTF(("an_rxeof: oversized packet %d\n", len));
			return;
		}
		len = 0;
	}

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL) {
		CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
		ifp->if_ierrors++;
		DPRINTF(("an_rxeof: MGET failed\n"));
		return;
	}
	if (off + len + AN_GAPLEN_MAX > MHLEN) {
		MCLGET(m, M_DONTWAIT);
		if ((m->m_flags & M_EXT) == 0) {
			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
			m_freem(m);
			ifp->if_ierrors++;
			DPRINTF(("an_rxeof: MCLGET failed\n"));
			return;
		}
	}
	m->m_data += off - sizeof(struct ieee80211_frame);

	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
		gaplen = frmhdr.an_gaplen;
		if (gaplen > AN_GAPLEN_MAX) {
			CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);
			m_freem(m);
			ifp->if_ierrors++;
			DPRINTF(("%s: gap too long\n", __func__));
			return;
		}
		/*
		 * We don't need the 16-bit mystery field (payload length?),
		 * so read it into the region reserved for the 802.11 header.
		 *
		 * When Cisco Aironet 350 cards w/ firmware version 5 or
		 * greater operate with certain Cisco 350 APs,
		 * the "gap" is filled with the SNAP header.  Read
		 * it in after the 802.11 header.
		 */
		gap = m->m_data + sizeof(struct ieee80211_frame) -
		    sizeof(uint16_t);
		an_read_bap(sc, fid, -1, gap, gaplen + sizeof(u_int16_t),
		    gaplen + sizeof(u_int16_t));
	} else
		gaplen = 0;

	an_read_bap(sc, fid, -1,
	    m->m_data + sizeof(struct ieee80211_frame) + gaplen, len, len);
	an_swap16((u_int16_t *)(m->m_data + sizeof(struct ieee80211_frame) + gaplen), (len+1)/2);
	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + gaplen +
	    len;

	memcpy(m->m_data, &frmhdr.an_whdr, sizeof(struct ieee80211_frame));
	CSR_WRITE_2(sc, AN_EVENT_ACK, AN_EV_RX);

#if NBPFILTER > 0
	if (sc->sc_drvbpf) {
		struct mbuf mb;
		struct an_rx_radiotap_header *tap = &sc->sc_rxtap;

		tap->ar_rate = frmhdr.an_rx_rate;
		tap->ar_antsignal = frmhdr.an_rx_signal_strength;
		tap->ar_chan_freq = ic->ic_bss->ni_chan->ic_freq;
		tap->ar_chan_flags = ic->ic_bss->ni_chan->ic_flags;


		mb.m_data = (caddr_t)tap;
		mb.m_len = sizeof(sc->sc_rxtapu);
		mb.m_next = m;
		mb.m_nextpkt = NULL;
		mb.m_type = 0;
		mb.m_flags = 0;
		bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
	}
#endif /* NBPFILTER > 0 */

	wh = mtod(m, struct ieee80211_frame *);
	rxi.rxi_flags = 0;
	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
		/*
		 * WEP is decrypted by hardware. Clear WEP bit
		 * header for ieee80211_input().
		 */
		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;

		rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
	}

	ni = ieee80211_find_rxnode(ic, wh);
	rxi.rxi_rssi = frmhdr.an_rx_signal_strength;
	rxi.rxi_tstamp = an_switch32(frmhdr.an_rx_time);
	ieee80211_input(ifp, m, ni, &rxi);
	ieee80211_release_node(ic, ni);
}
示例#5
0
文件: an.c 项目: ajinkya93/OpenBSD
void
an_start(struct ifnet *ifp)
{
	struct an_softc *sc = (struct an_softc *)ifp->if_softc;
	struct ieee80211com *ic = &sc->sc_ic;
	struct ieee80211_node *ni;
	struct ieee80211_frame *wh;
	struct an_txframe frmhdr;
	struct mbuf *m;
	u_int16_t len;
	int cur, fid;

	if (!sc->sc_enabled || sc->sc_invalid) {
		DPRINTF(("an_start: noop: enabled %d invalid %d\n",
		    sc->sc_enabled, sc->sc_invalid));
		return;
	}

	memset(&frmhdr, 0, sizeof(frmhdr));
	cur = sc->sc_txnext;
	for (;;) {
		if (ic->ic_state != IEEE80211_S_RUN) {
			DPRINTF(("an_start: not running %d\n", ic->ic_state));
			break;
		}
		m = ifq_deq_begin(&ifp->if_snd);
		if (m == NULL) {
			DPRINTF2(("an_start: no pending mbuf\n"));
			break;
		}
		if (sc->sc_txd[cur].d_inuse) {
			ifq_deq_rollback(&ifp->if_snd, m);
			DPRINTF2(("an_start: %x/%d busy\n",
			    sc->sc_txd[cur].d_fid, cur));
			ifq_set_oactive(&ifp->if_snd);
			break;
		}
		ifq_deq_commit(&ifp->if_snd, m);
		ifp->if_opackets++;
#if NBPFILTER > 0
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
		if ((m = ieee80211_encap(ifp, m, &ni)) == NULL) {
			ifp->if_oerrors++;
			continue;
		}
		if (ni != NULL)
			ieee80211_release_node(ic, ni);
#if NBPFILTER > 0
		if (ic->ic_rawbpf)
			bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
#endif

		wh = mtod(m, struct ieee80211_frame *);
		if (ic->ic_flags & IEEE80211_F_WEPON)
			wh->i_fc[1] |= IEEE80211_FC1_WEP;
		m_copydata(m, 0, sizeof(struct ieee80211_frame),
		    (caddr_t)&frmhdr.an_whdr);
		an_swap16((u_int16_t *)&frmhdr.an_whdr, sizeof(struct ieee80211_frame)/2);

		/* insert payload length in front of llc/snap */
		len = htons(m->m_pkthdr.len - sizeof(struct ieee80211_frame));
		m_adj(m, sizeof(struct ieee80211_frame) - sizeof(len));
		if (mtod(m, u_long) & 0x01)
			memcpy(mtod(m, caddr_t), &len, sizeof(len));
		else
			*mtod(m, u_int16_t *) = len;

		/*
		 * XXX Aironet firmware apparently convert the packet
		 * with longer than 1500 bytes in length into LLC/SNAP.
		 * If we have 1500 bytes in ethernet payload, it is
		 * 1508 bytes including LLC/SNAP and will be inserted
		 * additional LLC/SNAP header with 1501-1508 in its
		 * ethertype !!
		 * So we skip LLC/SNAP header and force firmware to
		 * convert it to LLC/SNAP again.
		 */
		m_adj(m, sizeof(struct llc));

		frmhdr.an_tx_ctl = AN_TXCTL_80211;
		frmhdr.an_tx_payload_len = m->m_pkthdr.len;
		frmhdr.an_gaplen = AN_TXGAP_802_11;

		if (ic->ic_fixed_rate != -1)
			frmhdr.an_tx_rate =
			    ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[
			    ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
		else
			frmhdr.an_tx_rate = 0;

		if (sizeof(frmhdr) + AN_TXGAP_802_11 + sizeof(len) +
		    m->m_pkthdr.len > AN_TX_MAX_LEN) {
			ifp->if_oerrors++;
			m_freem(m);
			continue;
		}

#if NBPFILTER > 0
		if (sc->sc_drvbpf) {
			struct mbuf mb;
			struct an_tx_radiotap_header *tap = &sc->sc_txtap;

			tap->at_rate = 
			    ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate];
			tap->at_chan_freq =
			    ic->ic_bss->ni_chan->ic_freq;
			tap->at_chan_flags =
			    ic->ic_bss->ni_chan->ic_flags;

			mb.m_data = (caddr_t)tap;
			mb.m_len = sizeof(sc->sc_txtapu);
			mb.m_next = m;
			mb.m_nextpkt = NULL;
			mb.m_type = 0;
			mb.m_flags = 0;
			bpf_mtap(sc->sc_drvbpf, m, BPF_DIRECTION_OUT);
		}
#endif

		fid = sc->sc_txd[cur].d_fid;
		if (an_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
			ifp->if_oerrors++;
			m_freem(m);
			continue;
		}
		/* dummy write to avoid seek. */
		an_write_bap(sc, fid, -1, &frmhdr, AN_TXGAP_802_11);
		an_mwrite_bap(sc, fid, -1, m, m->m_pkthdr.len);
		m_freem(m);

		DPRINTF2(("an_start: send %d byte via %x/%d\n",
		    ntohs(len) + sizeof(struct ieee80211_frame),
		    fid, cur));
		sc->sc_txd[cur].d_inuse = 1;
		if (an_cmd(sc, AN_CMD_TX, fid)) {
			printf("%s: xmit failed\n", ifp->if_xname);
			sc->sc_txd[cur].d_inuse = 0;
			continue;
		}
		sc->sc_tx_timer = 5;
		ifp->if_timer = 1;
		AN_INC(cur, AN_TX_RING_CNT);
		sc->sc_txnext = cur;
	}
}