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

📄 ieee80211_rx.c

📁 rtl8180网卡在linux下的驱动程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Original code based Host AP (software wireless LAN access point) driver  * for Intersil Prism2/2.5/3 - hostap.o module, common routines * * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen * <jkmaline@cc.hut.fi> * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> * Copyright (c) 2004, Intel Corporation * Association logic, scanning WX and logics, some management frame handling * ans misc modifications for the rtl8180-sa2400 driver added by Andrea Merello  * <andreamrl@tiscali.it> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. See README and COPYING for * more details. */#include <linux/compiler.h>#include <linux/config.h>#include <linux/errno.h>#include <linux/if_arp.h>#include <linux/in6.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/netdevice.h>#include <linux/pci.h>#include <linux/proc_fs.h>#include <linux/skbuff.h>#include <linux/slab.h>#include <linux/tcp.h>#include <linux/types.h>#include <linux/version.h>#include <linux/wireless.h>#include <linux/etherdevice.h>#include <asm/uaccess.h>#include <linux/ctype.h>#include "ieee80211.h"#define BEACON_SOURCE_OFF 10#define BEACON_BSSID_OFF 16#define BEACON_TAG_OFF 36#define BEACON_CAPA_OFF 34#define BEACON_INTERVAL_OFF 32#define IEEE80211_DEBUG_MASTER_MODEstatic inline u16 auth_parse(struct sk_buff *skb){	struct ieee80211_authentication *a;	if(skb->len <  sizeof(struct ieee80211_authentication)){ 		IEEE80211DMESG("invalid len in auth resp:%d should be %d",skb->len,			sizeof(struct ieee80211_authentication));		return 0xcafe;	}	a = (struct ieee80211_authentication*) skb->data;	return cpu_to_le32(a->status);}int auth_rq_parse(struct sk_buff *skb,u8* dest){struct ieee80211_authentication *a;	if(skb->len <  sizeof(struct ieee80211_authentication)){ 		IEEE80211DMESG("invalid len in auth request:%d should be %d",skb->len,			sizeof(struct ieee80211_authentication));			return -1;	}	a = (struct ieee80211_authentication*) skb->data;		memcpy(dest,a->header.addr2,ETH_ALEN);		if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) 		return  WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;		return WLAN_STATUS_SUCCESS;}static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, u8 *src){	u8 *tag;	u8 *skbend;	u8 *ssid=NULL;	u8 ssidlen=0;	struct ieee80211_header_data *header =		(struct ieee80211_header_data *) skb->data;	if (skb->len < sizeof (struct ieee80211_header_data)) 		return -1; /* corrupted */	memcpy(src,header->addr2, ETH_ALEN);	skbend = (u8*)skb->data + skb->len;	tag = skb->data + sizeof (struct ieee80211_header_data);	while (tag+1 < skbend){		if (*tag == 0){ 			ssid = tag+2;			ssidlen = *(tag+1);			break;		}		tag++; /* point to the len field */		tag = tag + *(tag); /* point to the last data byte of the tag */		tag++; /* point to the next tag */	}		//IEEE80211DMESG("Card MAC address is "MACSTR, MAC2STR(src));	if(ssidlen == 0) return 1;		if(!ssid) return 1; /* ssid not found in tagged param */	return (!strncmp(ssid, ieee->master_essid, ssidlen));		}int assoc_rq_parse(struct sk_buff *skb,u8* dest){	struct ieee80211_association_request_hdr *a;		if(skb->len <  sizeof(struct ieee80211_association_request_hdr)){ 		IEEE80211DMESG("invalid len in auth request:%d should be at least %d",skb->len,			sizeof(struct ieee80211_association_response_hdr));		return -1;	}		a = (struct ieee80211_association_request_hdr*) skb->data;	memcpy(dest,a->addr2,ETH_ALEN);		return 0;}static inline u16 assoc_parse(struct sk_buff *skb){	struct ieee80211_association_response_hdr *a;	if(skb->len <  sizeof(struct ieee80211_association_response_hdr)){ 		IEEE80211DMESG("invalid len in auth resp:%d should be at least %d",skb->len,			sizeof(struct ieee80211_association_response_hdr));		return 0xcafe;	}	a = (struct ieee80211_association_response_hdr*) skb->data;	return cpu_to_le32(a->status);}static inline intieee80211_rx_beacon(struct ieee80211_device *ieee ,struct sk_buff *skb ,struct ieee80211_rx_stats *rx_stats){			struct ieee80211_beacon *btmp;	struct ieee80211_beacon *beacon;	//struct ieee80211_beacon *beacon2;	struct list_head *b,*next,*prev,*delprev;	//IEEE80211DMESG("beacon");	u8 *ptag;	u8 unk_len;	u8 *skbend;	int i;		skbend = skb->data+skb->len;	delprev=NULL;		beacon = kmalloc(sizeof(struct ieee80211_beacon),GFP_ATOMIC);		beacon->last_scanned=rx_stats->mac_time;	beacon->rssi = rx_stats->signal;	beacon->quality = rx_stats->noise; //FIXME: we use noise to carry quality info		if(skb->len <BEACON_TAG_OFF) return -1;//corrupted	beacon->interval = skb->data[BEACON_INTERVAL_OFF];	beacon->interval |= skb->data[BEACON_INTERVAL_OFF+1]<<8;	beacon->capability = skb->data[BEACON_CAPA_OFF];	beacon->capability |= (skb->data[BEACON_CAPA_OFF+1])<<8;		memcpy(beacon->bssid,skb->data+BEACON_BSSID_OFF,ETH_ALEN); 		for(ptag=skb->data+BEACON_TAG_OFF;ptag+1 < skbend;){				switch(*ptag){				case 0: //ssid			beacon->ssid_len = ptag[1];					if(skbend < ptag+1+beacon->ssid_len) return -1;//corrupted						memcpy(beacon->ssid,ptag+2,beacon->ssid_len);			beacon->ssid[beacon->ssid_len]='\0';						ptag+=beacon->ssid_len+2;			break;						case 1:	 //rates			beacon->rates_len = ptag[1];						if(skbend < ptag+1+beacon->rates_len) return -1;//corrupted			for(i=0;i<beacon->rates_len;i++)				beacon->rates[i]=ptag[2+i] - 0x80;			ptag+=beacon->rates_len+2;			break;								case 3:			if(ptag[1] != 1)  return -1;//corrupted			if(skbend < ptag+1+1)  return -1;//corrupted			beacon->channel=ptag[2];			ptag+=3;			break;					default: //unk				unk_len = ptag[1];			if(skbend < ptag+1+unk_len) return -1;//corrupted//			IEEE80211DMESG("unk tag %x len %x ",ptag[0],ptag[1]);			ptag+=unk_len+2;			break;					}					}		///IEEE80211DMESG("b %s",beacon->ssid);	list_for_each(b,&ieee->beacons){				btmp=list_entry(b,struct ieee80211_beacon,list);				if(delprev){			//if(b->prev != &ieee->beacons) 			kfree(list_entry(delprev,struct ieee80211_beacon,list));			delprev=NULL;		}								if(0==memcmp( btmp->bssid, beacon->bssid,ETH_ALEN)){		//printk("duplicate beacon\n");			btmp->last_scanned=beacon->last_scanned;			btmp->rssi=beacon->rssi;			btmp->channel = beacon->channel;			btmp->capability = beacon->capability;			btmp->rates_len = beacon->rates_len;			btmp->quality = beacon->quality;			memcpy(btmp->rates,beacon->rates,beacon->rates_len);			/* Beacons and Probe Responses go through here, so			 * we should keep the name from the Probe instead of			 * overwriting it.  I was going to check btmp, but an			 * AP could change ESSID on the fly, and that should			 * be caught.			 */			/*if (beacon->ssid[0] != '\0') {				memcpy(btmp->ssid, beacon->ssid,				       beacon->ssid_len);				       }*/			memcpy(btmp->ssid, beacon->ssid, beacon->ssid_len);			kfree(beacon);			return 0;		}						/* 		*	this has to be done on scan request, and on association attempt to ensure old beacons aren't reported,		*	but we do it here too to assure that the list is never too large		*/		if(btmp->last_scanned + SCAN_JIFFI < jiffies){ 					  //!!!!!using list_del will result in oops due to list_for_each!!!!		  	prev = b->prev;		  	next = b->next;		  	next->prev = prev;		  	prev->next = next;			  delprev=b;			  //kfree(btmp);		}	}		if(ieee->link_state==WLAN_LINK_NONE){			/*beacon2 =  kmalloc(sizeof(struct ieee80211_beacon),GFP_ATOMIC);		memcpy(beacon2,beacon,sizeof(struct ieee80211_beacon));*/		//IEEE80211DMESG("Found network");		ieee80211_new_net(ieee,beacon);	}	list_add(&beacon->list,&ieee->beacons);	return 0;}static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, 					struct sk_buff *skb, 					struct ieee80211_rx_stats *rx_stats){	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;	u16 fc = le16_to_cpu(hdr->frame_control);	skb->dev = ieee->dev;	skb->mac.raw = skb->data;	skb_pull(skb, ieee80211_get_hdrlen(fc));	skb->pkt_type = PACKET_OTHERHOST;	skb->protocol = __constant_htons(ETH_P_80211_RAW);	memset(skb->cb, 0, sizeof(skb->cb));	netif_rx(skb);}/* Called only as a tasklet (software IRQ) */static struct ieee80211_frag_entry *ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq,			  unsigned int frag, u8 *src, u8 *dst){	struct ieee80211_frag_entry *entry;	int i;	for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) {		entry = &ieee->frag_cache[i];		if (entry->skb != NULL &&		    time_after(jiffies, entry->first_frag_time + 2 * HZ)) {			printk(KERN_DEBUG "%s: expiring fragment cache entry "			       "seq=%u last_frag=%u\n",			       ieee->dev->name, entry->seq, entry->last_frag);			dev_kfree_skb_any(entry->skb);			entry->skb = NULL;		}		if (entry->skb != NULL && entry->seq == seq &&		    (entry->last_frag + 1 == frag || frag == -1) &&		    memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&		    memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)			return entry;	}	return NULL;}/* Called only as a tasklet (software IRQ) */static struct sk_buff *ieee80211_frag_cache_get(struct ieee80211_device *ieee, 			 struct ieee80211_hdr *hdr){	struct sk_buff *skb = NULL;	u16 sc;	unsigned int frag, seq;	struct ieee80211_frag_entry *entry;		sc = le16_to_cpu(hdr->seq_ctrl);	frag = WLAN_GET_SEQ_FRAG(sc);	seq = WLAN_GET_SEQ_SEQ(sc);	if (frag == 0) {		/* Reserve enough space to fit maximum frame length */		skb = dev_alloc_skb(ieee->dev->mtu +				    sizeof(struct ieee80211_hdr) +				    8 /* LLC */ +				    2 /* alignment */ +				    8 /* WEP */ + ETH_ALEN /* WDS */);		if (skb == NULL)			return NULL;		entry = &ieee->frag_cache[ieee->frag_next_idx];		ieee->frag_next_idx++;		if (ieee->frag_next_idx >= IEEE80211_FRAG_CACHE_LEN)			ieee->frag_next_idx = 0;		if (entry->skb != NULL)			dev_kfree_skb_any(entry->skb);		entry->first_frag_time = jiffies;		entry->seq = seq;		entry->last_frag = frag;		entry->skb = skb;		memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);		memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);	} else {		/* received a fragment of a frame for which the head fragment		 * should have already been received */		entry = ieee80211_frag_cache_find(ieee, seq, frag, hdr->addr2,						  hdr->addr1);		if (entry != NULL) {			entry->last_frag = frag;			skb = entry->skb;		}	}	return skb;}/* Called only as a tasklet (software IRQ) */static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee,					   struct ieee80211_hdr *hdr){

⌨️ 快捷键说明

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