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

📄 hostap_hw.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
 * register has changed values between consecutive reads for an unknown reason. * This should really not happen, so more debugging is needed. This test * version is a big slower, but it will detect most of such register changes * and will try to get the correct fid eventually. */#define EXTRA_FID_READ_TESTSstatic inline u16 prism2_read_fid_reg(struct net_device *dev, u16 reg){#ifdef EXTRA_FID_READ_TESTS	u16 val, val2, val3;	int i;	for (i = 0; i < 10; i++) {		val = HFA384X_INW(reg);		val2 = HFA384X_INW(reg);		val3 = HFA384X_INW(reg);		if (val == val2 && val == val3)			return val;		printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"		       " %04x %04x %04x\n",		       dev->name, i, reg, val, val2, val3);		if ((val == val2 || val == val3) && val != 0)			return val;		if (val2 == val3 && val2 != 0)			return val2;	}	printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "	       "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);	return val;#else /* EXTRA_FID_READ_TESTS */	return HFA384X_INW(reg);#endif /* EXTRA_FID_READ_TESTS */}/* Called only as a tasklet (software IRQ) */static void prism2_rx(local_info_t *local){	struct net_device *dev = local->dev;	int res, rx_pending = 0;	u16 len, hdr_len, rxfid, status, macport;	struct net_device_stats *stats;	struct hfa384x_rx_frame rxdesc;	struct sk_buff *skb = NULL;	prism2_callback(local, PRISM2_CALLBACK_RX_START);	stats = hostap_get_stats(dev);	rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);#ifndef final_version	if (rxfid == 0) {		rxfid = HFA384X_INW(HFA384X_RXFID_OFF);		printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",		       rxfid);		if (rxfid == 0) {			schedule_work(&local->reset_queue);			goto rx_dropped;		}		/* try to continue with the new rxfid value */	}#endif	spin_lock(&local->baplock);	res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);	if (!res)		res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));	if (res) {		spin_unlock(&local->baplock);		printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,		       res);		if (res == -ETIMEDOUT) {			schedule_work(&local->reset_queue);		}		goto rx_dropped;	}	len = le16_to_cpu(rxdesc.data_len);	hdr_len = sizeof(rxdesc);	status = le16_to_cpu(rxdesc.status);	macport = (status >> 8) & 0x07;	/* Drop frames with too large reported payload length. Monitor mode	 * seems to sometimes pass frames (e.g., ctrl::ack) with signed and	 * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for	 * macport 7 */	if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {		if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {			if (len >= (u16) -14) {				hdr_len -= 65535 - len;				hdr_len--;			}			len = 0;		} else {			spin_unlock(&local->baplock);			printk(KERN_DEBUG "%s: Received frame with invalid "			       "length 0x%04x\n", dev->name, len);			hostap_dump_rx_header(dev->name, &rxdesc);			goto rx_dropped;		}	}	skb = dev_alloc_skb(len + hdr_len);	if (!skb) {		spin_unlock(&local->baplock);		printk(KERN_DEBUG "%s: RX failed to allocate skb\n",		       dev->name);		goto rx_dropped;	}	skb->dev = dev;	memcpy(skb_put(skb, hdr_len), &rxdesc, hdr_len);	if (len > 0)		res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len);	spin_unlock(&local->baplock);	if (res) {		printk(KERN_DEBUG "%s: RX failed to read "		       "frame data\n", dev->name);		goto rx_dropped;	}	skb_queue_tail(&local->rx_list, skb);	tasklet_schedule(&local->rx_tasklet); rx_exit:	prism2_callback(local, PRISM2_CALLBACK_RX_END);	if (!rx_pending) {		HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);	}	return; rx_dropped:	stats->rx_dropped++;	if (skb)		dev_kfree_skb(skb);	goto rx_exit;}/* Called only as a tasklet (software IRQ) */static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb){	struct hfa384x_rx_frame *rxdesc;	struct net_device *dev = skb->dev;	struct hostap_80211_rx_status stats;	int hdrlen, rx_hdrlen;	rx_hdrlen = sizeof(*rxdesc);	if (skb->len < sizeof(*rxdesc)) {		/* Allow monitor mode to receive shorter frames */		if (local->iw_mode == IW_MODE_MONITOR &&		    skb->len >= sizeof(*rxdesc) - 30) {			rx_hdrlen = skb->len;		} else {			dev_kfree_skb(skb);			return;		}	}	rxdesc = (struct hfa384x_rx_frame *) skb->data;	if (local->frame_dump & PRISM2_DUMP_RX_HDR &&	    skb->len >= sizeof(*rxdesc))		hostap_dump_rx_header(dev->name, rxdesc);	if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&	    (!local->monitor_allow_fcserr ||	     local->iw_mode != IW_MODE_MONITOR))		goto drop;	if (skb->len > PRISM2_DATA_MAXLEN) {		printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",		       dev->name, skb->len, PRISM2_DATA_MAXLEN);		goto drop;	}	stats.mac_time = le32_to_cpu(rxdesc->time);	stats.signal = rxdesc->signal - local->rssi_to_dBm;	stats.noise = rxdesc->silence - local->rssi_to_dBm;	stats.rate = rxdesc->rate;	/* Convert Prism2 RX structure into IEEE 802.11 header */	hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));	if (hdrlen > rx_hdrlen)		hdrlen = rx_hdrlen;	memmove(skb_pull(skb, rx_hdrlen - hdrlen),		&rxdesc->frame_control, hdrlen);	hostap_80211_rx(dev, skb, &stats);	return; drop:	dev_kfree_skb(skb);}/* Called only as a tasklet (software IRQ) */static void hostap_rx_tasklet(unsigned long data){	local_info_t *local = (local_info_t *) data;	struct sk_buff *skb;	while ((skb = skb_dequeue(&local->rx_list)) != NULL)		hostap_rx_skb(local, skb);}/* Called only from hardware IRQ */static void prism2_alloc_ev(struct net_device *dev){	struct hostap_interface *iface;	local_info_t *local;	int idx;	u16 fid;	iface = netdev_priv(dev);	local = iface->local;	fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);	PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);	spin_lock(&local->txfidlock);	idx = local->next_alloc;	do {		if (local->txfid[idx] == fid) {			PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",			       idx);#ifndef final_version			if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)				printk("Already released txfid found at idx "				       "%d\n", idx);			if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)				printk("Already reserved txfid found at idx "				       "%d\n", idx);#endif			local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;			idx++;			local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :				idx;			if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&			    netif_queue_stopped(dev))				netif_wake_queue(dev);			spin_unlock(&local->txfidlock);			return;		}		idx++;		if (idx >= PRISM2_TXFID_COUNT)			idx = 0;	} while (idx != local->next_alloc);	printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "	       "read 0x%04x) for alloc event\n", dev->name, fid,	       HFA384X_INW(HFA384X_ALLOCFID_OFF));	printk(KERN_DEBUG "TXFIDs:");	for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)		printk(" %04x[%04x]", local->txfid[idx],		       local->intransmitfid[idx]);	printk("\n");	spin_unlock(&local->txfidlock);	/* FIX: should probably schedule reset; reference to one txfid was lost	 * completely.. Bad things will happen if we run out of txfids	 * Actually, this will cause netdev watchdog to notice TX timeout and	 * then card reset after all txfids have been leaked. */}/* Called only as a tasklet (software IRQ) */static void hostap_tx_callback(local_info_t *local,			       struct hfa384x_tx_frame *txdesc, int ok,			       char *payload){	u16 sw_support, hdrlen, len;	struct sk_buff *skb;	struct hostap_tx_callback_info *cb;	/* Make sure that frame was from us. */	if (memcmp(txdesc->addr2, local->dev->dev_addr, ETH_ALEN)) {		printk(KERN_DEBUG "%s: TX callback - foreign frame\n",		       local->dev->name);		return;	}	sw_support = le16_to_cpu(txdesc->sw_support);	spin_lock(&local->lock);	cb = local->tx_callback;	while (cb != NULL && cb->idx != sw_support)		cb = cb->next;	spin_unlock(&local->lock);	if (cb == NULL) {		printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",		       local->dev->name, sw_support);		return;	}	hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control));	len = le16_to_cpu(txdesc->data_len);	skb = dev_alloc_skb(hdrlen + len);	if (skb == NULL) {		printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "		       "skb\n", local->dev->name);		return;	}	memcpy(skb_put(skb, hdrlen), (void *) &txdesc->frame_control, hdrlen);	if (payload)		memcpy(skb_put(skb, len), payload, len);	skb->dev = local->dev;	skb->mac.raw = skb->data;	cb->func(skb, ok, cb->data);}/* Called only as a tasklet (software IRQ) */static int hostap_tx_compl_read(local_info_t *local, int error,				struct hfa384x_tx_frame *txdesc,				char **payload){	u16 fid, len;	int res, ret = 0;	struct net_device *dev = local->dev;	fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);	PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error);	spin_lock(&local->baplock);	res = hfa384x_setup_bap(dev, BAP0, fid, 0);	if (!res)		res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc));	if (res) {		PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not "		       "read txdesc\n", dev->name, error, fid);		if (res == -ETIMEDOUT) {			schedule_work(&local->reset_queue);		}		ret = -1;		goto fail;	}	if (txdesc->sw_support) {		len = le16_to_cpu(txdesc->data_len);		if (len < PRISM2_DATA_MAXLEN) {			*payload = (char *) kmalloc(len, GFP_ATOMIC);			if (*payload == NULL ||			    hfa384x_from_bap(dev, BAP0, *payload, len)) {				PDEBUG(DEBUG_EXTRA, "%s: could not read TX "				       "frame payload\n", dev->name);				kfree(*payload);				*payload = NULL;				ret = -1;				goto fail;			}		}	} fail:	spin_unlock(&local->baplock);	return ret;}/* Called only as a tasklet (software IRQ) */static void prism2_tx_ev(local_info_t *local){	struct net_device *dev = local->dev;	char *payload = NULL;	struct hfa384x_tx_frame txdesc;	if (hostap_tx_compl_read(local, 0, &txdesc, &payload))		goto fail;	if (local->frame_dump & PRISM2_DUMP_TX_HDR) {		PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x "		       "retry_count=%d tx_rate=%d seq_ctrl=%d "		       "duration_id=%d\n",		       dev->name, le16_to_cpu(txdesc.status),		       txdesc.retry_count, txdesc.tx_rate,		       le16_to_cpu(txdesc.seq_ctrl),		       le16_to_cpu(txdesc.duration_id));	}	if (txdesc.sw_support)		hostap_tx_callback(local, &txdesc, 1, payload);	kfree(payload); fail:	HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF);}/* Called only as a tasklet (software IRQ) */static void hostap_sta_tx_exc_tasklet(unsigned long data){	local_info_t *local = (local_info_t *) data;	struct sk_buff *skb;	while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) {		struct hfa384x_tx_frame *txdesc =			(struct hfa384x_tx_frame *) skb->data;		if (skb->len >= sizeof(*txdesc)) {			/* Convert Prism2 RX structure into IEEE 802.11 header			 */			u16 fc = le16_to_cpu(txdesc->frame_control);			int hdrlen = hostap_80211_get_hdrlen(fc);			memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),				&txdesc->frame_control, hdrlen);			hostap_handle_sta_tx_exc(local, skb);		}		dev_kfree_skb(skb);	}}/* Called only as a tasklet (software IRQ) */static void prism2_txexc(local_info_t *local){	struct net_device *dev = local->dev;	u16 status, fc;	int show_dump, res;	char *payload = NULL;	struct hfa384x_tx_frame txdesc;	show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;	local->stats.tx_errors++;	res = hostap_tx_compl_read(local, 1, &txdesc, &payload);	HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);	if (res)		return;	status = le16_to_cpu(txdesc.status);	/* We produce a TXDROP event only for retry or lifetime	 * exceeded, because that's the only status that really mean	 * that this particular node went away.	 * Other errors means that *we* screwed up. - Jean II */	if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR))	{		union iwreq_data wrqu;		/* Copy 802.11 dest address. */		memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN);		wrqu.addr.sa_family = ARPHRD_ETHER;		wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);	} else		show_dump = 1;	if (local->iw_mode == IW_MODE_MASTER ||	    local->iw_mode == IW_MODE_REPEAT ||	    local->wds_type & HOSTAP_WDS_AP_CLIENT) {		struct sk_buff *skb;		skb = dev_alloc_skb(sizeof(txdesc));		if (skb) {			memcpy(skb_put(skb, sizeof(txdesc)), &txdesc,			       sizeof(txdesc));	

⌨️ 快捷键说明

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