diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 3 | ||||
-rw-r--r-- | net/core/Makefile | 2 | ||||
-rw-r--r-- | net/core/dev.c | 36 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt.c | 11 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_ccmp.c | 8 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 56 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_crypt_wep.c | 5 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_geo.c | 48 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_module.c | 20 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_rx.c | 167 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_tx.c | 30 | ||||
-rw-r--r-- | net/ieee80211/ieee80211_wx.c | 152 | ||||
-rw-r--r-- | net/socket.c | 9 |
13 files changed, 440 insertions, 107 deletions
diff --git a/net/Kconfig b/net/Kconfig index 5126f58..4193cdc 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -224,6 +224,9 @@ source "net/irda/Kconfig" source "net/bluetooth/Kconfig" source "net/ieee80211/Kconfig" +config WIRELESS_EXT + bool + endif # if NET endmenu # Networking diff --git a/net/core/Makefile b/net/core/Makefile index 630da0f..79fe12c 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -14,5 +14,5 @@ obj-$(CONFIG_XFRM) += flow.o obj-$(CONFIG_SYSFS) += net-sysfs.o obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o -obj-$(CONFIG_NET_RADIO) += wireless.o +obj-$(CONFIG_WIRELESS_EXT) += wireless.o obj-$(CONFIG_NETPOLL) += netpoll.o diff --git a/net/core/dev.c b/net/core/dev.c index 2afb0de..ef56c035 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -110,10 +110,8 @@ #include <linux/netpoll.h> #include <linux/rcupdate.h> #include <linux/delay.h> -#ifdef CONFIG_NET_RADIO -#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ +#include <linux/wireless.h> #include <net/iw_handler.h> -#endif /* CONFIG_NET_RADIO */ #include <asm/current.h> /* @@ -1448,8 +1446,29 @@ static inline struct net_device *skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; - if (dev->master) + if (dev->master) { + /* + * On bonding slaves other than the currently active + * slave, suppress duplicates except for 802.3ad + * ETH_P_SLOW and alb non-mcast/bcast. + */ + if (dev->priv_flags & IFF_SLAVE_INACTIVE) { + if (dev->master->priv_flags & IFF_MASTER_ALB) { + if (skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) + goto keep; + } + + if (dev->master->priv_flags & IFF_MASTER_8023AD && + skb->protocol == __constant_htons(ETH_P_SLOW)) + goto keep; + + kfree_skb(skb); + return NULL; + } +keep: skb->dev = dev->master; + } return dev; } @@ -1593,6 +1612,9 @@ int netif_receive_skb(struct sk_buff *skb) orig_dev = skb_bond(skb); + if (!orig_dev) + return NET_RX_DROP; + __get_cpu_var(netdev_rx_stat).total++; skb->h.raw = skb->nh.raw = skb->data; @@ -2028,7 +2050,7 @@ static struct file_operations softnet_seq_fops = { .release = seq_release, }; -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT extern int wireless_proc_init(void); #else #define wireless_proc_init() 0 @@ -2582,7 +2604,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT /* Take care of Wireless Extensions */ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { /* If command is `set a parameter', or @@ -2603,7 +2625,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) ret = -EFAULT; return ret; } -#endif /* WIRELESS_EXT */ +#endif /* CONFIG_WIRELESS_EXT */ return -EINVAL; } } diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c index ecc9bb1..cb71d79 100644 --- a/net/ieee80211/ieee80211_crypt.c +++ b/net/ieee80211/ieee80211_crypt.c @@ -18,7 +18,6 @@ #include <linux/string.h> #include <net/ieee80211.h> - MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("HostAP crypto"); MODULE_LICENSE("GPL"); @@ -33,11 +32,11 @@ static DEFINE_SPINLOCK(ieee80211_crypto_lock); void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) { - struct ieee80211_crypt_data *entry, *next; + struct ieee80211_crypt_data *entry, *next; unsigned long flags; spin_lock_irqsave(&ieee->lock, flags); - list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) { + list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) { if (atomic_read(&entry->refcnt) != 0 && !force) continue; @@ -141,9 +140,9 @@ int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); return -EINVAL; - found: + found: printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " - "'%s'\n", ops->name); + "'%s'\n", ops->name); list_del(&alg->list); spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); kfree(alg); @@ -163,7 +162,7 @@ struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); return NULL; - found: + found: spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); return alg->ops; } diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c index 3840d19..78b2d13 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/ieee80211/ieee80211_crypt_ccmp.c @@ -190,7 +190,8 @@ static void ccmp_init_blocks(struct crypto_tfm *tfm, ieee80211_ccmp_aes_encrypt(tfm, b0, s0); } -static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) +static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, + u8 *aeskey, int keylen, void *priv) { struct ieee80211_ccmp_data *key = priv; int i; @@ -199,6 +200,9 @@ static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, void *priv) if (skb_headroom(skb) < CCMP_HDR_LEN || skb->len < hdr_len) return -1; + if (aeskey != NULL && keylen >= CCMP_TK_LEN) + memcpy(aeskey, key->key, CCMP_TK_LEN); + pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdr_len); pos += hdr_len; @@ -238,7 +242,7 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; data_len = skb->len - hdr_len; - len = ieee80211_ccmp_hdr(skb, hdr_len, priv); + len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv); if (len < 0) return -1; diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index e098832..93def94 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c @@ -80,10 +80,9 @@ static void *ieee80211_tkip_init(int key_idx) { struct ieee80211_tkip_data *priv; - priv = kmalloc(sizeof(*priv), GFP_ATOMIC); + priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) goto fail; - memset(priv, 0, sizeof(*priv)); priv->key_idx = key_idx; @@ -271,34 +270,33 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, #endif } -static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) +static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, + u8 * rc4key, int keylen, void *priv) { struct ieee80211_tkip_data *tkey = priv; int len; - u8 *rc4key, *pos, *icv; + u8 *pos; struct ieee80211_hdr_4addr *hdr; - u32 crc; hdr = (struct ieee80211_hdr_4addr *)skb->data; if (skb_headroom(skb) < 8 || skb->len < hdr_len) - return NULL; + return -1; + + if (rc4key == NULL || keylen < 16) + return -1; if (!tkey->tx_phase1_done) { tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, tkey->tx_iv32); tkey->tx_phase1_done = 1; } - rc4key = kmalloc(16, GFP_ATOMIC); - if (!rc4key) - return NULL; tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); len = skb->len - hdr_len; pos = skb_push(skb, 8); memmove(pos, pos + 8, hdr_len); pos += hdr_len; - icv = skb_put(skb, 4); *pos++ = *rc4key; *pos++ = *(rc4key + 1); @@ -309,28 +307,28 @@ static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv) *pos++ = (tkey->tx_iv32 >> 16) & 0xff; *pos++ = (tkey->tx_iv32 >> 24) & 0xff; - crc = ~crc32_le(~0, pos, len); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; + tkey->tx_iv16++; + if (tkey->tx_iv16 == 0) { + tkey->tx_phase1_done = 0; + tkey->tx_iv32++; + } - return rc4key; + return 8; } static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { struct ieee80211_tkip_data *tkey = priv; int len; - const u8 *rc4key; - u8 *pos; + u8 rc4key[16], *pos, *icv; + u32 crc; struct scatterlist sg; if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *)skb->data; - printk(KERN_DEBUG "TKIP countermeasures: dropped " + printk(KERN_DEBUG ": TKIP countermeasures: dropped " "TX packet to " MAC_FMT "\n", MAC_ARG(hdr->addr1)); } @@ -343,22 +341,23 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) len = skb->len - hdr_len; pos = skb->data + hdr_len; - rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv); - if (!rc4key) + if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) return -1; + icv = skb_put(skb, 4); + + crc = ~crc32_le(~0, pos, len); + icv[0] = crc; + icv[1] = crc >> 8; + icv[2] = crc >> 16; + icv[3] = crc >> 24; + crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16); sg.page = virt_to_page(pos); sg.offset = offset_in_page(pos); sg.length = len + 4; crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4); - tkey->tx_iv16++; - if (tkey->tx_iv16 == 0) { - tkey->tx_phase1_done = 0; - tkey->tx_iv32++; - } - return 0; } @@ -379,7 +378,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP countermeasures: dropped " + printk(KERN_DEBUG ": TKIP countermeasures: dropped " "received packet from " MAC_FMT "\n", MAC_ARG(hdr->addr2)); } @@ -695,6 +694,7 @@ static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { .name = "TKIP", .init = ieee80211_tkip_init, .deinit = ieee80211_tkip_deinit, + .build_iv = ieee80211_tkip_hdr, .encrypt_mpdu = ieee80211_tkip_encrypt, .decrypt_mpdu = ieee80211_tkip_decrypt, .encrypt_msdu = ieee80211_michael_mic_add, diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c index f8dca31..649e581 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/ieee80211/ieee80211_crypt_wep.c @@ -76,7 +76,8 @@ static void prism2_wep_deinit(void *priv) } /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ -static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, void *priv) +static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, + u8 *key, int keylen, void *priv) { struct prism2_wep_data *wep = priv; u32 klen, len; @@ -131,7 +132,7 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; /* add the IV to the frame */ - if (prism2_wep_build_iv(skb, hdr_len, priv)) + if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv)) return -1; /* Copy the IV into the first 3 bytes of the key */ diff --git a/net/ieee80211/ieee80211_geo.c b/net/ieee80211/ieee80211_geo.c index 610cc5c..192243a 100644 --- a/net/ieee80211/ieee80211_geo.c +++ b/net/ieee80211/ieee80211_geo.c @@ -50,7 +50,8 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) /* Driver needs to initialize the geography map before using * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return 0; if (ieee->freq_band & IEEE80211_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) @@ -58,13 +59,15 @@ int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel) * this is a B only channel, we don't see it * as valid. */ if ((ieee->geo.bg[i].channel == channel) && + !(ieee->geo.bg[i].flags & IEEE80211_CH_INVALID) && (!(ieee->mode & IEEE_G) || !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) return IEEE80211_24GHZ_BAND; if (ieee->freq_band & IEEE80211_52GHZ_BAND) for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].channel == channel) + if ((ieee->geo.a[i].channel == channel) && + !(ieee->geo.a[i].flags & IEEE80211_CH_INVALID)) return IEEE80211_52GHZ_BAND; return 0; @@ -76,7 +79,8 @@ int ieee80211_channel_to_index(struct ieee80211_device *ieee, u8 channel) /* Driver needs to initialize the geography map before using * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return -1; if (ieee->freq_band & IEEE80211_24GHZ_BAND) for (i = 0; i < ieee->geo.bg_channels; i++) @@ -97,7 +101,8 @@ u8 ieee80211_freq_to_channel(struct ieee80211_device * ieee, u32 freq) /* Driver needs to initialize the geography map before using * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); + if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0) + return 0; freq /= 100000; @@ -133,6 +138,41 @@ const struct ieee80211_geo *ieee80211_get_geo(struct ieee80211_device *ieee) return &ieee->geo; } +u8 ieee80211_get_channel_flags(struct ieee80211_device * ieee, u8 channel) +{ + int index = ieee80211_channel_to_index(ieee, channel); + + if (index == -1) + return IEEE80211_CH_INVALID; + + if (channel <= IEEE80211_24GHZ_CHANNELS) + return ieee->geo.bg[index].flags; + + return ieee->geo.a[index].flags; +} + +static const struct ieee80211_channel bad_channel = { + .channel = 0, + .flags = IEEE80211_CH_INVALID, + .max_power = 0, +}; + +const struct ieee80211_channel *ieee80211_get_channel(struct ieee80211_device + *ieee, u8 channel) +{ + int index = ieee80211_channel_to_index(ieee, channel); + + if (index == -1) + return &bad_channel; + + if (channel <= IEEE80211_24GHZ_CHANNELS) + return &ieee->geo.bg[index]; + + return &ieee->geo.a[index]; +} + +EXPORT_SYMBOL(ieee80211_get_channel); +EXPORT_SYMBOL(ieee80211_get_channel_flags); EXPORT_SYMBOL(ieee80211_is_valid_channel); EXPORT_SYMBOL(ieee80211_freq_to_channel); EXPORT_SYMBOL(ieee80211_channel_to_index); diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c index 90d18b7..2cb84d8 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/net/ieee80211/ieee80211_module.c @@ -82,10 +82,28 @@ static int ieee80211_networks_allocate(struct ieee80211_device *ieee) return 0; } +void ieee80211_network_reset(struct ieee80211_network *network) +{ + if (!network) + return; + + if (network->ibss_dfs) { + kfree(network->ibss_dfs); + network->ibss_dfs = NULL; + } +} + static inline void ieee80211_networks_free(struct ieee80211_device *ieee) { + int i; + if (!ieee->networks) return; + + for (i = 0; i < MAX_NETWORK_COUNT; i++) + if (ieee->networks[i].ibss_dfs) + kfree(ieee->networks[i].ibss_dfs); + kfree(ieee->networks); ieee->networks = NULL; } @@ -195,7 +213,7 @@ void free_ieee80211(struct net_device *dev) static int debug = 0; u32 ieee80211_debug_level = 0; -struct proc_dir_entry *ieee80211_proc = NULL; +static struct proc_dir_entry *ieee80211_proc = NULL; static int show_debug_level(char *page, char **start, off_t offset, int count, int *eof, void *data) diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 7ac6a71..a7f2a64 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c @@ -369,8 +369,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* Put this code here so that we avoid duplicating it in all * Rx paths. - Jean II */ +#ifdef CONFIG_WIRELESS_EXT #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ -#ifdef CONFIG_NET_RADIO /* If spy monitoring on */ if (ieee->spy_data.spy_number > 0) { struct iw_quality wstats; @@ -397,8 +397,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* Update spy records */ wireless_spy_update(ieee->dev, hdr->addr2, &wstats); } -#endif /* CONFIG_NET_RADIO */ #endif /* IW_WIRELESS_SPY */ +#endif /* CONFIG_WIRELESS_EXT */ #ifdef NOT_YET hostap_update_rx_stats(local->ap, hdr, rx_stats); @@ -574,7 +574,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, /* skb: hdr + (possibly fragmented) plaintext payload */ // PR: FIXME: hostap has additional conditions in the "if" below: // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && - if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { + if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) { int flen; struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); @@ -754,7 +754,14 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, memset(skb->cb, 0, sizeof(skb->cb)); skb->dev = dev; skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ - netif_rx(skb); + if (netif_rx(skb) == NET_RX_DROP) { + /* netif_rx always succeeds, but it might drop + * the packet. If it drops the packet, we log that + * in our stats. */ + IEEE80211_DEBUG_DROP + ("RX: netif_rx dropped the packet\n"); + stats->rx_dropped++; + } } rx_exit: @@ -930,6 +937,45 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element return rc; } +#ifdef CONFIG_IEEE80211_DEBUG +#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x + +static const char *get_info_element_string(u16 id) +{ + switch (id) { + MFIE_STRING(SSID); + MFIE_STRING(RATES); + MFIE_STRING(FH_SET); + MFIE_STRING(DS_SET); + MFIE_STRING(CF_SET); + MFIE_STRING(TIM); + MFIE_STRING(IBSS_SET); + MFIE_STRING(COUNTRY); + MFIE_STRING(HOP_PARAMS); + MFIE_STRING(HOP_TABLE); + MFIE_STRING(REQUEST); + MFIE_STRING(CHALLENGE); + MFIE_STRING(POWER_CONSTRAINT); + MFIE_STRING(POWER_CAPABILITY); + MFIE_STRING(TPC_REQUEST); + MFIE_STRING(TPC_REPORT); + MFIE_STRING(SUPP_CHANNELS); + MFIE_STRING(CSA); + MFIE_STRING(MEASURE_REQUEST); + MFIE_STRING(MEASURE_REPORT); + MFIE_STRING(QUIET); + MFIE_STRING(IBSS_DFS); + MFIE_STRING(ERP_INFO); + MFIE_STRING(RSN); + MFIE_STRING(RATES_EX); + MFIE_STRING(GENERIC); + MFIE_STRING(QOS_PARAMETER); + default: + return "UNKNOWN"; + } +} +#endif + static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, u16 length, struct ieee80211_network *network) @@ -1040,7 +1086,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element break; case MFIE_TYPE_TIM: - IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: ignored\n"); + network->tim.tim_count = info_element->data[0]; + network->tim.tim_period = info_element->data[1]; + IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n"); break; case MFIE_TYPE_ERP_INFO: @@ -1091,10 +1139,49 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element printk(KERN_ERR "QoS Error need to parse QOS_PARAMETER IE\n"); break; + /* 802.11h */ + case MFIE_TYPE_POWER_CONSTRAINT: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_POWER_CONSTRAINT; + break; + + case MFIE_TYPE_CSA: + network->power_constraint = info_element->data[0]; + network->flags |= NETWORK_HAS_CSA; + break; + + case MFIE_TYPE_QUIET: + network->quiet.count = info_element->data[0]; + network->quiet.period = info_element->data[1]; + network->quiet.duration = info_element->data[2]; + network->quiet.offset = info_element->data[3]; + network->flags |= NETWORK_HAS_QUIET; + break; + + case MFIE_TYPE_IBSS_DFS: + if (network->ibss_dfs) + break; + network->ibss_dfs = + kmalloc(info_element->len, GFP_ATOMIC); + if (!network->ibss_dfs) + return 1; + memcpy(network->ibss_dfs, info_element->data, + info_element->len); + network->flags |= NETWORK_HAS_IBSS_DFS; + break; + + case MFIE_TYPE_TPC_REPORT: + network->tpc_report.transmit_power = + info_element->data[0]; + network->tpc_report.link_margin = info_element->data[1]; + network->flags |= NETWORK_HAS_TPC_REPORT; + break; default: - IEEE80211_DEBUG_MGMT("unsupported IE %d\n", - info_element->id); + IEEE80211_DEBUG_MGMT + ("Unsupported info element: %s (%d)\n", + get_info_element_string(info_element->id), + info_element->id); break; } @@ -1110,7 +1197,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct ieee80211_assoc_response *frame, struct ieee80211_rx_stats *stats) { - struct ieee80211_network network_resp; + struct ieee80211_network network_resp = { + .ibss_dfs = NULL, + }; struct ieee80211_network *network = &network_resp; struct net_device *dev = ieee->dev; @@ -1253,7 +1342,22 @@ static void update_network(struct ieee80211_network *dst, int qos_active; u8 old_param; - memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); + ieee80211_network_reset(dst); + dst->ibss_dfs = src->ibss_dfs; + + /* We only update the statistics if they were created by receiving + * the network information on the actual channel the network is on. + * + * This keeps beacons received on neighbor channels from bringing + * down the signal level of an AP. */ + if (dst->channel == src->stats.received_channel) + memcpy(&dst->stats, &src->stats, + sizeof(struct ieee80211_rx_stats)); + else + IEEE80211_DEBUG_SCAN("Network " MAC_FMT " info received " + "off channel (%d vs. %d)\n", MAC_ARG(src->bssid), + dst->channel, src->stats.received_channel); + dst->capability = src->capability; memcpy(dst->rates, src->rates, src->rates_len); dst->rates_len = src->rates_len; @@ -1269,6 +1373,7 @@ static void update_network(struct ieee80211_network *dst, dst->listen_interval = src->listen_interval; dst->atim_window = src->atim_window; dst->erp_value = src->erp_value; + dst->tim = src->tim; memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); dst->wpa_ie_len = src->wpa_ie_len; @@ -1313,7 +1418,9 @@ static void ieee80211_process_probe_response(struct ieee80211_device *stats) { struct net_device *dev = ieee->dev; - struct ieee80211_network network; + struct ieee80211_network network = { + .ibss_dfs = NULL, + }; struct ieee80211_network *target; struct ieee80211_network *oldest = NULL; #ifdef CONFIG_IEEE80211_DEBUG @@ -1386,6 +1493,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device escape_essid(target->ssid, target->ssid_len), MAC_ARG(target->bssid)); + ieee80211_network_reset(target); } else { /* Otherwise just pull from the free list */ target = list_entry(ieee->network_free_list.next, @@ -1402,6 +1510,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device "BEACON" : "PROBE RESPONSE"); #endif memcpy(target, &network, sizeof(*target)); + network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { IEEE80211_DEBUG_SCAN("Updating '%s' (" MAC_FMT ") via %s.\n", @@ -1411,6 +1520,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); update_network(target, &network); + network.ibss_dfs = NULL; } spin_unlock_irqrestore(&ieee->lock, flags); @@ -1495,10 +1605,43 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, header); break; + case IEEE80211_STYPE_ACTION: + IEEE80211_DEBUG_MGMT("ACTION\n"); + if (ieee->handle_action) + ieee->handle_action(ieee->dev, + (struct ieee80211_action *) + header, stats); + break; + + case IEEE80211_STYPE_REASSOC_REQ: + IEEE80211_DEBUG_MGMT("received reassoc (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n", + ieee->dev->name); + if (ieee->handle_reassoc_request != NULL) + ieee->handle_reassoc_request(ieee->dev, + (struct ieee80211_reassoc_request *) + header); + break; + + case IEEE80211_STYPE_ASSOC_REQ: + IEEE80211_DEBUG_MGMT("received assoc (%d)\n", + WLAN_FC_GET_STYPE(le16_to_cpu + (header->frame_ctl))); + + IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n", + ieee->dev->name); + if (ieee->handle_assoc_request != NULL) + ieee->handle_assoc_request(ieee->dev); + break; + case IEEE80211_STYPE_DEAUTH: - printk("DEAUTH from AP\n"); + IEEE80211_DEBUG_MGMT("DEAUTH\n"); if (ieee->handle_deauth != NULL) - ieee->handle_deauth(ieee->dev, (struct ieee80211_auth *) + ieee->handle_deauth(ieee->dev, + (struct ieee80211_deauth *) header); break; default: diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 8fdd943..8b4332f 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c @@ -56,7 +56,18 @@ Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | `--------------------------------------------------| |------' Total: 28 non-data bytes `----.----' | - .- 'Frame data' expands to <---------------------------' + .- 'Frame data' expands, if WEP enabled, to <----------' + | + V + ,-----------------------. +Bytes | 4 | 0-2296 | 4 | + |-----|-----------|-----| +Desc. | IV | Encrypted | ICV | + | | Packet | | + `-----| |-----' + `-----.-----' + | + .- 'Encrypted Packet' expands to | V ,---------------------------------------------------. @@ -65,18 +76,7 @@ Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | | DSAP | SSAP | | | | Packet | | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | - `-----------------------------------------| | -Total: 8 non-data bytes `----.----' - | - .- 'IP Packet' expands, if WEP enabled, to <--' - | - V - ,-----------------------. -Bytes | 4 | 0-2296 | 4 | - |-----|-----------|-----| -Desc. | IV | Encrypted | ICV | - | | IP Packet | | - `-----------------------' + `---------------------------------------------------- Total: 8 non-data bytes 802.3 Ethernet Data Frame @@ -470,7 +470,9 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) atomic_inc(&crypt->refcnt); if (crypt->ops->build_iv) crypt->ops->build_iv(skb_frag, hdr_len, - crypt->priv); + ieee->sec.keys[ieee->sec.active_key], + ieee->sec.key_sizes[ieee->sec.active_key], + crypt->priv); atomic_dec(&crypt->refcnt); } diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index f87c6b8..af7f9bb 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c @@ -149,9 +149,7 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee, 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; if (ieee->perfect_rssi == ieee->worst_rssi) iwe.u.qual.qual = 100; else @@ -179,6 +177,13 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee, iwe.u.qual.noise = network->stats.noise; } + if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) { + iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; + iwe.u.qual.level = 0; + } else { + iwe.u.qual.level = network->stats.signal; + } + start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); iwe.cmd = IWEVCUSTOM; @@ -188,33 +193,21 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee, if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); + memset(&iwe, 0, sizeof(iwe)); if (network->wpa_ie_len) { - char buf[MAX_WPA_IE_LEN * 2 + 30]; - - u8 *p = buf; - p += sprintf(p, "wpa_ie="); - for (i = 0; i < network->wpa_ie_len; i++) { - p += sprintf(p, "%02x", network->wpa_ie[i]); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = strlen(buf); + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->wpa_ie, network->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->wpa_ie_len; start = iwe_stream_add_point(start, stop, &iwe, buf); } + memset(&iwe, 0, sizeof(iwe)); if (network->rsn_ie_len) { - char buf[MAX_WPA_IE_LEN * 2 + 30]; - - u8 *p = buf; - p += sprintf(p, "rsn_ie="); - for (i = 0; i < network->rsn_ie_len; i++) { - p += sprintf(p, "%02x", network->rsn_ie[i]); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = strlen(buf); + char buf[MAX_WPA_IE_LEN]; + memcpy(buf, network->rsn_ie, network->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = network->rsn_ie_len; start = iwe_stream_add_point(start, stop, &iwe, buf); } @@ -229,6 +222,28 @@ static char *ipw2100_translate_scan(struct ieee80211_device *ieee, if (iwe.u.data.length) start = iwe_stream_add_point(start, stop, &iwe, custom); + /* Add spectrum management information */ + iwe.cmd = -1; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: "); + + if (ieee80211_get_channel_flags(ieee, network->channel) & + IEEE80211_CH_INVALID) { + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID "); + } + + if (ieee80211_get_channel_flags(ieee, network->channel) & + IEEE80211_CH_RADAR_DETECT) { + iwe.cmd = IWEVCUSTOM; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS "); + } + + if (iwe.cmd == IWEVCUSTOM) { + iwe.u.data.length = p - custom; + start = iwe_stream_add_point(start, stop, &iwe, custom); + } + return start; } @@ -734,9 +749,98 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return 0; } +int ieee80211_wx_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&ieee->lock, flags); + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + /* + * Host AP driver does not use these parameters and allows + * wpa_supplicant to control them internally. + */ + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + break; /* FIXME */ + case IW_AUTH_DROP_UNENCRYPTED: + ieee->drop_unencrypted = !!wrqu->param.value; + break; + case IW_AUTH_80211_AUTH_ALG: + break; /* FIXME */ + case IW_AUTH_WPA_ENABLED: + ieee->privacy_invoked = ieee->wpa_enabled = !!wrqu->param.value; + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + ieee->ieee802_1x = !!wrqu->param.value; + break; + case IW_AUTH_PRIVACY_INVOKED: + ieee->privacy_invoked = !!wrqu->param.value; + break; + default: + err = -EOPNOTSUPP; + break; + } + spin_unlock_irqrestore(&ieee->lock, flags); + return err; +} + +int ieee80211_wx_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct ieee80211_device *ieee = netdev_priv(dev); + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&ieee->lock, flags); + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + case IW_AUTH_TKIP_COUNTERMEASURES: /* FIXME */ + case IW_AUTH_80211_AUTH_ALG: /* FIXME */ + /* + * Host AP driver does not use these parameters and allows + * wpa_supplicant to control them internally. + */ + err = -EOPNOTSUPP; + break; + case IW_AUTH_DROP_UNENCRYPTED: + wrqu->param.value = ieee->drop_unencrypted; + break; + case IW_AUTH_WPA_ENABLED: + wrqu->param.value = ieee->wpa_enabled; + break; + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + wrqu->param.value = ieee->ieee802_1x; + break; + default: + err = -EOPNOTSUPP; + break; + } + spin_unlock_irqrestore(&ieee->lock, flags); + return err; +} + EXPORT_SYMBOL(ieee80211_wx_set_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_encodeext); EXPORT_SYMBOL(ieee80211_wx_get_scan); EXPORT_SYMBOL(ieee80211_wx_set_encode); EXPORT_SYMBOL(ieee80211_wx_get_encode); + +EXPORT_SYMBOL_GPL(ieee80211_wx_set_auth); +EXPORT_SYMBOL_GPL(ieee80211_wx_get_auth); diff --git a/net/socket.c b/net/socket.c index a00851f..7e1bdef 100644 --- a/net/socket.c +++ b/net/socket.c @@ -84,10 +84,7 @@ #include <linux/compat.h> #include <linux/kmod.h> #include <linux/audit.h> - -#ifdef CONFIG_NET_RADIO -#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */ -#endif /* CONFIG_NET_RADIO */ +#include <linux/wireless.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -840,11 +837,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { err = dev_ioctl(cmd, argp); } else -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { err = dev_ioctl(cmd, argp); } else -#endif /* WIRELESS_EXT */ +#endif /* CONFIG_WIRELESS_EXT */ switch (cmd) { case FIOSETOWN: case SIOCSPGRP: |