📄 ieee80211_rx.c
字号:
/* * 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 + -