diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/ieee80211/ieee80211_crypt_tkip.c | 11 | ||||
| -rw-r--r-- | net/ieee80211/ieee80211_rx.c | 18 | ||||
| -rw-r--r-- | net/ieee80211/ieee80211_tx.c | 88 | ||||
| -rw-r--r-- | net/ieee80211/ieee80211_wx.c | 44 | ||||
| -rw-r--r-- | net/ieee80211/softmac/Kconfig | 1 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_assoc.c | 96 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_auth.c | 15 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_event.c | 30 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_io.c | 169 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_module.c | 117 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_priv.h | 5 | ||||
| -rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_wx.c | 36 |
12 files changed, 402 insertions, 228 deletions
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c index 93def94c1b32..3fa5df2e1f0b 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/ieee80211/ieee80211_crypt_tkip.c | |||
| @@ -501,8 +501,11 @@ static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr, | |||
| 501 | static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) | 501 | static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) |
| 502 | { | 502 | { |
| 503 | struct ieee80211_hdr_4addr *hdr11; | 503 | struct ieee80211_hdr_4addr *hdr11; |
| 504 | u16 stype; | ||
| 504 | 505 | ||
| 505 | hdr11 = (struct ieee80211_hdr_4addr *)skb->data; | 506 | hdr11 = (struct ieee80211_hdr_4addr *)skb->data; |
| 507 | stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl)); | ||
| 508 | |||
| 506 | switch (le16_to_cpu(hdr11->frame_ctl) & | 509 | switch (le16_to_cpu(hdr11->frame_ctl) & |
| 507 | (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | 510 | (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { |
| 508 | case IEEE80211_FCTL_TODS: | 511 | case IEEE80211_FCTL_TODS: |
| @@ -523,7 +526,13 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) | |||
| 523 | break; | 526 | break; |
| 524 | } | 527 | } |
| 525 | 528 | ||
| 526 | hdr[12] = 0; /* priority */ | 529 | if (stype & IEEE80211_STYPE_QOS_DATA) { |
| 530 | const struct ieee80211_hdr_3addrqos *qoshdr = | ||
| 531 | (struct ieee80211_hdr_3addrqos *)skb->data; | ||
| 532 | hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID; | ||
| 533 | } else | ||
| 534 | hdr[12] = 0; /* priority */ | ||
| 535 | |||
| 527 | hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ | 536 | hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ |
| 528 | } | 537 | } |
| 529 | 538 | ||
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c index 604b7b0097bc..2bf567fd5a17 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/net/ieee80211/ieee80211_rx.c | |||
| @@ -369,7 +369,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
| 369 | 369 | ||
| 370 | /* Put this code here so that we avoid duplicating it in all | 370 | /* Put this code here so that we avoid duplicating it in all |
| 371 | * Rx paths. - Jean II */ | 371 | * Rx paths. - Jean II */ |
| 372 | #ifdef CONFIG_WIRELESS_EXT | ||
| 373 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | 372 | #ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ |
| 374 | /* If spy monitoring on */ | 373 | /* If spy monitoring on */ |
| 375 | if (ieee->spy_data.spy_number > 0) { | 374 | if (ieee->spy_data.spy_number > 0) { |
| @@ -398,7 +397,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, | |||
| 398 | wireless_spy_update(ieee->dev, hdr->addr2, &wstats); | 397 | wireless_spy_update(ieee->dev, hdr->addr2, &wstats); |
| 399 | } | 398 | } |
| 400 | #endif /* IW_WIRELESS_SPY */ | 399 | #endif /* IW_WIRELESS_SPY */ |
| 401 | #endif /* CONFIG_WIRELESS_EXT */ | ||
| 402 | 400 | ||
| 403 | #ifdef NOT_YET | 401 | #ifdef NOT_YET |
| 404 | hostap_update_rx_stats(local->ap, hdr, rx_stats); | 402 | hostap_update_rx_stats(local->ap, hdr, rx_stats); |
| @@ -1692,8 +1690,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
| 1692 | WLAN_FC_GET_STYPE(le16_to_cpu | 1690 | WLAN_FC_GET_STYPE(le16_to_cpu |
| 1693 | (header->frame_ctl))); | 1691 | (header->frame_ctl))); |
| 1694 | 1692 | ||
| 1695 | IEEE80211_WARNING("%s: IEEE80211_REASSOC_REQ received\n", | 1693 | IEEE80211_DEBUG_MGMT("%s: IEEE80211_REASSOC_REQ received\n", |
| 1696 | ieee->dev->name); | 1694 | ieee->dev->name); |
| 1697 | if (ieee->handle_reassoc_request != NULL) | 1695 | if (ieee->handle_reassoc_request != NULL) |
| 1698 | ieee->handle_reassoc_request(ieee->dev, | 1696 | ieee->handle_reassoc_request(ieee->dev, |
| 1699 | (struct ieee80211_reassoc_request *) | 1697 | (struct ieee80211_reassoc_request *) |
| @@ -1705,8 +1703,8 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
| 1705 | WLAN_FC_GET_STYPE(le16_to_cpu | 1703 | WLAN_FC_GET_STYPE(le16_to_cpu |
| 1706 | (header->frame_ctl))); | 1704 | (header->frame_ctl))); |
| 1707 | 1705 | ||
| 1708 | IEEE80211_WARNING("%s: IEEE80211_ASSOC_REQ received\n", | 1706 | IEEE80211_DEBUG_MGMT("%s: IEEE80211_ASSOC_REQ received\n", |
| 1709 | ieee->dev->name); | 1707 | ieee->dev->name); |
| 1710 | if (ieee->handle_assoc_request != NULL) | 1708 | if (ieee->handle_assoc_request != NULL) |
| 1711 | ieee->handle_assoc_request(ieee->dev); | 1709 | ieee->handle_assoc_request(ieee->dev); |
| 1712 | break; | 1710 | break; |
| @@ -1722,10 +1720,10 @@ void ieee80211_rx_mgt(struct ieee80211_device *ieee, | |||
| 1722 | IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", | 1720 | IEEE80211_DEBUG_MGMT("received UNKNOWN (%d)\n", |
| 1723 | WLAN_FC_GET_STYPE(le16_to_cpu | 1721 | WLAN_FC_GET_STYPE(le16_to_cpu |
| 1724 | (header->frame_ctl))); | 1722 | (header->frame_ctl))); |
| 1725 | IEEE80211_WARNING("%s: Unknown management packet: %d\n", | 1723 | IEEE80211_DEBUG_MGMT("%s: Unknown management packet: %d\n", |
| 1726 | ieee->dev->name, | 1724 | ieee->dev->name, |
| 1727 | WLAN_FC_GET_STYPE(le16_to_cpu | 1725 | WLAN_FC_GET_STYPE(le16_to_cpu |
| 1728 | (header->frame_ctl))); | 1726 | (header->frame_ctl))); |
| 1729 | break; | 1727 | break; |
| 1730 | } | 1728 | } |
| 1731 | } | 1729 | } |
diff --git a/net/ieee80211/ieee80211_tx.c b/net/ieee80211/ieee80211_tx.c index 8b4332f53394..6a5de1b84459 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/net/ieee80211/ieee80211_tx.c | |||
| @@ -220,13 +220,43 @@ static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, | |||
| 220 | return txb; | 220 | return txb; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | static int ieee80211_classify(struct sk_buff *skb) | ||
| 224 | { | ||
| 225 | struct ethhdr *eth; | ||
| 226 | struct iphdr *ip; | ||
| 227 | |||
| 228 | eth = (struct ethhdr *)skb->data; | ||
| 229 | if (eth->h_proto != __constant_htons(ETH_P_IP)) | ||
| 230 | return 0; | ||
| 231 | |||
| 232 | ip = skb->nh.iph; | ||
| 233 | switch (ip->tos & 0xfc) { | ||
| 234 | case 0x20: | ||
| 235 | return 2; | ||
| 236 | case 0x40: | ||
| 237 | return 1; | ||
| 238 | case 0x60: | ||
| 239 | return 3; | ||
| 240 | case 0x80: | ||
| 241 | return 4; | ||
| 242 | case 0xa0: | ||
| 243 | return 5; | ||
| 244 | case 0xc0: | ||
| 245 | return 6; | ||
| 246 | case 0xe0: | ||
| 247 | return 7; | ||
| 248 | default: | ||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 223 | /* Incoming skb is converted to a txb which consists of | 253 | /* Incoming skb is converted to a txb which consists of |
| 224 | * a block of 802.11 fragment packets (stored as skbs) */ | 254 | * a block of 802.11 fragment packets (stored as skbs) */ |
| 225 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | 255 | int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) |
| 226 | { | 256 | { |
| 227 | struct ieee80211_device *ieee = netdev_priv(dev); | 257 | struct ieee80211_device *ieee = netdev_priv(dev); |
| 228 | struct ieee80211_txb *txb = NULL; | 258 | struct ieee80211_txb *txb = NULL; |
| 229 | struct ieee80211_hdr_3addr *frag_hdr; | 259 | struct ieee80211_hdr_3addrqos *frag_hdr; |
| 230 | int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, | 260 | int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size, |
| 231 | rts_required; | 261 | rts_required; |
| 232 | unsigned long flags; | 262 | unsigned long flags; |
| @@ -234,9 +264,10 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 234 | int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; | 264 | int ether_type, encrypt, host_encrypt, host_encrypt_msdu, host_build_iv; |
| 235 | int bytes, fc, hdr_len; | 265 | int bytes, fc, hdr_len; |
| 236 | struct sk_buff *skb_frag; | 266 | struct sk_buff *skb_frag; |
| 237 | struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ | 267 | struct ieee80211_hdr_3addrqos header = {/* Ensure zero initialized */ |
| 238 | .duration_id = 0, | 268 | .duration_id = 0, |
| 239 | .seq_ctl = 0 | 269 | .seq_ctl = 0, |
| 270 | .qos_ctl = 0 | ||
| 240 | }; | 271 | }; |
| 241 | u8 dest[ETH_ALEN], src[ETH_ALEN]; | 272 | u8 dest[ETH_ALEN], src[ETH_ALEN]; |
| 242 | struct ieee80211_crypt_data *crypt; | 273 | struct ieee80211_crypt_data *crypt; |
| @@ -282,12 +313,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 282 | memcpy(dest, skb->data, ETH_ALEN); | 313 | memcpy(dest, skb->data, ETH_ALEN); |
| 283 | memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); | 314 | memcpy(src, skb->data + ETH_ALEN, ETH_ALEN); |
| 284 | 315 | ||
| 285 | /* Advance the SKB to the start of the payload */ | ||
| 286 | skb_pull(skb, sizeof(struct ethhdr)); | ||
| 287 | |||
| 288 | /* Determine total amount of storage required for TXB packets */ | ||
| 289 | bytes = skb->len + SNAP_SIZE + sizeof(u16); | ||
| 290 | |||
| 291 | if (host_encrypt || host_build_iv) | 316 | if (host_encrypt || host_build_iv) |
| 292 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | | 317 | fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | |
| 293 | IEEE80211_FCTL_PROTECTED; | 318 | IEEE80211_FCTL_PROTECTED; |
| @@ -306,9 +331,23 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 306 | memcpy(header.addr2, src, ETH_ALEN); | 331 | memcpy(header.addr2, src, ETH_ALEN); |
| 307 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); | 332 | memcpy(header.addr3, ieee->bssid, ETH_ALEN); |
| 308 | } | 333 | } |
| 309 | header.frame_ctl = cpu_to_le16(fc); | ||
| 310 | hdr_len = IEEE80211_3ADDR_LEN; | 334 | hdr_len = IEEE80211_3ADDR_LEN; |
| 311 | 335 | ||
| 336 | if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) { | ||
| 337 | fc |= IEEE80211_STYPE_QOS_DATA; | ||
| 338 | hdr_len += 2; | ||
| 339 | |||
| 340 | skb->priority = ieee80211_classify(skb); | ||
| 341 | header.qos_ctl |= skb->priority & IEEE80211_QCTL_TID; | ||
| 342 | } | ||
| 343 | header.frame_ctl = cpu_to_le16(fc); | ||
| 344 | |||
| 345 | /* Advance the SKB to the start of the payload */ | ||
| 346 | skb_pull(skb, sizeof(struct ethhdr)); | ||
| 347 | |||
| 348 | /* Determine total amount of storage required for TXB packets */ | ||
| 349 | bytes = skb->len + SNAP_SIZE + sizeof(u16); | ||
| 350 | |||
| 312 | /* Encrypt msdu first on the whole data packet. */ | 351 | /* Encrypt msdu first on the whole data packet. */ |
| 313 | if ((host_encrypt || host_encrypt_msdu) && | 352 | if ((host_encrypt || host_encrypt_msdu) && |
| 314 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { | 353 | crypt && crypt->ops && crypt->ops->encrypt_msdu) { |
| @@ -402,7 +441,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 402 | if (rts_required) { | 441 | if (rts_required) { |
| 403 | skb_frag = txb->fragments[0]; | 442 | skb_frag = txb->fragments[0]; |
| 404 | frag_hdr = | 443 | frag_hdr = |
| 405 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); | 444 | (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); |
| 406 | 445 | ||
| 407 | /* | 446 | /* |
| 408 | * Set header frame_ctl to the RTS. | 447 | * Set header frame_ctl to the RTS. |
| @@ -433,7 +472,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 433 | crypt->ops->extra_mpdu_prefix_len); | 472 | crypt->ops->extra_mpdu_prefix_len); |
| 434 | 473 | ||
| 435 | frag_hdr = | 474 | frag_hdr = |
| 436 | (struct ieee80211_hdr_3addr *)skb_put(skb_frag, hdr_len); | 475 | (struct ieee80211_hdr_3addrqos *)skb_put(skb_frag, hdr_len); |
| 437 | memcpy(frag_hdr, &header, hdr_len); | 476 | memcpy(frag_hdr, &header, hdr_len); |
| 438 | 477 | ||
| 439 | /* If this is not the last fragment, then add the MOREFRAGS | 478 | /* If this is not the last fragment, then add the MOREFRAGS |
| @@ -516,7 +555,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 516 | /* Incoming 802.11 strucure is converted to a TXB | 555 | /* Incoming 802.11 strucure is converted to a TXB |
| 517 | * a block of 802.11 fragment packets (stored as skbs) */ | 556 | * a block of 802.11 fragment packets (stored as skbs) */ |
| 518 | int ieee80211_tx_frame(struct ieee80211_device *ieee, | 557 | int ieee80211_tx_frame(struct ieee80211_device *ieee, |
| 519 | struct ieee80211_hdr *frame, int len) | 558 | struct ieee80211_hdr *frame, int hdr_len, int total_len, |
| 559 | int encrypt_mpdu) | ||
| 520 | { | 560 | { |
| 521 | struct ieee80211_txb *txb = NULL; | 561 | struct ieee80211_txb *txb = NULL; |
| 522 | unsigned long flags; | 562 | unsigned long flags; |
| @@ -526,6 +566,9 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
| 526 | 566 | ||
| 527 | spin_lock_irqsave(&ieee->lock, flags); | 567 | spin_lock_irqsave(&ieee->lock, flags); |
| 528 | 568 | ||
| 569 | if (encrypt_mpdu && !ieee->sec.encrypt) | ||
| 570 | encrypt_mpdu = 0; | ||
| 571 | |||
| 529 | /* If there is no driver handler to take the TXB, dont' bother | 572 | /* If there is no driver handler to take the TXB, dont' bother |
| 530 | * creating it... */ | 573 | * creating it... */ |
| 531 | if (!ieee->hard_start_xmit) { | 574 | if (!ieee->hard_start_xmit) { |
| @@ -533,32 +576,41 @@ int ieee80211_tx_frame(struct ieee80211_device *ieee, | |||
| 533 | goto success; | 576 | goto success; |
| 534 | } | 577 | } |
| 535 | 578 | ||
| 536 | if (unlikely(len < 24)) { | 579 | if (unlikely(total_len < 24)) { |
| 537 | printk(KERN_WARNING "%s: skb too small (%d).\n", | 580 | printk(KERN_WARNING "%s: skb too small (%d).\n", |
| 538 | ieee->dev->name, len); | 581 | ieee->dev->name, total_len); |
| 539 | goto success; | 582 | goto success; |
| 540 | } | 583 | } |
| 541 | 584 | ||
| 585 | if (encrypt_mpdu) | ||
| 586 | frame->frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
| 587 | |||
| 542 | /* When we allocate the TXB we allocate enough space for the reserve | 588 | /* When we allocate the TXB we allocate enough space for the reserve |
| 543 | * and full fragment bytes (bytes_per_frag doesn't include prefix, | 589 | * and full fragment bytes (bytes_per_frag doesn't include prefix, |
| 544 | * postfix, header, FCS, etc.) */ | 590 | * postfix, header, FCS, etc.) */ |
| 545 | txb = ieee80211_alloc_txb(1, len, ieee->tx_headroom, GFP_ATOMIC); | 591 | txb = ieee80211_alloc_txb(1, total_len, ieee->tx_headroom, GFP_ATOMIC); |
| 546 | if (unlikely(!txb)) { | 592 | if (unlikely(!txb)) { |
| 547 | printk(KERN_WARNING "%s: Could not allocate TXB\n", | 593 | printk(KERN_WARNING "%s: Could not allocate TXB\n", |
| 548 | ieee->dev->name); | 594 | ieee->dev->name); |
| 549 | goto failed; | 595 | goto failed; |
| 550 | } | 596 | } |
| 551 | txb->encrypted = 0; | 597 | txb->encrypted = 0; |
| 552 | txb->payload_size = len; | 598 | txb->payload_size = total_len; |
| 553 | 599 | ||
| 554 | skb_frag = txb->fragments[0]; | 600 | skb_frag = txb->fragments[0]; |
| 555 | 601 | ||
| 556 | memcpy(skb_put(skb_frag, len), frame, len); | 602 | memcpy(skb_put(skb_frag, total_len), frame, total_len); |
| 557 | 603 | ||
| 558 | if (ieee->config & | 604 | if (ieee->config & |
| 559 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) | 605 | (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) |
| 560 | skb_put(skb_frag, 4); | 606 | skb_put(skb_frag, 4); |
| 561 | 607 | ||
| 608 | /* To avoid overcomplicating things, we do the corner-case frame | ||
| 609 | * encryption in software. The only real situation where encryption is | ||
| 610 | * needed here is during software-based shared key authentication. */ | ||
| 611 | if (encrypt_mpdu) | ||
| 612 | ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); | ||
| 613 | |||
| 562 | success: | 614 | success: |
| 563 | spin_unlock_irqrestore(&ieee->lock, flags); | 615 | spin_unlock_irqrestore(&ieee->lock, flags); |
| 564 | 616 | ||
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c index b885fd189403..a78c4f845f66 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/net/ieee80211/ieee80211_wx.c | |||
| @@ -50,7 +50,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
| 50 | char *p; | 50 | char *p; |
| 51 | struct iw_event iwe; | 51 | struct iw_event iwe; |
| 52 | int i, j; | 52 | int i, j; |
| 53 | u8 max_rate, rate; | 53 | char *current_val; /* For rates */ |
| 54 | u8 rate; | ||
| 54 | 55 | ||
| 55 | /* First entry *MUST* be the AP MAC address */ | 56 | /* First entry *MUST* be the AP MAC address */ |
| 56 | iwe.cmd = SIOCGIWAP; | 57 | iwe.cmd = SIOCGIWAP; |
| @@ -107,9 +108,13 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
| 107 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); | 108 | start = iwe_stream_add_point(start, stop, &iwe, network->ssid); |
| 108 | 109 | ||
| 109 | /* Add basic and extended rates */ | 110 | /* Add basic and extended rates */ |
| 110 | max_rate = 0; | 111 | /* Rate : stuffing multiple values in a single event require a bit |
| 111 | p = custom; | 112 | * more of magic - Jean II */ |
| 112 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); | 113 | current_val = start + IW_EV_LCP_LEN; |
| 114 | iwe.cmd = SIOCGIWRATE; | ||
| 115 | /* Those two flags are ignored... */ | ||
| 116 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | ||
| 117 | |||
| 113 | for (i = 0, j = 0; i < network->rates_len;) { | 118 | for (i = 0, j = 0; i < network->rates_len;) { |
| 114 | if (j < network->rates_ex_len && | 119 | if (j < network->rates_ex_len && |
| 115 | ((network->rates_ex[j] & 0x7F) < | 120 | ((network->rates_ex[j] & 0x7F) < |
| @@ -117,28 +122,21 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, | |||
| 117 | rate = network->rates_ex[j++] & 0x7F; | 122 | rate = network->rates_ex[j++] & 0x7F; |
| 118 | else | 123 | else |
| 119 | rate = network->rates[i++] & 0x7F; | 124 | rate = network->rates[i++] & 0x7F; |
| 120 | if (rate > max_rate) | 125 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
| 121 | max_rate = rate; | 126 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
| 122 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 127 | /* Add new value to event */ |
| 123 | "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | 128 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); |
| 124 | } | 129 | } |
| 125 | for (; j < network->rates_ex_len; j++) { | 130 | for (; j < network->rates_ex_len; j++) { |
| 126 | rate = network->rates_ex[j] & 0x7F; | 131 | rate = network->rates_ex[j] & 0x7F; |
| 127 | p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), | 132 | /* Bit rate given in 500 kb/s units (+ 0x80) */ |
| 128 | "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); | 133 | iwe.u.bitrate.value = ((rate & 0x7f) * 500000); |
| 129 | if (rate > max_rate) | 134 | /* Add new value to event */ |
| 130 | max_rate = rate; | 135 | current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); |
| 131 | } | 136 | } |
| 132 | 137 | /* Check if we added any rate */ | |
| 133 | iwe.cmd = SIOCGIWRATE; | 138 | if((current_val - start) > IW_EV_LCP_LEN) |
| 134 | iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; | 139 | start = current_val; |
| 135 | iwe.u.bitrate.value = max_rate * 500000; | ||
| 136 | start = iwe_stream_add_event(start, stop, &iwe, IW_EV_PARAM_LEN); | ||
| 137 | |||
| 138 | iwe.cmd = IWEVCUSTOM; | ||
| 139 | iwe.u.data.length = p - custom; | ||
| 140 | if (iwe.u.data.length) | ||
| 141 | start = iwe_stream_add_point(start, stop, &iwe, custom); | ||
| 142 | 140 | ||
| 143 | /* Add quality statistics */ | 141 | /* Add quality statistics */ |
| 144 | iwe.cmd = IWEVQUAL; | 142 | iwe.cmd = IWEVQUAL; |
| @@ -505,7 +503,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, | |||
| 505 | len = sec->key_sizes[key]; | 503 | len = sec->key_sizes[key]; |
| 506 | memcpy(keybuf, sec->keys[key], len); | 504 | memcpy(keybuf, sec->keys[key], len); |
| 507 | 505 | ||
| 508 | erq->length = (len >= 0 ? len : 0); | 506 | erq->length = len; |
| 509 | erq->flags |= IW_ENCODE_ENABLED; | 507 | erq->flags |= IW_ENCODE_ENABLED; |
| 510 | 508 | ||
| 511 | if (ieee->open_wep) | 509 | if (ieee->open_wep) |
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig index f2a27cc6ecb1..2811651cb134 100644 --- a/net/ieee80211/softmac/Kconfig +++ b/net/ieee80211/softmac/Kconfig | |||
| @@ -2,6 +2,7 @@ config IEEE80211_SOFTMAC | |||
| 2 | tristate "Software MAC add-on to the IEEE 802.11 networking stack" | 2 | tristate "Software MAC add-on to the IEEE 802.11 networking stack" |
| 3 | depends on IEEE80211 && EXPERIMENTAL | 3 | depends on IEEE80211 && EXPERIMENTAL |
| 4 | select WIRELESS_EXT | 4 | select WIRELESS_EXT |
| 5 | select IEEE80211_CRYPT_WEP | ||
| 5 | ---help--- | 6 | ---help--- |
| 6 | This option enables the hardware independent software MAC addon | 7 | This option enables the hardware independent software MAC addon |
| 7 | for the IEEE 802.11 networking stack. | 8 | for the IEEE 802.11 networking stack. |
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 57ea9f6f465c..5e9a90651d04 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c | |||
| @@ -82,51 +82,52 @@ ieee80211softmac_assoc_timeout(void *d) | |||
| 82 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL); | 82 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | /* Sends out a disassociation request to the desired AP */ | 85 | void |
| 86 | static void | 86 | ieee80211softmac_disassoc(struct ieee80211softmac_device *mac) |
| 87 | ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) | ||
| 88 | { | 87 | { |
| 89 | unsigned long flags; | 88 | unsigned long flags; |
| 89 | |||
| 90 | spin_lock_irqsave(&mac->lock, flags); | ||
| 91 | if (mac->associnfo.associating) | ||
| 92 | cancel_delayed_work(&mac->associnfo.timeout); | ||
| 93 | |||
| 94 | netif_carrier_off(mac->dev); | ||
| 95 | |||
| 96 | mac->associated = 0; | ||
| 97 | mac->associnfo.bssvalid = 0; | ||
| 98 | mac->associnfo.associating = 0; | ||
| 99 | ieee80211softmac_init_txrates(mac); | ||
| 100 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
| 101 | spin_unlock_irqrestore(&mac->lock, flags); | ||
| 102 | } | ||
| 103 | |||
| 104 | /* Sends out a disassociation request to the desired AP */ | ||
| 105 | void | ||
| 106 | ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason) | ||
| 107 | { | ||
| 90 | struct ieee80211softmac_network *found; | 108 | struct ieee80211softmac_network *found; |
| 91 | 109 | ||
| 92 | if (mac->associnfo.bssvalid && mac->associated) { | 110 | if (mac->associnfo.bssvalid && mac->associated) { |
| 93 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | 111 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); |
| 94 | if (found) | 112 | if (found) |
| 95 | ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); | 113 | ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); |
| 96 | } else if (mac->associnfo.associating) { | ||
| 97 | cancel_delayed_work(&mac->associnfo.timeout); | ||
| 98 | } | 114 | } |
| 99 | 115 | ||
| 100 | /* Change our state */ | 116 | ieee80211softmac_disassoc(mac); |
| 101 | spin_lock_irqsave(&mac->lock, flags); | ||
| 102 | /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ | ||
| 103 | mac->associated = 0; | ||
| 104 | mac->associnfo.associating = 0; | ||
| 105 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
| 106 | spin_unlock_irqrestore(&mac->lock, flags); | ||
| 107 | } | 117 | } |
| 108 | 118 | ||
| 109 | static inline int | 119 | static inline int |
| 110 | we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) | 120 | we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) |
| 111 | { | 121 | { |
| 112 | int idx, search, found; | 122 | int idx; |
| 113 | u8 rate, search_rate; | 123 | u8 rate; |
| 114 | 124 | ||
| 115 | for (idx = 0; idx < (from_len); idx++) { | 125 | for (idx = 0; idx < (from_len); idx++) { |
| 116 | rate = (from)[idx]; | 126 | rate = (from)[idx]; |
| 117 | if (!(rate & IEEE80211_BASIC_RATE_MASK)) | 127 | if (!(rate & IEEE80211_BASIC_RATE_MASK)) |
| 118 | continue; | 128 | continue; |
| 119 | found = 0; | ||
| 120 | rate &= ~IEEE80211_BASIC_RATE_MASK; | 129 | rate &= ~IEEE80211_BASIC_RATE_MASK; |
| 121 | for (search = 0; search < mac->ratesinfo.count; search++) { | 130 | if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) |
| 122 | search_rate = mac->ratesinfo.rates[search]; | ||
| 123 | search_rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
| 124 | if (rate == search_rate) { | ||
| 125 | found = 1; | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | if (!found) | ||
| 130 | return 0; | 131 | return 0; |
| 131 | } | 132 | } |
| 132 | return 1; | 133 | return 1; |
| @@ -163,12 +164,28 @@ network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_ne | |||
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | static void | 166 | static void |
| 166 | ieee80211softmac_assoc_notify(struct net_device *dev, void *context) | 167 | ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context) |
| 167 | { | 168 | { |
| 168 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | 169 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); |
| 169 | ieee80211softmac_assoc_work((void*)mac); | 170 | ieee80211softmac_assoc_work((void*)mac); |
| 170 | } | 171 | } |
| 171 | 172 | ||
| 173 | static void | ||
| 174 | ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context) | ||
| 175 | { | ||
| 176 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
| 177 | |||
| 178 | switch (event_type) { | ||
| 179 | case IEEE80211SOFTMAC_EVENT_AUTHENTICATED: | ||
| 180 | ieee80211softmac_assoc_work((void*)mac); | ||
| 181 | break; | ||
| 182 | case IEEE80211SOFTMAC_EVENT_AUTH_FAILED: | ||
| 183 | case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT: | ||
| 184 | ieee80211softmac_disassoc(mac); | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 172 | /* This function is called to handle userspace requests (asynchronously) */ | 189 | /* This function is called to handle userspace requests (asynchronously) */ |
| 173 | void | 190 | void |
| 174 | ieee80211softmac_assoc_work(void *d) | 191 | ieee80211softmac_assoc_work(void *d) |
| @@ -176,14 +193,18 @@ ieee80211softmac_assoc_work(void *d) | |||
| 176 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; | 193 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; |
| 177 | struct ieee80211softmac_network *found = NULL; | 194 | struct ieee80211softmac_network *found = NULL; |
| 178 | struct ieee80211_network *net = NULL, *best = NULL; | 195 | struct ieee80211_network *net = NULL, *best = NULL; |
| 196 | int bssvalid; | ||
| 179 | unsigned long flags; | 197 | unsigned long flags; |
| 180 | 198 | ||
| 199 | /* ieee80211_disassoc might clear this */ | ||
| 200 | bssvalid = mac->associnfo.bssvalid; | ||
| 201 | |||
| 181 | /* meh */ | 202 | /* meh */ |
| 182 | if (mac->associated) | 203 | if (mac->associated) |
| 183 | ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); | 204 | ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); |
| 184 | 205 | ||
| 185 | /* try to find the requested network in our list, if we found one already */ | 206 | /* try to find the requested network in our list, if we found one already */ |
| 186 | if (mac->associnfo.bssvalid || mac->associnfo.bssfixed) | 207 | if (bssvalid || mac->associnfo.bssfixed) |
| 187 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | 208 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); |
| 188 | 209 | ||
| 189 | /* Search the ieee80211 networks for this network if we didn't find it by bssid, | 210 | /* Search the ieee80211 networks for this network if we didn't find it by bssid, |
| @@ -244,7 +265,7 @@ ieee80211softmac_assoc_work(void *d) | |||
| 244 | * Maybe we can hope to have more memory after scanning finishes ;) | 265 | * Maybe we can hope to have more memory after scanning finishes ;) |
| 245 | */ | 266 | */ |
| 246 | dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); | 267 | dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); |
| 247 | ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL); | 268 | ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL); |
| 248 | if (ieee80211softmac_start_scan(mac)) | 269 | if (ieee80211softmac_start_scan(mac)) |
| 249 | dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); | 270 | dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); |
| 250 | return; | 271 | return; |
| @@ -279,7 +300,7 @@ ieee80211softmac_assoc_work(void *d) | |||
| 279 | * otherwise adding the notification would be racy. */ | 300 | * otherwise adding the notification would be racy. */ |
| 280 | if (!ieee80211softmac_auth_req(mac, found)) { | 301 | if (!ieee80211softmac_auth_req(mac, found)) { |
| 281 | dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); | 302 | dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); |
| 282 | ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL); | 303 | ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); |
| 283 | } else { | 304 | } else { |
| 284 | printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); | 305 | printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); |
| 285 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); | 306 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); |
| @@ -297,6 +318,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac, | |||
| 297 | struct ieee80211softmac_network *net) | 318 | struct ieee80211softmac_network *net) |
| 298 | { | 319 | { |
| 299 | mac->associnfo.associating = 0; | 320 | mac->associnfo.associating = 0; |
| 321 | mac->associnfo.supported_rates = net->supported_rates; | ||
| 322 | ieee80211softmac_recalc_txrates(mac); | ||
| 323 | |||
| 300 | mac->associated = 1; | 324 | mac->associated = 1; |
| 301 | if (mac->set_bssid_filter) | 325 | if (mac->set_bssid_filter) |
| 302 | mac->set_bssid_filter(mac->dev, net->bssid); | 326 | mac->set_bssid_filter(mac->dev, net->bssid); |
| @@ -380,7 +404,6 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
| 380 | struct ieee80211_disassoc *disassoc) | 404 | struct ieee80211_disassoc *disassoc) |
| 381 | { | 405 | { |
| 382 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | 406 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); |
| 383 | unsigned long flags; | ||
| 384 | 407 | ||
| 385 | if (unlikely(!mac->running)) | 408 | if (unlikely(!mac->running)) |
| 386 | return -ENODEV; | 409 | return -ENODEV; |
| @@ -392,14 +415,11 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
| 392 | return 0; | 415 | return 0; |
| 393 | 416 | ||
| 394 | dprintk(KERN_INFO PFX "got disassoc frame\n"); | 417 | dprintk(KERN_INFO PFX "got disassoc frame\n"); |
| 395 | netif_carrier_off(dev); | 418 | ieee80211softmac_disassoc(mac); |
| 396 | spin_lock_irqsave(&mac->lock, flags); | 419 | |
| 397 | mac->associnfo.bssvalid = 0; | 420 | /* try to reassociate */ |
| 398 | mac->associated = 0; | ||
| 399 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
| 400 | schedule_work(&mac->associnfo.work); | 421 | schedule_work(&mac->associnfo.work); |
| 401 | spin_unlock_irqrestore(&mac->lock, flags); | 422 | |
| 402 | |||
| 403 | return 0; | 423 | return 0; |
| 404 | } | 424 | } |
| 405 | 425 | ||
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c index 06e332624665..90b8484e509b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ b/net/ieee80211/softmac/ieee80211softmac_auth.c | |||
| @@ -107,6 +107,7 @@ ieee80211softmac_auth_queue(void *data) | |||
| 107 | printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); | 107 | printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); |
| 108 | /* Remove this item from the queue */ | 108 | /* Remove this item from the queue */ |
| 109 | spin_lock_irqsave(&mac->lock, flags); | 109 | spin_lock_irqsave(&mac->lock, flags); |
| 110 | net->authenticating = 0; | ||
| 110 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); | 111 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); |
| 111 | cancel_delayed_work(&auth->work); /* just to make sure... */ | 112 | cancel_delayed_work(&auth->work); /* just to make sure... */ |
| 112 | list_del(&auth->list); | 113 | list_del(&auth->list); |
| @@ -212,13 +213,13 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) | |||
| 212 | aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; | 213 | aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; |
| 213 | spin_unlock_irqrestore(&mac->lock, flags); | 214 | spin_unlock_irqrestore(&mac->lock, flags); |
| 214 | 215 | ||
| 215 | /* Switch to correct channel for this network */ | 216 | /* Send our response */ |
| 216 | mac->set_channel(mac->dev, net->channel); | ||
| 217 | |||
| 218 | /* Send our response (How to encrypt?) */ | ||
| 219 | ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); | 217 | ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); |
| 220 | break; | 218 | return 0; |
| 221 | case IEEE80211SOFTMAC_AUTH_SHARED_PASS: | 219 | case IEEE80211SOFTMAC_AUTH_SHARED_PASS: |
| 220 | kfree(net->challenge); | ||
| 221 | net->challenge = NULL; | ||
| 222 | net->challenge_len = 0; | ||
| 222 | /* Check the status code of the response */ | 223 | /* Check the status code of the response */ |
| 223 | switch(auth->status) { | 224 | switch(auth->status) { |
| 224 | case WLAN_STATUS_SUCCESS: | 225 | case WLAN_STATUS_SUCCESS: |
| @@ -229,6 +230,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) | |||
| 229 | spin_unlock_irqrestore(&mac->lock, flags); | 230 | spin_unlock_irqrestore(&mac->lock, flags); |
| 230 | printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", | 231 | printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", |
| 231 | MAC_ARG(net->bssid)); | 232 | MAC_ARG(net->bssid)); |
| 233 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); | ||
| 232 | break; | 234 | break; |
| 233 | default: | 235 | default: |
| 234 | printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", | 236 | printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", |
| @@ -279,6 +281,9 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac, | |||
| 279 | struct list_head *list_ptr; | 281 | struct list_head *list_ptr; |
| 280 | unsigned long flags; | 282 | unsigned long flags; |
| 281 | 283 | ||
| 284 | /* deauthentication implies disassociation */ | ||
| 285 | ieee80211softmac_disassoc(mac); | ||
| 286 | |||
| 282 | /* Lock and reset status flags */ | 287 | /* Lock and reset status flags */ |
| 283 | spin_lock_irqsave(&mac->lock, flags); | 288 | spin_lock_irqsave(&mac->lock, flags); |
| 284 | net->authenticating = 0; | 289 | net->authenticating = 0; |
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c index 8cc8f3f0f8e7..f34fa2ef666b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ b/net/ieee80211/softmac/ieee80211softmac_event.c | |||
| @@ -38,7 +38,8 @@ | |||
| 38 | * The event context is private and can only be used from | 38 | * The event context is private and can only be used from |
| 39 | * within this module. Its meaning varies with the event | 39 | * within this module. Its meaning varies with the event |
| 40 | * type: | 40 | * type: |
| 41 | * SCAN_FINISHED: no special meaning | 41 | * SCAN_FINISHED, |
| 42 | * DISASSOCIATED: NULL | ||
| 42 | * ASSOCIATED, | 43 | * ASSOCIATED, |
| 43 | * ASSOCIATE_FAILED, | 44 | * ASSOCIATE_FAILED, |
| 44 | * ASSOCIATE_TIMEOUT, | 45 | * ASSOCIATE_TIMEOUT, |
| @@ -59,15 +60,15 @@ | |||
| 59 | */ | 60 | */ |
| 60 | 61 | ||
| 61 | static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { | 62 | static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { |
| 62 | "scan finished", | 63 | NULL, /* scan finished */ |
| 63 | "associated", | 64 | NULL, /* associated */ |
| 64 | "associating failed", | 65 | "associating failed", |
| 65 | "associating timed out", | 66 | "associating timed out", |
| 66 | "authenticated", | 67 | "authenticated", |
| 67 | "authenticating failed", | 68 | "authenticating failed", |
| 68 | "authenticating timed out", | 69 | "authenticating timed out", |
| 69 | "associating failed because no suitable network was found", | 70 | "associating failed because no suitable network was found", |
| 70 | "disassociated", | 71 | NULL, /* disassociated */ |
| 71 | }; | 72 | }; |
| 72 | 73 | ||
| 73 | 74 | ||
| @@ -77,7 +78,7 @@ ieee80211softmac_notify_callback(void *d) | |||
| 77 | struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; | 78 | struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; |
| 78 | kfree(d); | 79 | kfree(d); |
| 79 | 80 | ||
| 80 | event.fun(event.mac->dev, event.context); | 81 | event.fun(event.mac->dev, event.event_type, event.context); |
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | int | 84 | int |
| @@ -136,30 +137,24 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve | |||
| 136 | int we_event; | 137 | int we_event; |
| 137 | char *msg = NULL; | 138 | char *msg = NULL; |
| 138 | 139 | ||
| 140 | memset(&wrqu, '\0', sizeof (union iwreq_data)); | ||
| 141 | |||
| 139 | switch(event) { | 142 | switch(event) { |
| 140 | case IEEE80211SOFTMAC_EVENT_ASSOCIATED: | 143 | case IEEE80211SOFTMAC_EVENT_ASSOCIATED: |
| 141 | network = (struct ieee80211softmac_network *)event_ctx; | 144 | network = (struct ieee80211softmac_network *)event_ctx; |
| 142 | wrqu.data.length = 0; | ||
| 143 | wrqu.data.flags = 0; | ||
| 144 | memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); | 145 | memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); |
| 145 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 146 | /* fall through */ |
| 146 | we_event = SIOCGIWAP; | ||
| 147 | break; | ||
| 148 | case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: | 147 | case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: |
| 149 | wrqu.data.length = 0; | ||
| 150 | wrqu.data.flags = 0; | ||
| 151 | memset(&wrqu, '\0', sizeof (union iwreq_data)); | ||
| 152 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 148 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
| 153 | we_event = SIOCGIWAP; | 149 | we_event = SIOCGIWAP; |
| 154 | break; | 150 | break; |
| 155 | case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: | 151 | case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: |
| 156 | wrqu.data.length = 0; | ||
| 157 | wrqu.data.flags = 0; | ||
| 158 | memset(&wrqu, '\0', sizeof (union iwreq_data)); | ||
| 159 | we_event = SIOCGIWSCAN; | 152 | we_event = SIOCGIWSCAN; |
| 160 | break; | 153 | break; |
| 161 | default: | 154 | default: |
| 162 | msg = event_descriptions[event]; | 155 | msg = event_descriptions[event]; |
| 156 | if (!msg) | ||
| 157 | msg = "SOFTMAC EVENT BUG"; | ||
| 163 | wrqu.data.length = strlen(msg); | 158 | wrqu.data.length = strlen(msg); |
| 164 | we_event = IWEVCUSTOM; | 159 | we_event = IWEVCUSTOM; |
| 165 | break; | 160 | break; |
| @@ -172,6 +167,9 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve | |||
| 172 | if ((eventptr->event_type == event || eventptr->event_type == -1) | 167 | if ((eventptr->event_type == event || eventptr->event_type == -1) |
| 173 | && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { | 168 | && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { |
| 174 | list_del(&eventptr->list); | 169 | list_del(&eventptr->list); |
| 170 | /* User may have subscribed to ANY event, so | ||
| 171 | * we tell them which event triggered it. */ | ||
| 172 | eventptr->event_type = event; | ||
| 175 | schedule_work(&eventptr->work); | 173 | schedule_work(&eventptr->work); |
| 176 | } | 174 | } |
| 177 | } | 175 | } |
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c index cc6cd56c85b1..09541611e48c 100644 --- a/net/ieee80211/softmac/ieee80211softmac_io.c +++ b/net/ieee80211/softmac/ieee80211softmac_io.c | |||
| @@ -149,6 +149,56 @@ ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac, | |||
| 149 | * shouldn't the sequence number be in ieee80211? */ | 149 | * shouldn't the sequence number be in ieee80211? */ |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | static u16 | ||
| 153 | ieee80211softmac_capabilities(struct ieee80211softmac_device *mac, | ||
| 154 | struct ieee80211softmac_network *net) | ||
| 155 | { | ||
| 156 | u16 capability = 0; | ||
| 157 | |||
| 158 | /* ESS and IBSS bits are set according to the current mode */ | ||
| 159 | switch (mac->ieee->iw_mode) { | ||
| 160 | case IW_MODE_INFRA: | ||
| 161 | capability = cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
| 162 | break; | ||
| 163 | case IW_MODE_ADHOC: | ||
| 164 | capability = cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
| 165 | break; | ||
| 166 | case IW_MODE_AUTO: | ||
| 167 | capability = net->capabilities & | ||
| 168 | (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS); | ||
| 169 | break; | ||
| 170 | default: | ||
| 171 | /* bleh. we don't ever go to these modes */ | ||
| 172 | printk(KERN_ERR PFX "invalid iw_mode!\n"); | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* CF Pollable / CF Poll Request */ | ||
| 177 | /* Needs to be implemented, for now, the 0's == not supported */ | ||
| 178 | |||
| 179 | /* Privacy Bit */ | ||
| 180 | capability |= mac->ieee->sec.level ? | ||
| 181 | cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; | ||
| 182 | |||
| 183 | /* Short Preamble */ | ||
| 184 | /* Always supported: we probably won't ever be powering devices which | ||
| 185 | * dont support this... */ | ||
| 186 | capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
| 187 | |||
| 188 | /* PBCC */ | ||
| 189 | /* Not widely used */ | ||
| 190 | |||
| 191 | /* Channel Agility */ | ||
| 192 | /* Not widely used */ | ||
| 193 | |||
| 194 | /* Short Slot */ | ||
| 195 | /* Will be implemented later */ | ||
| 196 | |||
| 197 | /* DSSS-OFDM */ | ||
| 198 | /* Not widely used */ | ||
| 199 | |||
| 200 | return capability; | ||
| 201 | } | ||
| 152 | 202 | ||
| 153 | /***************************************************************************** | 203 | /***************************************************************************** |
| 154 | * Create Management packets | 204 | * Create Management packets |
| @@ -179,27 +229,6 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt, | |||
| 179 | return 0; | 229 | return 0; |
| 180 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); | 230 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); |
| 181 | 231 | ||
| 182 | /* Fill in capability Info */ | ||
| 183 | switch (mac->ieee->iw_mode) { | ||
| 184 | case IW_MODE_INFRA: | ||
| 185 | (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_ESS); | ||
| 186 | break; | ||
| 187 | case IW_MODE_ADHOC: | ||
| 188 | (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
| 189 | break; | ||
| 190 | case IW_MODE_AUTO: | ||
| 191 | (*pkt)->capability = net->capabilities & (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS); | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | /* bleh. we don't ever go to these modes */ | ||
| 195 | printk(KERN_ERR PFX "invalid iw_mode!\n"); | ||
| 196 | break; | ||
| 197 | } | ||
| 198 | /* Need to add this | ||
| 199 | (*pkt)->capability |= mac->ieee->short_slot ? | ||
| 200 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; | ||
| 201 | */ | ||
| 202 | (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; | ||
| 203 | /* Fill in Listen Interval (?) */ | 232 | /* Fill in Listen Interval (?) */ |
| 204 | (*pkt)->listen_interval = cpu_to_le16(10); | 233 | (*pkt)->listen_interval = cpu_to_le16(10); |
| 205 | 234 | ||
| @@ -239,17 +268,9 @@ ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt, | |||
| 239 | return 0; | 268 | return 0; |
| 240 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid); | 269 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid); |
| 241 | 270 | ||
| 242 | /* Fill in capability Info */ | 271 | /* Fill in the capabilities */ |
| 243 | (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ? | 272 | (*pkt)->capability = ieee80211softmac_capabilities(mac, net); |
| 244 | cpu_to_le16(WLAN_CAPABILITY_ESS) : | 273 | |
| 245 | cpu_to_le16(WLAN_CAPABILITY_IBSS); | ||
| 246 | /* | ||
| 247 | (*pkt)->capability |= mac->ieee->short_slot ? | ||
| 248 | cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0; | ||
| 249 | */ | ||
| 250 | (*pkt)->capability |= mac->ieee->sec.level ? | ||
| 251 | cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; | ||
| 252 | |||
| 253 | /* Fill in Listen Interval (?) */ | 274 | /* Fill in Listen Interval (?) */ |
| 254 | (*pkt)->listen_interval = cpu_to_le16(10); | 275 | (*pkt)->listen_interval = cpu_to_le16(10); |
| 255 | /* Fill in the current AP MAC */ | 276 | /* Fill in the current AP MAC */ |
| @@ -268,26 +289,27 @@ ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt, | |||
| 268 | static u32 | 289 | static u32 |
| 269 | ieee80211softmac_auth(struct ieee80211_auth **pkt, | 290 | ieee80211softmac_auth(struct ieee80211_auth **pkt, |
| 270 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, | 291 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, |
| 271 | u16 transaction, u16 status) | 292 | u16 transaction, u16 status, int *encrypt_mpdu) |
| 272 | { | 293 | { |
| 273 | u8 *data; | 294 | u8 *data; |
| 295 | int auth_mode = mac->ieee->sec.auth_mode; | ||
| 296 | int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY | ||
| 297 | && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE); | ||
| 298 | |||
| 274 | /* Allocate Packet */ | 299 | /* Allocate Packet */ |
| 275 | (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( | 300 | (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( |
| 276 | 2 + /* Auth Algorithm */ | 301 | 2 + /* Auth Algorithm */ |
| 277 | 2 + /* Auth Transaction Seq */ | 302 | 2 + /* Auth Transaction Seq */ |
| 278 | 2 + /* Status Code */ | 303 | 2 + /* Status Code */ |
| 279 | /* Challenge Text IE */ | 304 | /* Challenge Text IE */ |
| 280 | mac->ieee->open_wep ? 0 : | 305 | is_shared_response ? 0 : 1 + 1 + net->challenge_len |
| 281 | 1 + 1 + WLAN_AUTH_CHALLENGE_LEN | 306 | ); |
| 282 | ); | ||
| 283 | if (unlikely((*pkt) == NULL)) | 307 | if (unlikely((*pkt) == NULL)) |
| 284 | return 0; | 308 | return 0; |
| 285 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); | 309 | ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); |
| 286 | 310 | ||
| 287 | /* Algorithm */ | 311 | /* Algorithm */ |
| 288 | (*pkt)->algorithm = mac->ieee->open_wep ? | 312 | (*pkt)->algorithm = cpu_to_le16(auth_mode); |
| 289 | cpu_to_le16(WLAN_AUTH_OPEN) : | ||
| 290 | cpu_to_le16(WLAN_AUTH_SHARED_KEY); | ||
| 291 | /* Transaction */ | 313 | /* Transaction */ |
| 292 | (*pkt)->transaction = cpu_to_le16(transaction); | 314 | (*pkt)->transaction = cpu_to_le16(transaction); |
| 293 | /* Status */ | 315 | /* Status */ |
| @@ -295,18 +317,20 @@ ieee80211softmac_auth(struct ieee80211_auth **pkt, | |||
| 295 | 317 | ||
| 296 | data = (u8 *)(*pkt)->info_element; | 318 | data = (u8 *)(*pkt)->info_element; |
| 297 | /* Challenge Text */ | 319 | /* Challenge Text */ |
| 298 | if(!mac->ieee->open_wep){ | 320 | if (is_shared_response) { |
| 299 | *data = MFIE_TYPE_CHALLENGE; | 321 | *data = MFIE_TYPE_CHALLENGE; |
| 300 | data++; | 322 | data++; |
| 301 | 323 | ||
| 302 | /* Copy the challenge in */ | 324 | /* Copy the challenge in */ |
| 303 | // *data = challenge length | 325 | *data = net->challenge_len; |
| 304 | // data += sizeof(u16); | 326 | data++; |
| 305 | // memcpy(data, challenge, challenge length); | 327 | memcpy(data, net->challenge, net->challenge_len); |
| 306 | // data += challenge length; | 328 | data += net->challenge_len; |
| 307 | 329 | ||
| 308 | /* Add the full size to the packet length */ | 330 | /* Make sure this frame gets encrypted with the shared key */ |
| 309 | } | 331 | *encrypt_mpdu = 1; |
| 332 | } else | ||
| 333 | *encrypt_mpdu = 0; | ||
| 310 | 334 | ||
| 311 | /* Return the packet size */ | 335 | /* Return the packet size */ |
| 312 | return (data - (u8 *)(*pkt)); | 336 | return (data - (u8 *)(*pkt)); |
| @@ -396,6 +420,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, | |||
| 396 | { | 420 | { |
| 397 | void *pkt = NULL; | 421 | void *pkt = NULL; |
| 398 | u32 pkt_size = 0; | 422 | u32 pkt_size = 0; |
| 423 | int encrypt_mpdu = 0; | ||
| 399 | 424 | ||
| 400 | switch(type) { | 425 | switch(type) { |
| 401 | case IEEE80211_STYPE_ASSOC_REQ: | 426 | case IEEE80211_STYPE_ASSOC_REQ: |
| @@ -405,7 +430,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, | |||
| 405 | pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); | 430 | pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); |
| 406 | break; | 431 | break; |
| 407 | case IEEE80211_STYPE_AUTH: | 432 | case IEEE80211_STYPE_AUTH: |
| 408 | pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16)); | 433 | pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu); |
| 409 | break; | 434 | break; |
| 410 | case IEEE80211_STYPE_DISASSOC: | 435 | case IEEE80211_STYPE_DISASSOC: |
| 411 | case IEEE80211_STYPE_DEAUTH: | 436 | case IEEE80211_STYPE_DEAUTH: |
| @@ -434,52 +459,8 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, | |||
| 434 | * or get rid of it alltogether? | 459 | * or get rid of it alltogether? |
| 435 | * Does this work for you now? | 460 | * Does this work for you now? |
| 436 | */ | 461 | */ |
| 437 | ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size); | 462 | ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, |
| 438 | 463 | IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu); | |
| 439 | kfree(pkt); | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | |||
| 444 | /* Create an rts/cts frame */ | ||
| 445 | static u32 | ||
| 446 | ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt, | ||
| 447 | struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, | ||
| 448 | u32 type) | ||
| 449 | { | ||
| 450 | /* Allocate Packet */ | ||
| 451 | (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC); | ||
| 452 | memset(*pkt, 0, IEEE80211_2ADDR_LEN); | ||
| 453 | if((*pkt) == NULL) | ||
| 454 | return 0; | ||
| 455 | ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid); | ||
| 456 | return IEEE80211_2ADDR_LEN; | ||
| 457 | } | ||
| 458 | |||
| 459 | |||
| 460 | /* Sends a control packet */ | ||
| 461 | static int | ||
| 462 | ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac, | ||
| 463 | struct ieee80211softmac_network *net, u32 type, u32 arg) | ||
| 464 | { | ||
| 465 | void *pkt = NULL; | ||
| 466 | u32 pkt_size = 0; | ||
| 467 | |||
| 468 | switch(type) { | ||
| 469 | case IEEE80211_STYPE_RTS: | ||
| 470 | case IEEE80211_STYPE_CTS: | ||
| 471 | pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type); | ||
| 472 | break; | ||
| 473 | default: | ||
| 474 | printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type); | ||
| 475 | return -EINVAL; | ||
| 476 | } | ||
| 477 | |||
| 478 | if(pkt_size == 0) | ||
| 479 | return -ENOMEM; | ||
| 480 | |||
| 481 | /* Send the packet to the ieee80211 layer for tx */ | ||
| 482 | ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size); | ||
| 483 | 464 | ||
| 484 | kfree(pkt); | 465 | kfree(pkt); |
| 485 | return 0; | 466 | return 0; |
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c index 6252be2c0db9..4b2e57d12418 100644 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ b/net/ieee80211/softmac/ieee80211softmac_module.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include "ieee80211softmac_priv.h" | 27 | #include "ieee80211softmac_priv.h" |
| 28 | #include <linux/sort.h> | 28 | #include <linux/sort.h> |
| 29 | #include <linux/etherdevice.h> | ||
| 29 | 30 | ||
| 30 | struct net_device *alloc_ieee80211softmac(int sizeof_priv) | 31 | struct net_device *alloc_ieee80211softmac(int sizeof_priv) |
| 31 | { | 32 | { |
| @@ -61,14 +62,6 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv) | |||
| 61 | softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; | 62 | softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; |
| 62 | softmac->stop_scan = ieee80211softmac_stop_scan_implementation; | 63 | softmac->stop_scan = ieee80211softmac_stop_scan_implementation; |
| 63 | 64 | ||
| 64 | //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...) | ||
| 65 | // It has to be set to the highest rate all stations in the current network can handle. | ||
| 66 | softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB; | ||
| 67 | softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB; | ||
| 68 | /* This is reassigned in ieee80211softmac_start to sane values. */ | ||
| 69 | softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB; | ||
| 70 | softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB; | ||
| 71 | |||
| 72 | /* to start with, we can't send anything ... */ | 65 | /* to start with, we can't send anything ... */ |
| 73 | netif_carrier_off(dev); | 66 | netif_carrier_off(dev); |
| 74 | 67 | ||
| @@ -170,15 +163,82 @@ static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *m | |||
| 170 | } | 163 | } |
| 171 | } | 164 | } |
| 172 | 165 | ||
| 173 | void ieee80211softmac_start(struct net_device *dev) | 166 | int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate) |
| 167 | { | ||
| 168 | int search; | ||
| 169 | u8 search_rate; | ||
| 170 | |||
| 171 | for (search = 0; search < ri->count; search++) { | ||
| 172 | search_rate = ri->rates[search]; | ||
| 173 | search_rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
| 174 | if (rate == search_rate) | ||
| 175 | return 1; | ||
| 176 | } | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Finds the highest rate which is: | ||
| 182 | * 1. Present in ri (optionally a basic rate) | ||
| 183 | * 2. Supported by the device | ||
| 184 | * 3. Less than or equal to the user-defined rate | ||
| 185 | */ | ||
| 186 | static u8 highest_supported_rate(struct ieee80211softmac_device *mac, | ||
| 187 | struct ieee80211softmac_ratesinfo *ri, int basic_only) | ||
| 188 | { | ||
| 189 | u8 user_rate = mac->txrates.user_rate; | ||
| 190 | int i; | ||
| 191 | |||
| 192 | if (ri->count == 0) { | ||
| 193 | dprintk(KERN_ERR PFX "empty ratesinfo?\n"); | ||
| 194 | return IEEE80211_CCK_RATE_1MB; | ||
| 195 | } | ||
| 196 | |||
| 197 | for (i = ri->count - 1; i >= 0; i--) { | ||
| 198 | u8 rate = ri->rates[i]; | ||
| 199 | if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK)) | ||
| 200 | continue; | ||
| 201 | rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
| 202 | if (rate > user_rate) | ||
| 203 | continue; | ||
| 204 | if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) | ||
| 205 | return rate; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* If we haven't found a suitable rate by now, just trust the user */ | ||
| 209 | return user_rate; | ||
| 210 | } | ||
| 211 | |||
| 212 | void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac) | ||
| 213 | { | ||
| 214 | struct ieee80211softmac_txrates *txrates = &mac->txrates; | ||
| 215 | struct ieee80211softmac_txrates oldrates; | ||
| 216 | u32 change = 0; | ||
| 217 | |||
| 218 | if (mac->txrates_change) | ||
| 219 | oldrates = mac->txrates; | ||
| 220 | |||
| 221 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
| 222 | txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0); | ||
| 223 | |||
| 224 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
| 225 | txrates->default_fallback = lower_rate(mac, txrates->default_rate); | ||
| 226 | |||
| 227 | change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; | ||
| 228 | txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1); | ||
| 229 | |||
| 230 | if (mac->txrates_change) | ||
| 231 | mac->txrates_change(mac->dev, change, &oldrates); | ||
| 232 | |||
| 233 | } | ||
| 234 | |||
| 235 | void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac) | ||
| 174 | { | 236 | { |
| 175 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
| 176 | struct ieee80211_device *ieee = mac->ieee; | 237 | struct ieee80211_device *ieee = mac->ieee; |
| 177 | u32 change = 0; | 238 | u32 change = 0; |
| 239 | struct ieee80211softmac_txrates *txrates = &mac->txrates; | ||
| 178 | struct ieee80211softmac_txrates oldrates; | 240 | struct ieee80211softmac_txrates oldrates; |
| 179 | 241 | ||
| 180 | ieee80211softmac_start_check_rates(mac); | ||
| 181 | |||
| 182 | /* TODO: We need some kind of state machine to lower the default rates | 242 | /* TODO: We need some kind of state machine to lower the default rates |
| 183 | * if we loose too many packets. | 243 | * if we loose too many packets. |
| 184 | */ | 244 | */ |
| @@ -193,22 +253,37 @@ void ieee80211softmac_start(struct net_device *dev) | |||
| 193 | more reliable. Note similar logic in | 253 | more reliable. Note similar logic in |
| 194 | ieee80211softmac_wx_set_rate() */ | 254 | ieee80211softmac_wx_set_rate() */ |
| 195 | if (ieee->modulation & IEEE80211_CCK_MODULATION) { | 255 | if (ieee->modulation & IEEE80211_CCK_MODULATION) { |
| 196 | mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; | 256 | txrates->user_rate = IEEE80211_CCK_RATE_11MB; |
| 197 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
| 198 | mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB; | ||
| 199 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
| 200 | } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { | 257 | } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { |
| 201 | mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; | 258 | txrates->user_rate = IEEE80211_OFDM_RATE_54MB; |
| 202 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
| 203 | mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB; | ||
| 204 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
| 205 | } else | 259 | } else |
| 206 | assert(0); | 260 | assert(0); |
| 261 | |||
| 262 | txrates->default_rate = IEEE80211_CCK_RATE_1MB; | ||
| 263 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; | ||
| 264 | |||
| 265 | txrates->default_fallback = IEEE80211_CCK_RATE_1MB; | ||
| 266 | change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; | ||
| 267 | |||
| 268 | txrates->mcast_rate = IEEE80211_CCK_RATE_1MB; | ||
| 269 | change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; | ||
| 270 | |||
| 271 | txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB; | ||
| 272 | change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; | ||
| 273 | |||
| 207 | if (mac->txrates_change) | 274 | if (mac->txrates_change) |
| 208 | mac->txrates_change(dev, change, &oldrates); | 275 | mac->txrates_change(mac->dev, change, &oldrates); |
| 209 | 276 | ||
| 210 | mac->running = 1; | 277 | mac->running = 1; |
| 211 | } | 278 | } |
| 279 | |||
| 280 | void ieee80211softmac_start(struct net_device *dev) | ||
| 281 | { | ||
| 282 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
| 283 | |||
| 284 | ieee80211softmac_start_check_rates(mac); | ||
| 285 | ieee80211softmac_init_txrates(mac); | ||
| 286 | } | ||
| 212 | EXPORT_SYMBOL_GPL(ieee80211softmac_start); | 287 | EXPORT_SYMBOL_GPL(ieee80211softmac_start); |
| 213 | 288 | ||
| 214 | void ieee80211softmac_stop(struct net_device *dev) | 289 | void ieee80211softmac_stop(struct net_device *dev) |
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index 65d9816c8ecc..fa1f8e3acfc0 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h | |||
| @@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, | |||
| 116 | struct ieee80211softmac_essid *essid); | 116 | struct ieee80211softmac_essid *essid); |
| 117 | 117 | ||
| 118 | /* Rates related */ | 118 | /* Rates related */ |
| 119 | int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate); | ||
| 119 | u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); | 120 | u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); |
| 121 | void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac); | ||
| 122 | void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac); | ||
| 120 | static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { | 123 | static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { |
| 121 | return ieee80211softmac_lower_rate_delta(mac, rate, 1); | 124 | return ieee80211softmac_lower_rate_delta(mac, rate, 1); |
| 122 | } | 125 | } |
| @@ -150,6 +153,8 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
| 150 | int ieee80211softmac_handle_reassoc_req(struct net_device * dev, | 153 | int ieee80211softmac_handle_reassoc_req(struct net_device * dev, |
| 151 | struct ieee80211_reassoc_request * reassoc); | 154 | struct ieee80211_reassoc_request * reassoc); |
| 152 | void ieee80211softmac_assoc_timeout(void *d); | 155 | void ieee80211softmac_assoc_timeout(void *d); |
| 156 | void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason); | ||
| 157 | void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac); | ||
| 153 | 158 | ||
| 154 | /* some helper functions */ | 159 | /* some helper functions */ |
| 155 | static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) | 160 | static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) |
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c index 27edb2b5581a..22aa6199185b 100644 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ b/net/ieee80211/softmac/ieee80211softmac_wx.c | |||
| @@ -211,8 +211,8 @@ ieee80211softmac_wx_set_rate(struct net_device *net_dev, | |||
| 211 | if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) | 211 | if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) |
| 212 | goto out_unlock; | 212 | goto out_unlock; |
| 213 | 213 | ||
| 214 | mac->txrates.default_rate = rate; | 214 | mac->txrates.user_rate = rate; |
| 215 | mac->txrates.default_fallback = lower_rate(mac, rate); | 215 | ieee80211softmac_recalc_txrates(mac); |
| 216 | err = 0; | 216 | err = 0; |
| 217 | 217 | ||
| 218 | out_unlock: | 218 | out_unlock: |
| @@ -431,3 +431,35 @@ ieee80211softmac_wx_get_genie(struct net_device *dev, | |||
| 431 | } | 431 | } |
| 432 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); | 432 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); |
| 433 | 433 | ||
| 434 | int | ||
| 435 | ieee80211softmac_wx_set_mlme(struct net_device *dev, | ||
| 436 | struct iw_request_info *info, | ||
| 437 | union iwreq_data *wrqu, | ||
| 438 | char *extra) | ||
| 439 | { | ||
| 440 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
| 441 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | ||
| 442 | u16 reason = cpu_to_le16(mlme->reason_code); | ||
| 443 | struct ieee80211softmac_network *net; | ||
| 444 | |||
| 445 | if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) { | ||
| 446 | printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n"); | ||
| 447 | return -EINVAL; | ||
| 448 | } | ||
| 449 | |||
| 450 | switch (mlme->cmd) { | ||
| 451 | case IW_MLME_DEAUTH: | ||
| 452 | net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data); | ||
| 453 | if (!net) { | ||
| 454 | printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n"); | ||
| 455 | return -EINVAL; | ||
| 456 | } | ||
| 457 | return ieee80211softmac_deauth_req(mac, net, reason); | ||
| 458 | case IW_MLME_DISASSOC: | ||
| 459 | ieee80211softmac_send_disassoc_req(mac, reason); | ||
| 460 | return 0; | ||
| 461 | default: | ||
| 462 | return -EOPNOTSUPP; | ||
| 463 | } | ||
| 464 | } | ||
| 465 | EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme); | ||
