📄 hostap_80211_rx.c
字号:
#include <linux/etherdevice.h>#include "hostap_80211.h"#include "hostap.h"void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){ struct hostap_ieee80211_hdr *hdr; u16 fc; hdr = (struct hostap_ieee80211_hdr *) skb->data; printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " "jiffies=%ld\n", name, rx_stats->signal, rx_stats->noise, rx_stats->rate, skb->len, jiffies); if (skb->len < 2) return; fc = le16_to_cpu(hdr->frame_control); printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", fc, WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc), fc & WLAN_FC_TODS ? " [ToDS]" : "", fc & WLAN_FC_FROMDS ? " [FromDS]" : ""); if (skb->len < IEEE80211_DATA_HDR3_LEN) { printk("\n"); return; } printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctrl)); printk(KERN_DEBUG " A1=" MACSTR " A2=" MACSTR " A3=" MACSTR, MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); if (skb->len >= 30) printk(" A4=" MACSTR, MAC2STR(hdr->addr4)); printk("\n");}/* Send RX frame to netif with 802.11 (and possible prism) header. * Called from hardware or software IRQ context. */int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats, int type){ struct hostap_interface *iface = dev->priv; local_info_t *local = iface->local; int hdrlen, phdrlen, head_need, tail_need; u16 fc; int prism_header, ret; struct hostap_ieee80211_hdr *hdr; dev->last_rx = jiffies; if (dev->type == ARPHRD_IEEE80211_PRISM) { if (local->monitor_type == PRISM2_MONITOR_PRISM) { prism_header = 1; phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ prism_header = 2; phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); } } else { prism_header = 0; phdrlen = 0; } hdr = (struct hostap_ieee80211_hdr *) skb->data; fc = le16_to_cpu(hdr->frame_control); if (type == PRISM2_RX_MGMT && (fc & WLAN_FC_PVER)) { printk(KERN_DEBUG "%s: dropped management frame with header " "version %d\n", dev->name, fc & WLAN_FC_PVER); dev_kfree_skb_any(skb); return 0; } hdrlen = hostap_80211_get_hdrlen(fc); /* check if there is enough room for extra data; if not, expand skb * buffer to be large enough for the changes */ head_need = phdrlen; tail_need = 0;#ifdef PRISM2_ADD_BOGUS_CRC tail_need += 4;#endif /* PRISM2_ADD_BOGUS_CRC */ head_need -= skb_headroom(skb); tail_need -= skb_tailroom(skb); if (head_need > 0 || tail_need > 0) { if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, tail_need > 0 ? tail_need : 0, GFP_ATOMIC)) { printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " "reallocate skb buffer\n", dev->name); dev_kfree_skb_any(skb); return 0; } } /* We now have an skb with enough head and tail room, so just insert * the extra data */#ifdef PRISM2_ADD_BOGUS_CRC memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */#endif /* PRISM2_ADD_BOGUS_CRC */ if (prism_header == 1) { struct linux_wlan_ng_prism_hdr *hdr; hdr = (struct linux_wlan_ng_prism_hdr *) skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->msgcode = LWNG_CAP_DID_BASE; hdr->msglen = sizeof(*hdr); memcpy(hdr->devname, dev->name, sizeof(hdr->devname));#define LWNG_SETVAL(f,i,s,l,d) \hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \hdr->f.status = s; hdr->f.len = l; hdr->f.data = d LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); LWNG_SETVAL(istx, 9, 0, 4, 0); LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen);#undef LWNG_SETVAL } else if (prism_header == 2) { struct linux_wlan_ng_cap_hdr *hdr; hdr = (struct linux_wlan_ng_cap_hdr *) skb_push(skb, phdrlen); memset(hdr, 0, phdrlen); hdr->version = htonl(LWNG_CAPHDR_VERSION); hdr->length = htonl(phdrlen); hdr->mactime = __cpu_to_be64(rx_stats->mac_time); hdr->hosttime = __cpu_to_be64(jiffies); hdr->phytype = htonl(4); /* dss_dot11_b */ hdr->channel = htonl(local->channel); hdr->datarate = htonl(rx_stats->rate); hdr->antenna = htonl(0); /* unknown */ hdr->priority = htonl(0); /* unknown */ hdr->ssi_type = htonl(3); /* raw */ hdr->ssi_signal = htonl(rx_stats->signal); hdr->ssi_noise = htonl(rx_stats->noise); hdr->preamble = htonl(0); /* unknown */ hdr->encoding = htonl(1); /* cck */ } ret = skb->len - phdrlen; skb->dev = dev; skb->mac.raw = skb->data; skb_pull(skb, hdrlen); if (prism_header) skb_pull(skb, phdrlen); skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_802_2); memset(skb->cb, 0, sizeof(skb->cb)); netif_rx(skb); return ret;}/* Called only as a tasklet (software IRQ) */static void monitor_rx(struct net_device *dev, struct sk_buff *skb, struct hostap_80211_rx_status *rx_stats){ struct net_device_stats *stats; int len; len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); stats = hostap_get_stats(dev); stats->rx_packets++; stats->rx_bytes += len;}/* Called only as a tasklet (software IRQ) */static struct prism2_frag_entry *prism2_frag_cache_find(local_info_t *local, unsigned int seq, unsigned int frag, u8 *src, u8 *dst){ struct prism2_frag_entry *entry; int i; for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { entry = &local->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", local->dev->name, entry->seq, entry->last_frag); dev_kfree_skb(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 *prism2_frag_cache_get(local_info_t *local, struct hostap_ieee80211_hdr *hdr){ struct sk_buff *skb = NULL; u16 sc; unsigned int frag, seq; struct prism2_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(local->dev->mtu + sizeof(struct hostap_ieee80211_hdr) + 8 /* LLC */ + 2 /* alignment */ + 8 /* WEP */ + ETH_ALEN /* WDS */); if (skb == NULL) return NULL; entry = &local->frag_cache[local->frag_next_idx]; local->frag_next_idx++; if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) local->frag_next_idx = 0; if (entry->skb != NULL) dev_kfree_skb(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 = prism2_frag_cache_find(local, 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 prism2_frag_cache_invalidate(local_info_t *local, struct hostap_ieee80211_hdr *hdr){ u16 sc; unsigned int seq; struct prism2_frag_entry *entry; sc = le16_to_cpu(hdr->seq_ctrl); seq = WLAN_GET_SEQ_SEQ(sc); entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); if (entry == NULL) { printk(KERN_DEBUG "%s: could not invalidate fragment cache " "entry (seq=%u)\n", local->dev->name, seq); return -1; } entry->skb = NULL; return 0;}static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, u8 *ssid, size_t ssid_len){ struct list_head *ptr; struct hostap_bss_info *bss; list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && (ssid == NULL || (ssid_len == bss->ssid_len && memcmp(ssid, bss->ssid, ssid_len) == 0))) { list_move(&bss->list, &local->bss_list); return bss; } } return NULL;}static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, u8 *ssid, size_t ssid_len){ struct hostap_bss_info *bss; if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { bss = list_entry(local->bss_list.prev, struct hostap_bss_info, list); list_del(&bss->list); local->num_bss_info--; } else { bss = (struct hostap_bss_info *) kmalloc(sizeof(*bss), GFP_ATOMIC); if (bss == NULL) return NULL; } memset(bss, 0, sizeof(*bss)); memcpy(bss->bssid, bssid, ETH_ALEN); memcpy(bss->ssid, ssid, ssid_len); bss->ssid_len = ssid_len; local->num_bss_info++; list_add(&bss->list, &local->bss_list); return bss;}static void __hostap_expire_bss(local_info_t *local){ struct hostap_bss_info *bss; while (local->num_bss_info > 0) { bss = list_entry(local->bss_list.prev, struct hostap_bss_info, list); if (!time_after(jiffies, bss->last_update + 60 * HZ)) break; list_del(&bss->list); local->num_bss_info--; kfree(bss); }}/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so * the same routine can be used to parse both of them. */static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, int stype){ struct hostap_ieee80211_mgmt *mgmt; int left, chan = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -