Better handling or received frames, especially management ones. Signed-off-by: Jiri Benc Signed-off-by: Jirka Bohac Index: netdev/include/net/ieee80211.h =================================================================== --- netdev.orig/include/net/ieee80211.h 2005-09-17 15:12:37.000000000 +0200 +++ netdev/include/net/ieee80211.h 2005-09-17 15:13:47.000000000 +0200 @@ -333,11 +333,9 @@ enum ieee80211_reasoncode { WLAN_REASON_CIPHER_SUITE_REJECTED = 24, }; -#define IEEE80211_STATMASK_SIGNAL (1<<0) -#define IEEE80211_STATMASK_RSSI (1<<1) -#define IEEE80211_STATMASK_NOISE (1<<2) -#define IEEE80211_STATMASK_RATE (1<<3) -#define IEEE80211_STATMASK_WEMASK 0x7 +#define IEEE80211_RSSI_CAP_SIGNAL 1 /* signal field is valid */ +#define IEEE80211_RSSI_CAP_QUAL 2 /* signal - noise difference is valid */ +#define IEEE80211_RSSI_CAP_SIGNAL_NOISE 3 /* both signal and noise fields are valid */ enum ieee80211_modulation { IEEE80211_DSSS_MODULATION, @@ -463,20 +461,14 @@ struct ieee80211_xmit_info { u16 xmit_flags; /* WLAN_CAPABILITY_SHORT_PREAMBLE, WLAN_CAPABILITY_SHORT_SLOT_TIME */ }; -/* NOTE: This data is for statistical purposes; not all hardware provides this - * information for frames received. Not setting these will not cause - * any adverse affects. */ -struct ieee80211_rx_stats { - u32 mac_time; - s8 rssi; - u8 signal; - u8 noise; +struct ieee80211_rx_info { + unsigned long mac_time; + int signal; /* in dBm; both signal and noise have to be */ + int noise; /* set, at least to a reasonable constant value */ + int channel; int modulation; /* ieee80211_modulation constant */ int rate; /* ieee80211_rate constant */ - u8 received_channel; - u8 control; - u8 mask; - u16 len; + u16 rx_flags; }; /* IEEE 802.11 requires that STA supports concurrent reception of at least @@ -698,13 +690,13 @@ struct ieee80211_network { u8 ssid[IW_ESSID_MAX_SIZE + 1]; u8 ssid_len; - /* These are network statistics */ - struct ieee80211_rx_stats stats; u16 capability; unsigned modulations; /* modulations supported by the network */ u32 rates; /* rates belonging to the basic rate set */ u32 rates_ex; /* extra rates supported by the network */ unsigned long last_scanned; + int signal; /* signal/noise from last beacon */ + int noise; u8 flags; u32 last_associate; u32 time_stamp[2]; @@ -751,6 +743,8 @@ enum ieee80211_state { #define IEEE80211_CFG_PROBE_REQ (1 << 7) /* generate probe responses */ #define IEEE80211_CFG_PROBE_RESP (1 << 8) +/* frames passed to ieee80211_rx have FCS at the end */ +#define IEEE80211_CFG_RX_FCS (1 << 9) struct ieee80211_device { struct net_device *dev; @@ -779,6 +773,8 @@ struct ieee80211_device { /* Modulations and rates supported by the device */ unsigned supported_modulations; u32 supported_rates; + int rssi_flags; /* set by the driver to one of IEEE80211_RSSI_CAP_ + constants */ /* WEP and other encryption related settings at the device level */ int open_wep; /* Set to 1 to allow unencrypted frames */ @@ -1012,10 +1008,7 @@ extern void ieee80211_reset_queue(struct /* ieee80211_rx.c */ extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats); -extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr *header, - struct ieee80211_rx_stats *stats); + struct ieee80211_rx_info *info); /* ieee80211_wx.c */ extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, Index: netdev/net/ieee80211/ieee80211_rx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_rx.c 2005-09-17 15:05:51.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_rx.c 2005-09-17 15:18:57.000000000 +0200 @@ -36,9 +36,13 @@ #include +static int ieee80211_rx_mgmt(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_info *info); + static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) + struct ieee80211_rx_info *info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -159,63 +163,6 @@ static int ieee80211_frag_cache_invalida return 0; } -#ifdef NOT_YET -/* ieee80211_rx_frame_mgtmt - * - * Responsible for handling management control frames - * - * Called by ieee80211_rx */ -static inline int -ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, u16 type, - u16 stype) -{ - if (ieee->iw_mode == IW_MODE_MASTER) { - printk(KERN_DEBUG "%s: Master mode not yet suppported.\n", - ieee80211_dev(ieee)->name); - return 0; -/* - hostap_update_sta_ps(ieee, (struct hostap_ieee80211_hdr *) - skb->data);*/ - } - - if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) { - if (stype == WLAN_FC_STYPE_BEACON && - ieee->iw_mode == IW_MODE_MASTER) { - struct sk_buff *skb2; - /* Process beacon frames also in kernel driver to - * update STA(AP) table statistics */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - hostap_rx(skb2->dev, skb2, rx_stats); - } - - /* send management frames to the user space daemon for - * processing */ - ieee->apdevstats.rx_packets++; - ieee->apdevstats.rx_bytes += skb->len; - prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT); - return 0; - } - - if (ieee->iw_mode == IW_MODE_MASTER) { - if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { - printk(KERN_DEBUG "%s: unknown management frame " - "(type=0x%02x, stype=0x%02x) dropped\n", - skb->dev->name, type, stype); - return -1; - } - - hostap_rx(skb->dev, skb, rx_stats); - return 0; - } - - printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame " - "received in non-Host AP mode\n", skb->dev->name); - return -1; -} -#endif - /* Called by ieee80211_rx_frame_decrypt */ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, struct sk_buff *skb) @@ -372,12 +319,15 @@ unsigned short ieee80211_type_trans(stru } skb->input_dev = ieee->dev; - if (is_broadcast_ether_addr(daddr)) - skb->pkt_type = PACKET_BROADCAST; - else if (is_multicast_ether_addr(daddr)) - skb->pkt_type = PACKET_MULTICAST; - else if (memcmp(daddr, ieee->dev->dev_addr, IEEE80211_ALEN)) - skb->pkt_type = PACKET_OTHERHOST; + + if (!skb->pkt_type) { + if (is_broadcast_ether_addr(daddr)) + skb->pkt_type = PACKET_BROADCAST; + else if (is_multicast_ether_addr(daddr)) + skb->pkt_type = PACKET_MULTICAST; + else if (memcmp(daddr, ieee->dev->dev_addr, IEEE80211_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + } return type; } @@ -386,7 +336,7 @@ unsigned short ieee80211_type_trans(stru * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) + struct ieee80211_rx_info *info) { struct net_device *dev = ieee80211_dev(ieee); struct ieee80211_hdr *hdr; @@ -402,25 +352,34 @@ int ieee80211_rx(struct ieee80211_device int from_assoc_ap = 0; void *sta = NULL; #endif - u8 dst[IEEE80211_ALEN]; - u8 src[IEEE80211_ALEN]; + u8 *daddr, *saddr, *bssid; struct ieee80211_crypt_data *crypt = NULL; int keyidx = 0; hdr = (struct ieee80211_hdr *)skb->data; stats = &ieee->stats; - if (skb->len < 10) { + if (skb->len < IEEE80211_1ADDR_LEN + IEEE80211_FCS_LEN) { printk(KERN_INFO "%s: SKB length < 10\n", dev->name); goto rx_dropped; } + if (ieee->config & IEEE80211_CFG_RX_FCS) { + /* TODO: check FCS */ + skb_pull(skb, IEEE80211_FCS_LEN); + } fc = le16_to_cpu(hdr->frame_ctl); type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); + hdrlen = __ieee80211_get_hdrlen(fc); + + if (skb->len < hdrlen) + goto rx_dropped; + if (type == IEEE80211_FTYPE_CTL) + goto rx_receive; + sc = le16_to_cpu(hdr->seq_ctl); frag = WLAN_GET_SEQ_FRAG(sc); - hdrlen = __ieee80211_get_hdrlen(fc); /* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */ @@ -458,7 +417,7 @@ int ieee80211_rx(struct ieee80211_device #endif if (ieee->iw_mode == IW_MODE_MONITOR) { - ieee80211_monitor_rx(ieee, skb, rx_stats); + ieee80211_monitor_rx(ieee, skb, info); stats->rx_packets++; stats->rx_bytes += skb->len; return 1; @@ -522,32 +481,57 @@ int ieee80211_rx(struct ieee80211_device } #endif - /* Data frame - extract src/dst addresses */ - if (skb->len < IEEE80211_3ADDR_LEN) - goto rx_dropped; - + /* Extract src/dst addresses */ switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, IEEE80211_ALEN); - memcpy(src, hdr->addr3, IEEE80211_ALEN); + daddr = hdr->addr1; + saddr = hdr->addr3; + bssid = hdr->addr2; break; case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, IEEE80211_ALEN); - memcpy(src, hdr->addr2, IEEE80211_ALEN); + daddr = hdr->addr3; + saddr = hdr->addr2; + bssid = hdr->addr1; break; case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: if (skb->len < IEEE80211_4ADDR_LEN) goto rx_dropped; - memcpy(dst, hdr->addr3, IEEE80211_ALEN); - memcpy(src, hdr->addr4, IEEE80211_ALEN); + daddr = hdr->addr3; + saddr = hdr->addr4; /* FIXME: this is wrong */ + bssid = NULL; break; case 0: - memcpy(dst, hdr->addr1, IEEE80211_ALEN); - memcpy(src, hdr->addr2, IEEE80211_ALEN); + default: + daddr = hdr->addr1; + saddr = hdr->addr2; + bssid = hdr->addr3; break; } + if (bssid && memcmp(bssid, ieee->bssid, IEEE80211_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + else if (is_broadcast_ether_addr(daddr)) + skb->pkt_type = PACKET_BROADCAST; + else if (is_multicast_ether_addr(daddr)) + skb->pkt_type = PACKET_MULTICAST; + else if (memcmp(daddr, dev->dev_addr, IEEE80211_ALEN)) + skb->pkt_type = PACKET_OTHERHOST; + else + skb->pkt_type = PACKET_HOST; + + if ((skb->pkt_type == PACKET_BROADCAST || skb->pkt_type == PACKET_MULTICAST) + && !memcmp(saddr, dev->dev_addr, IEEE80211_ALEN)) { + /* ignore our own broadcast and multicast frames */ + goto rx_silently_dropped; + } + + if (type == IEEE80211_FTYPE_MGMT && + (skb->pkt_type != PACKET_OTHERHOST || + stype == IEEE80211_STYPE_PROBE_RESP || + stype == IEEE80211_STYPE_BEACON)) + return ieee80211_rx_mgmt(ieee, skb, info); + #ifdef NOT_YET if (hostap_rx_frame_wds(ieee, hdr, fc, &wds)) goto rx_dropped; @@ -757,6 +741,7 @@ int ieee80211_rx(struct ieee80211_device } #endif +rx_receive: if (skb) { skb->protocol = ieee80211_type_trans(skb, ieee); memset(skb->cb, 0, sizeof(skb->cb)); @@ -775,6 +760,7 @@ int ieee80211_rx(struct ieee80211_device rx_dropped: stats->rx_dropped++; +rx_silently_dropped: /* Returning 0 indicates to caller that we have not handled the SKB-- * so it is still allocated and can be used again by underlying * hardware as a DMA target */ @@ -783,10 +769,11 @@ int ieee80211_rx(struct ieee80211_device #define MGMT_FRAME_FIXED_PART_LENGTH 0x24 -static inline int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee80211_probe_response - *beacon, +static inline int ieee80211_network_init(struct ieee80211_device *ieee, + struct ieee80211_probe_response *beacon, + int len, struct ieee80211_network *network, - struct ieee80211_rx_stats *stats) + struct ieee80211_rx_info *info) { #ifdef CONFIG_IEEE80211_DEBUG char rates_str[64]; @@ -812,17 +799,17 @@ static inline int ieee80211_network_init network->flags = 0; network->atim_window = 0; - network->modulations = 1 << stats->modulation; + network->modulations = 1 << info->modulation; if (IEEE80211_HAS_52GHZ_MODE(network->modulations)) { /* for A band (No DS info) */ - network->channel = stats->received_channel; + network->channel = info->channel; } network->wpa_ie_len = 0; network->rsn_ie_len = 0; info_element = beacon->info_element; - left = stats->len - sizeof(*beacon); + left = len - sizeof(*beacon); while (left >= sizeof(struct ieee80211_info_element)) { if (sizeof(struct ieee80211_info_element) + info_element->len > left) { @@ -958,7 +945,8 @@ static inline int ieee80211_network_init if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) network->flags |= NETWORK_EMPTY_ESSID; - memcpy(&network->stats, stats, sizeof(network->stats)); + network->signal = info->signal; + network->noise = info->noise; return 0; } @@ -978,7 +966,8 @@ static inline int is_same_network(struct static inline void update_network(struct ieee80211_network *dst, struct ieee80211_network *src) { - memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); + dst->signal = src->signal; + dst->noise = src->noise; dst->capability = src->capability; dst->modulations = src->modulations; dst->rates = src->rates; @@ -1001,11 +990,11 @@ static inline void update_network(struct /* dst->last_associate is not overwritten */ } -static inline void ieee80211_process_probe_response(struct ieee80211_device - *ieee, struct - ieee80211_probe_response - *beacon, struct ieee80211_rx_stats - *stats) +static inline void ieee80211_process_probe_response(struct ieee80211_device *ieee, + struct ieee80211_probe_response + *beacon, + int len, + struct ieee80211_rx_info *info) { struct ieee80211_network network; struct ieee80211_network *target; @@ -1037,7 +1026,7 @@ static inline void ieee80211_process_pro (beacon->capability & (1 << 0x1)) ? '1' : '0', (beacon->capability & (1 << 0x0)) ? '1' : '0'); - if (ieee80211_network_init(ieee, beacon, &network, stats)) { + if (ieee80211_network_init(ieee, beacon, len, &network, info)) { IEEE80211_DEBUG_SCAN("Dropped '%s' (" MAC_FMT ") via %s.\n", escape_essid(info_element->data, info_element->len), @@ -1119,56 +1108,60 @@ static inline void ieee80211_process_pro spin_unlock_irqrestore(&ieee->lock, flags); } -void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr *header, - struct ieee80211_rx_stats *stats) +static int ieee80211_rx_mgmt(struct ieee80211_device *ieee, + struct sk_buff *skb, + struct ieee80211_rx_info *info) { - switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + switch (ieee80211_get_stype(hdr)) { case IEEE80211_STYPE_ASSOC_RESP: IEEE80211_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); break; case IEEE80211_STYPE_REASSOC_RESP: IEEE80211_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); break; case IEEE80211_STYPE_PROBE_RESP: IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); IEEE80211_DEBUG_SCAN("Probe response\n"); ieee80211_process_probe_response(ieee, (struct ieee80211_probe_response *) - header, stats); + hdr, skb->len, info); break; case IEEE80211_STYPE_BEACON: IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); IEEE80211_DEBUG_SCAN("Beacon\n"); ieee80211_process_probe_response(ieee, (struct ieee80211_probe_response *) - header, stats); + hdr, skb->len, info); break; default: IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); IEEE80211_WARNING("%s: Unknown management packet: %d\n", ieee80211_dev(ieee)->name, WLAN_FC_GET_STYPE(le16_to_cpu - (header->frame_ctl))); + (hdr->frame_ctl))); break; } + + dev_kfree_skb_any(skb); + return 0; } -EXPORT_SYMBOL(ieee80211_rx_mgt); EXPORT_SYMBOL(ieee80211_rx); Index: netdev/net/ieee80211/ieee80211_wx.c =================================================================== --- netdev.orig/net/ieee80211/ieee80211_wx.c 2005-09-17 14:59:05.000000000 +0200 +++ netdev/net/ieee80211/ieee80211_wx.c 2005-09-17 15:20:25.000000000 +0200 @@ -134,37 +134,16 @@ static inline char *ipw2100_translate_sc /* Add quality statistics */ iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | - IW_QUAL_NOISE_UPDATED; - - if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) { - iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID | - IW_QUAL_LEVEL_INVALID; - iwe.u.qual.qual = 0; - iwe.u.qual.level = 0; - } else { - iwe.u.qual.level = network->stats.rssi; - iwe.u.qual.qual = - (100 * - (ieee->perfect_rssi - ieee->worst_rssi) * - (ieee->perfect_rssi - ieee->worst_rssi) - - (ieee->perfect_rssi - network->stats.rssi) * - (15 * (ieee->perfect_rssi - ieee->worst_rssi) + - 62 * (ieee->perfect_rssi - network->stats.rssi))) / - ((ieee->perfect_rssi - ieee->worst_rssi) * - (ieee->perfect_rssi - ieee->worst_rssi)); - if (iwe.u.qual.qual > 100) - iwe.u.qual.qual = 100; - else if (iwe.u.qual.qual < 1) - iwe.u.qual.qual = 0; - } - - if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) { - iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; - iwe.u.qual.noise = 0; - } else { - iwe.u.qual.noise = network->stats.noise; - } + iwe.u.qual.qual = network->signal - network->noise; + iwe.u.qual.level = network->signal; + iwe.u.qual.noise = network->noise; + if (ieee->rssi_flags == IEEE80211_RSSI_CAP_SIGNAL) + iwe.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; + else if (ieee->rssi_flags == IEEE80211_RSSI_CAP_QUAL) + iwe.u.qual.updated = IW_QUAL_LEVEL_INVALID | IW_QUAL_NOISE_INVALID; + else if (ieee->rssi_flags != IEEE80211_RSSI_CAP_SIGNAL_NOISE) + iwe.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + iwe.u.qual.updated |= (~iwe.u.qual.updated >> 4) & 7; start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);