wl_linux.c

来自「wi-fi sources for asus wl138g v2 pci car」· C语言 代码 · 共 1,790 行 · 第 1/3 页

C
1,790
字号
	/* call common first level interrupt handler */	if ((ours = wlc_isr(wl->wlc, &wantdpc))) {		/* if more to do... */		if (wantdpc) {			/* ...disable interrupts... */			wlc_intrsoff_isr(wl->wlc);			/* ...and call the second level interrupt handler */#if WL_TASKLET			/* schedule dpc */			ASSERT(wl->resched == FALSE);			tasklet_schedule(&wl->tasklet);#else			wlc_dpc(wl->wlc, FALSE);			wlc_intrson(wl->wlc);#endif /* WL_TASKLET */		}	}	spin_unlock(&wl->lock);	return IRQ_RETVAL(ours);}#if WL_TASKLETstatic voidwl_dpc(ulong data){	wl_info_t *wl;	wl = (wl_info_t*) data;	WL_LOCK(wl);	/* call the common second level interrupt handler */	if (wl->pub->up) {		if (wl->resched)			wlc_intrsupd(wl->wlc);		wl->resched = wlc_dpc(wl->wlc, TRUE);	}	/* wlc_dpc() may bring the driver down */	if (!wl->pub->up)		goto done;	/* re-schedule dpc */	if (wl->resched)		tasklet_schedule(&wl->tasklet);	/* re-enable interrupts */	else		wlc_intrson(wl->wlc);done:	WL_UNLOCK(wl);}#endif	/* WL_TASKLET */voidwl_sendup(wl_info_t *wl, wl_if_t *wlif, void *p){	struct sk_buff *skb;	WL_TRACE(("wl%d: wl_sendup: %d bytes\n", wl->pub->unit, PKTLEN(wl->osh, p)));	/* route packet to the appropriate interface */	if (wlif) {		/* drop if the interface is not up yet */		if (!netif_device_present(wlif->dev)) {			WL_ERROR(("wl%d: wl_sendup: interface not ready\n", wl->pub->unit));			PKTFREE(wl->osh, p, FALSE);			return;		}		/* Convert the packet, mainly detach the pkttag */		skb = PKTTONATIVE(wl->osh, p);		skb->dev = wlif->dev;	} else {		/* Convert the packet, mainly detach the pkttag */		skb = PKTTONATIVE(wl->osh, p);		skb->dev = wl->dev;	}	skb->protocol = eth_type_trans(skb, wl->dev);	ASSERT(ISALIGNED((uintptr)skb->data, 4));	/* send it up */	netif_rx(skb);}intwl_dump(wl_info_t *wl, char *buf, uint len){	/* big enough? */	if (len < WLC_IOCTL_MAXLEN)		return (WLC_IOCTL_MAXLEN);	sprintf(buf, "wl%d: %s %s version %s\n", wl->pub->unit,		__DATE__, __TIME__, EPI_VERSION_STR);	wlc_tinydump(wl->wlc, &buf[strlen(buf)]);	ASSERT(strlen(buf) < len);	return (strlen(buf));}static voidwl_link_up(wl_info_t *wl){	WL_ERROR(("wl%d: link up\n", wl->pub->unit));}static voidwl_link_down(wl_info_t *wl){	WL_ERROR(("wl%d: link down\n", wl->pub->unit));}voidwl_event(wl_info_t *wl, wlc_event_t *e){#ifdef CONFIG_NET_RADIO	wl_iw_event(wl->dev, e);#endif /* CONFIG_NET_RADIO */	switch (e->event.event_type) {	case WLC_E_LINK:	case WLC_E_NDIS_LINK:		if (e->event.flags&WLC_EVENT_MSG_LINK)			wl_link_up(wl);		else			wl_link_down(wl);		break;	case WLC_E_MIC_ERROR:		wl_tkipmic_error(wl, e->addr,			e->event.flags&WLC_EVENT_MSG_GROUP,			e->event.flags&WLC_EVENT_MSG_FLUSHTXQ);		break;	}}static voidwl_timer(ulong data){	wl_timer_t *t;	t = (wl_timer_t*) data;	WL_LOCK(t->wl);	if (t->set) {		if (t->periodic) {			t->timer.expires = jiffies + t->ms*HZ/1000;			t->wl->callbacks++;			add_timer(&t->timer);			t->set = TRUE;		} else			t->set = FALSE;		t->fn(t->wl->wlc);	}	t->wl->callbacks--;	WL_UNLOCK(t->wl);}wl_timer_t *wl_init_timer(wl_info_t *wl, void (*fn)(void *wlc)){	wl_timer_t *t;	if (!(t = MALLOC(wl->osh, sizeof(wl_timer_t)))) {		WL_ERROR(("wl%d: wl_init_timer: out of memory, malloced %d bytes\n", wl->pub->unit,			MALLOCED(wl->osh)));		return 0;	}	init_timer(&t->timer);	t->timer.data = (ulong) t;	t->timer.function = wl_timer;	t->wl = wl;	t->fn = fn;	t->set = FALSE;	t->periodic = FALSE;	t->ms = 0;	t->next = wl->timers;	wl->timers = t;	return t;}voidwl_add_timer(wl_info_t *wl, wl_timer_t *t, uint ms, int periodic){	ASSERT(!t->set);	t->ms = ms;	t->periodic = (bool) periodic;	t->set = TRUE;	t->timer.expires = jiffies + ms*HZ/1000;	wl->callbacks++;	add_timer(&t->timer);}/* return TRUE if timer successfully deleted, FALSE if still pending */boolwl_del_timer(wl_info_t *wl, wl_timer_t *t){	if (t->set) {		t->set = FALSE;		if (!del_timer(&t->timer))			return FALSE;		wl->callbacks--;	}	return TRUE;}voidwl_free_timer(wl_info_t *wl, wl_timer_t *t){	ASSERT(!t->set);}static voidwl_tkipmic_error(wl_info_t *wl, struct ether_addr *ea, bool group, bool flush_txq){	WL_WSEC(("wl%d: mic error using %s key\n", wl->pub->unit,		(group) ? "group" : "pairwise"));}voidwl_monitor(wl_info_t *wl, wl_rxsts_t *rxsts, void *p){	struct sk_buff *oskb = (struct sk_buff *)p;	p80211msg_t *phdr;	struct sk_buff *skb;	uint len;	uchar *pdata;	WL_TRACE(("wl%d: wl_monitor\n", wl->pub->unit));	if (!wl->monitor)		return;	len = sizeof(p80211msg_t) + oskb->len - D11_PHY_HDR_LEN;	if ((skb = dev_alloc_skb(len)) == NULL)		return;	skb_put(skb, len);	phdr = (p80211msg_t*)skb->data;	/* Initialize the message members */	phdr->msgcode = WL_MON_FRAME;	phdr->msglen = sizeof(p80211msg_t);	strcpy(phdr->devname, wl->dev->name);	phdr->hosttime.did = WL_MON_FRAME_HOSTTIME;	phdr->hosttime.status = P80211ITEM_OK;	phdr->hosttime.len = 4;	phdr->hosttime.data = jiffies;	phdr->channel.did = WL_MON_FRAME_CHANNEL;	phdr->channel.status = P80211ITEM_NO_VALUE;	phdr->channel.len = 4;	phdr->channel.data = 0;	phdr->signal.did = WL_MON_FRAME_SIGNAL;	phdr->signal.status = P80211ITEM_NO_VALUE;	phdr->signal.len = 4;	phdr->signal.data = (rxsts->preamble == WL_RXS_PREAMBLE_SHORT) ? 1 : 0;	phdr->noise.did = WL_MON_FRAME_NOISE;	phdr->noise.status = P80211ITEM_NO_VALUE;	phdr->noise.len = 4;	phdr->noise.data = 0;	phdr->rate.did = WL_MON_FRAME_RATE;	phdr->rate.status = P80211ITEM_OK;	phdr->rate.len = 4;	phdr->rate.data = rxsts->datarate;	phdr->istx.did = WL_MON_FRAME_ISTX;	phdr->istx.status = P80211ITEM_NO_VALUE;	phdr->istx.len = 4;	phdr->istx.data = 0;	phdr->mactime.did = WL_MON_FRAME_MACTIME;	phdr->mactime.status = P80211ITEM_OK;	phdr->mactime.len = 4;	phdr->mactime.data = rxsts->mactime;	phdr->rssi.did = WL_MON_FRAME_RSSI;	phdr->rssi.status = P80211ITEM_OK;	phdr->rssi.len = 4;	phdr->rssi.data = rxsts->signal;		/* to dbm */	phdr->sq.did = WL_MON_FRAME_SQ;	phdr->sq.status = P80211ITEM_OK;	phdr->sq.len = 4;	phdr->sq.data = rxsts->sq;	phdr->frmlen.did = WL_MON_FRAME_FRMLEN;	phdr->frmlen.status = P80211ITEM_OK;	phdr->frmlen.status = P80211ITEM_OK;	phdr->frmlen.len = 4;	phdr->frmlen.data = rxsts->pktlength;	pdata = skb->data + sizeof(p80211msg_t);	bcopy(oskb->data + D11_PHY_HDR_LEN, pdata, oskb->len - D11_PHY_HDR_LEN);	skb->dev = wl->monitor;	skb->dev->last_rx = jiffies;	skb->mac.raw = skb->data;	skb->ip_summed = CHECKSUM_NONE;	skb->pkt_type = PACKET_OTHERHOST;	skb->protocol = htons(ETH_P_80211_RAW);	netif_rx(skb);}static intwl_monitor_start(struct sk_buff *skb, struct net_device *dev){	dev_kfree_skb(skb);	return 0;}static voidwl_add_monitor(wl_task_t *task){	wl_info_t *wl = (wl_info_t *) task->context;	WL_LOCK(wl);	if (wl->monitor)		goto done;	if (!(wl->monitor = MALLOC(wl->osh, sizeof(struct net_device))))		goto done;	bzero(wl->monitor, sizeof(struct net_device));	DEV_WLPTR(wl->monitor) = wl;	wl->monitor->hard_start_xmit = wl_monitor_start;	wl->monitor->do_ioctl = wl_ioctl;	sprintf(wl->monitor->name, "prism%d", wl->pub->unit);	bcopy(wl->dev->dev_addr, wl->monitor->dev_addr, ETHER_ADDR_LEN);	wl->monitor->type = ARPHRD_IEEE80211_PRISM;	wl->monitor->flags = wl->dev->flags;	if (register_netdev(wl->monitor)) {		MFREE(wl->osh, wl->monitor, sizeof(struct net_device));		wl->monitor = NULL;		goto done;	}done:	WL_ERROR(("wl%d: wl_add_monitor: out of memory, malloced %d bytes\n", wl->pub->unit,		MALLOCED(wl->osh)));	MFREE(wl->osh, task, sizeof(wl_task_t));	wl->callbacks--;	WL_UNLOCK(wl);}static voidwl_del_monitor(wl_task_t *task){	wl_info_t *wl = (wl_info_t *) task->context;	WL_LOCK(wl);	if (!wl->monitor)		goto done;	unregister_netdev(wl->monitor);	MFREE(wl->osh, wl->monitor, sizeof(struct net_device));	wl->monitor = NULL;done:	MFREE(wl->osh, task, sizeof(wl_task_t));	wl->callbacks--;	WL_UNLOCK(wl);}/* * Create a dedicated monitor interface since libpcap caches the * packet type when it opens the device. The protocol type in the skb * is dropped somewhere in libpcap, and every received frame is tagged * with the DLT/ARPHRD type that's read by libpcap when the device is * opened. * * If libpcap was fixed to handle per-packet link types, we might not * need to create a pseudo device at all, wl_set_monitor() would be * unnecessary, and wlc->monitor could just get set in wlc_ioctl(). */voidwl_set_monitor(wl_info_t *wl, int val){	WL_TRACE(("wl%d: wl_set_monitor: val %d\n", wl->pub->unit, val));	if (val && !wl->monitor)		(void) wl_schedule_task(wl, wl_add_monitor, wl);	else if (!val && wl->monitor)		(void) wl_schedule_task(wl, wl_del_monitor, wl);}struct net_device *wl_netdev_get(wl_info_t *wl){	return wl->dev;}intwl_tkip_miccheck(wl_info_t *wl, void *p, int hdr_len, bool group_key, int key_index){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	struct sk_buff *skb;	skb = PKTTONATIVE(wl->osh, p);	if (wl->tkipmodops) {		if (group_key && wl->tkip_bcast_data)			return(wl->tkipmodops->decrypt_msdu(skb, key_index, hdr_len, wl->tkip_bcast_data));		else if (!group_key && wl->tkip_ucast_data)			return(wl->tkipmodops->decrypt_msdu(skb, key_index, hdr_len, wl->tkip_ucast_data));	}#endif	/* Error */	WL_ERROR(("%s: No tkip mod ops\n", __FUNCTION__));	return -1;}intwl_tkip_micadd(wl_info_t *wl, void *p, int hdr_len){	int error = -1;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	struct sk_buff *skb;	skb = PKTTONATIVE(wl->osh, p);	if (wl->tkipmodops) {		if (wl->tkip_ucast_data)			error = wl->tkipmodops->encrypt_msdu(skb, hdr_len, wl->tkip_ucast_data);		if (error)			WL_ERROR(("Error encrypting MSDU %d\n", error));	}	else #endif		WL_ERROR(("%s: No tkip mod ops\n", __FUNCTION__));	return error;	}intwl_tkip_encrypt(wl_info_t *wl, void *p, int hdr_len){	int error = -1;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	struct sk_buff *skb;	skb = PKTTONATIVE(wl->osh, p);	if (wl->tkipmodops) {		if (wl->tkip_ucast_data)			error = wl->tkipmodops->encrypt_mpdu(skb, hdr_len, wl->tkip_ucast_data);		if (error) {			WL_ERROR(("Error encrypting MPDU %d\n", error));		}	}	else #endif		WL_ERROR(("%s: No tkip mod ops\n", __FUNCTION__));	return error;	}intwl_tkip_decrypt(wl_info_t *wl, void *p, int hdr_len, bool group_key){	int err = -1;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	struct sk_buff *skb;	skb = PKTTONATIVE(wl->osh, p);	if (wl->tkipmodops) {		if (group_key && wl->tkip_bcast_data)			err = wl->tkipmodops->decrypt_mpdu(skb, hdr_len, wl->tkip_bcast_data);		else if (!group_key && wl->tkip_ucast_data)			err = wl->tkipmodops->decrypt_mpdu(skb, hdr_len, wl->tkip_ucast_data);	}	else 		WL_ERROR(("%s: No tkip mod ops\n", __FUNCTION__));#endif 			/* Error */	return err;}intwl_tkip_keyset(wl_info_t *wl, wsec_key_t *key){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	bool group_key = FALSE;		uchar	rxseq[IW_ENCODE_SEQ_MAX_SIZE];	if (key->len != 0) {		WL_WSEC(("%s: Key Length is Not zero\n", __FUNCTION__));		if (key->algo != CRYPTO_ALGO_TKIP) {			WL_WSEC(("%s: Algo is Not TKIP %d\n", __FUNCTION__, key->algo));			return 0;		}		WL_WSEC(("%s: Trying to set a key in TKIP Mod\n", __FUNCTION__));	}	else 		WL_WSEC(("%s: Trying to Remove a Key from TKIP Mod\n", __FUNCTION__));	if (ETHER_ISNULLADDR(&key->ea) || ETHER_ISBCAST(&key->ea)) {		group_key = TRUE;		WL_WSEC(("Group Key index %d\n", key->id));	}	else 		WL_WSEC(("Unicast Key index %d\n", key->id));	if (wl->tkipmodops) {		if (group_key) {			if (key->len) {				if (!wl->tkip_bcast_data) {					WL_WSEC(("Init TKIP Bcast Module\n"));					WL_UNLOCK(wl);					wl->tkip_bcast_data = wl->tkipmodops->init(key->id);					WL_LOCK(wl);				}				if (wl->tkip_bcast_data) {					bzero(rxseq, IW_ENCODE_SEQ_MAX_SIZE);					bcopy(&key->rxiv, rxseq, 6);					wl->tkipmodops->set_key(&key->data, key->len, (uint8 *)&key->rxiv, wl->tkip_bcast_data);				}			}			else {				if (wl->tkip_bcast_data) {					WL_WSEC(("Deinit TKIP Bcast Module\n"));					wl->tkipmodops->deinit(wl->tkip_bcast_data);					wl->tkip_bcast_data = NULL;				}			}		}		else {			if (key->len) {				if (!wl->tkip_ucast_data) {					WL_WSEC(("Init TKIP Ucast Module\n"));					WL_UNLOCK(wl);					wl->tkip_ucast_data = wl->tkipmodops->init(key->id);					WL_LOCK(wl);				}				if (wl->tkip_ucast_data) {					bzero(rxseq, IW_ENCODE_SEQ_MAX_SIZE);					bcopy(&key->rxiv, rxseq, 6);					wl->tkipmodops->set_key(&key->data, key->len, (uint8 *)&key->rxiv, wl->tkip_ucast_data);				}			}			else {				if (wl->tkip_ucast_data) {					WL_WSEC(("Deinit TKIP Ucast Module\n"));					wl->tkipmodops->deinit(wl->tkip_ucast_data);					wl->tkip_ucast_data = NULL;				}			}		}	}	else #endif		WL_WSEC(("%s: No tkip mod ops\n", __FUNCTION__));	return 0;}void wl_tkip_printstats(wl_info_t *wl, bool group_key){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)	char debug_buf[512];	if (wl->tkipmodops) {		if (group_key && wl->tkip_bcast_data)			wl->tkipmodops->print_stats(debug_buf, wl->tkip_bcast_data);		else if (!group_key && wl->tkip_ucast_data)			wl->tkipmodops->print_stats(debug_buf, wl->tkip_ucast_data);		else 			return;		printk("%s: TKIP stats from module: %s\n", debug_buf, group_key?"Bcast":"Ucast");	}#endif}

⌨️ 快捷键说明

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