diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-09-08 11:44:26 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-11 15:53:37 -0400 |
commit | 98c8fccfaea838e62ffde2f2e44568844e0e5472 (patch) | |
tree | c69552d4be03dd8321b6f90b3fbb17c607fa9940 | |
parent | 0a51b27e956bd9580296c48191b78175ed8b5971 (diff) |
mac80211: refactor and move scan RX code
This patch refactors some code and moves the scan RX function
to scan.c. More importantly, however, it changes it so that the
MLME's beacon/probe_resp functions aren't invoked when scanning
so that we can remove a "if (scanning)" conditions from two
places.
There's a very slight behavioural change in this patch: now,
when scanning, IBSS and mesh aren't updated even on the same
channel.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | net/mac80211/ieee80211_i.h | 9 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 253 | ||||
-rw-r--r-- | net/mac80211/scan.c | 68 |
3 files changed, 194 insertions, 136 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 25dccd5cb2ff..4753ed3f3f10 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -937,6 +937,15 @@ void ieee802_11_parse_elems(u8 *start, size_t len, | |||
937 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 937 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
938 | int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, | 938 | int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, |
939 | u8 *ssid, size_t ssid_len); | 939 | u8 *ssid, size_t ssid_len); |
940 | struct ieee80211_sta_bss * | ||
941 | ieee80211_bss_info_update(struct ieee80211_local *local, | ||
942 | struct ieee80211_rx_status *rx_status, | ||
943 | struct ieee80211_mgmt *mgmt, | ||
944 | size_t len, | ||
945 | struct ieee802_11_elems *elems, | ||
946 | int freq, bool beacon); | ||
947 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||
948 | struct ieee80211_sta_bss *bss); | ||
940 | 949 | ||
941 | #ifdef CONFIG_MAC80211_MESH | 950 | #ifdef CONFIG_MAC80211_MESH |
942 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); | 951 | void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 2caea9759b7e..1708a3d1cd38 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -128,10 +128,9 @@ static void __ieee80211_rx_bss_hash_del(struct ieee80211_local *local, | |||
128 | } | 128 | } |
129 | 129 | ||
130 | static struct ieee80211_sta_bss * | 130 | static struct ieee80211_sta_bss * |
131 | ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, | 131 | ieee80211_rx_bss_add(struct ieee80211_local *local, u8 *bssid, int freq, |
132 | u8 *ssid, u8 ssid_len) | 132 | u8 *ssid, u8 ssid_len) |
133 | { | 133 | { |
134 | struct ieee80211_local *local = sdata->local; | ||
135 | struct ieee80211_sta_bss *bss; | 134 | struct ieee80211_sta_bss *bss; |
136 | 135 | ||
137 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | 136 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); |
@@ -230,8 +229,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | |||
230 | kfree(bss); | 229 | kfree(bss); |
231 | } | 230 | } |
232 | 231 | ||
233 | static void ieee80211_rx_bss_put(struct ieee80211_local *local, | 232 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
234 | struct ieee80211_sta_bss *bss) | 233 | struct ieee80211_sta_bss *bss) |
235 | { | 234 | { |
236 | local_bh_disable(); | 235 | local_bh_disable(); |
237 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { | 236 | if (!atomic_dec_and_lock(&bss->users, &local->sta_bss_lock)) { |
@@ -2443,74 +2442,16 @@ static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local, | |||
2443 | return mandatory_rates; | 2442 | return mandatory_rates; |
2444 | } | 2443 | } |
2445 | 2444 | ||
2446 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | 2445 | struct ieee80211_sta_bss * |
2447 | struct ieee80211_mgmt *mgmt, | 2446 | ieee80211_bss_info_update(struct ieee80211_local *local, |
2448 | size_t len, | 2447 | struct ieee80211_rx_status *rx_status, |
2449 | struct ieee80211_rx_status *rx_status, | 2448 | struct ieee80211_mgmt *mgmt, |
2450 | struct ieee802_11_elems *elems) | 2449 | size_t len, |
2450 | struct ieee802_11_elems *elems, | ||
2451 | int freq, bool beacon) | ||
2451 | { | 2452 | { |
2452 | struct ieee80211_local *local = sdata->local; | ||
2453 | int freq, clen; | ||
2454 | struct ieee80211_sta_bss *bss; | 2453 | struct ieee80211_sta_bss *bss; |
2455 | struct sta_info *sta; | 2454 | int clen; |
2456 | struct ieee80211_channel *channel; | ||
2457 | u64 beacon_timestamp, rx_timestamp; | ||
2458 | u64 supp_rates = 0; | ||
2459 | bool beacon = ieee80211_is_beacon(mgmt->frame_control); | ||
2460 | enum ieee80211_band band = rx_status->band; | ||
2461 | DECLARE_MAC_BUF(mac); | ||
2462 | DECLARE_MAC_BUF(mac2); | ||
2463 | |||
2464 | if (elems->ds_params && elems->ds_params_len == 1) | ||
2465 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
2466 | else | ||
2467 | freq = rx_status->freq; | ||
2468 | |||
2469 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
2470 | |||
2471 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
2472 | return; | ||
2473 | |||
2474 | if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id && | ||
2475 | elems->mesh_config && mesh_matches_local(elems, sdata)) { | ||
2476 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
2477 | |||
2478 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, | ||
2479 | mesh_peer_accepts_plinks(elems)); | ||
2480 | } | ||
2481 | |||
2482 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates && | ||
2483 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | ||
2484 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
2485 | |||
2486 | rcu_read_lock(); | ||
2487 | |||
2488 | sta = sta_info_get(local, mgmt->sa); | ||
2489 | if (sta) { | ||
2490 | u64 prev_rates; | ||
2491 | |||
2492 | prev_rates = sta->supp_rates[band]; | ||
2493 | /* make sure mandatory rates are always added */ | ||
2494 | sta->supp_rates[band] = supp_rates | | ||
2495 | ieee80211_sta_get_mandatory_rates(local, band); | ||
2496 | |||
2497 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2498 | if (sta->supp_rates[band] != prev_rates) | ||
2499 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
2500 | "for %s based on beacon info (0x%llx | " | ||
2501 | "0x%llx -> 0x%llx)\n", | ||
2502 | sdata->dev->name, print_mac(mac, sta->addr), | ||
2503 | (unsigned long long) prev_rates, | ||
2504 | (unsigned long long) supp_rates, | ||
2505 | (unsigned long long) sta->supp_rates[band]); | ||
2506 | #endif | ||
2507 | } else { | ||
2508 | ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid, | ||
2509 | mgmt->sa, supp_rates); | ||
2510 | } | ||
2511 | |||
2512 | rcu_read_unlock(); | ||
2513 | } | ||
2514 | 2455 | ||
2515 | #ifdef CONFIG_MAC80211_MESH | 2456 | #ifdef CONFIG_MAC80211_MESH |
2516 | if (elems->mesh_config) | 2457 | if (elems->mesh_config) |
@@ -2528,10 +2469,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2528 | elems->mesh_config_len, freq); | 2469 | elems->mesh_config_len, freq); |
2529 | else | 2470 | else |
2530 | #endif | 2471 | #endif |
2531 | bss = ieee80211_rx_bss_add(sdata, mgmt->bssid, freq, | 2472 | bss = ieee80211_rx_bss_add(local, mgmt->bssid, freq, |
2532 | elems->ssid, elems->ssid_len); | 2473 | elems->ssid, elems->ssid_len); |
2533 | if (!bss) | 2474 | if (!bss) |
2534 | return; | 2475 | return NULL; |
2535 | } else { | 2476 | } else { |
2536 | #if 0 | 2477 | #if 0 |
2537 | /* TODO: order by RSSI? */ | 2478 | /* TODO: order by RSSI? */ |
@@ -2578,17 +2519,114 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2578 | bss->supp_rates_len += clen; | 2519 | bss->supp_rates_len += clen; |
2579 | } | 2520 | } |
2580 | 2521 | ||
2581 | bss->band = band; | 2522 | bss->band = rx_status->band; |
2582 | 2523 | ||
2583 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | 2524 | bss->timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
2584 | |||
2585 | bss->timestamp = beacon_timestamp; | ||
2586 | bss->last_update = jiffies; | 2525 | bss->last_update = jiffies; |
2587 | bss->signal = rx_status->signal; | 2526 | bss->signal = rx_status->signal; |
2588 | bss->noise = rx_status->noise; | 2527 | bss->noise = rx_status->noise; |
2589 | bss->qual = rx_status->qual; | 2528 | bss->qual = rx_status->qual; |
2529 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | ||
2530 | |||
2590 | if (!beacon) | 2531 | if (!beacon) |
2591 | bss->last_probe_resp = jiffies; | 2532 | bss->last_probe_resp = jiffies; |
2533 | |||
2534 | /* | ||
2535 | * For probe responses, or if we don't have any information yet, | ||
2536 | * use the IEs from the beacon. | ||
2537 | */ | ||
2538 | if (!bss->ies || !beacon) { | ||
2539 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { | ||
2540 | kfree(bss->ies); | ||
2541 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); | ||
2542 | } | ||
2543 | if (bss->ies) { | ||
2544 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
2545 | bss->ies_len = elems->total_len; | ||
2546 | } else | ||
2547 | bss->ies_len = 0; | ||
2548 | } | ||
2549 | |||
2550 | return bss; | ||
2551 | } | ||
2552 | |||
2553 | static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||
2554 | struct ieee80211_mgmt *mgmt, | ||
2555 | size_t len, | ||
2556 | struct ieee80211_rx_status *rx_status, | ||
2557 | struct ieee802_11_elems *elems, | ||
2558 | bool beacon) | ||
2559 | { | ||
2560 | struct ieee80211_local *local = sdata->local; | ||
2561 | int freq; | ||
2562 | struct ieee80211_sta_bss *bss; | ||
2563 | struct sta_info *sta; | ||
2564 | struct ieee80211_channel *channel; | ||
2565 | u64 beacon_timestamp, rx_timestamp; | ||
2566 | u64 supp_rates = 0; | ||
2567 | enum ieee80211_band band = rx_status->band; | ||
2568 | DECLARE_MAC_BUF(mac); | ||
2569 | DECLARE_MAC_BUF(mac2); | ||
2570 | |||
2571 | if (elems->ds_params && elems->ds_params_len == 1) | ||
2572 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | ||
2573 | else | ||
2574 | freq = rx_status->freq; | ||
2575 | |||
2576 | channel = ieee80211_get_channel(local->hw.wiphy, freq); | ||
2577 | |||
2578 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
2579 | return; | ||
2580 | |||
2581 | if (ieee80211_vif_is_mesh(&sdata->vif) && elems->mesh_id && | ||
2582 | elems->mesh_config && mesh_matches_local(elems, sdata)) { | ||
2583 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
2584 | |||
2585 | mesh_neighbour_update(mgmt->sa, supp_rates, sdata, | ||
2586 | mesh_peer_accepts_plinks(elems)); | ||
2587 | } | ||
2588 | |||
2589 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems->supp_rates && | ||
2590 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { | ||
2591 | supp_rates = ieee80211_sta_get_rates(local, elems, band); | ||
2592 | |||
2593 | rcu_read_lock(); | ||
2594 | |||
2595 | sta = sta_info_get(local, mgmt->sa); | ||
2596 | if (sta) { | ||
2597 | u64 prev_rates; | ||
2598 | |||
2599 | prev_rates = sta->supp_rates[band]; | ||
2600 | /* make sure mandatory rates are always added */ | ||
2601 | sta->supp_rates[band] = supp_rates | | ||
2602 | ieee80211_sta_get_mandatory_rates(local, band); | ||
2603 | |||
2604 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||
2605 | if (sta->supp_rates[band] != prev_rates) | ||
2606 | printk(KERN_DEBUG "%s: updated supp_rates set " | ||
2607 | "for %s based on beacon info (0x%llx | " | ||
2608 | "0x%llx -> 0x%llx)\n", | ||
2609 | sdata->dev->name, print_mac(mac, sta->addr), | ||
2610 | (unsigned long long) prev_rates, | ||
2611 | (unsigned long long) supp_rates, | ||
2612 | (unsigned long long) sta->supp_rates[band]); | ||
2613 | #endif | ||
2614 | } else { | ||
2615 | ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid, | ||
2616 | mgmt->sa, supp_rates); | ||
2617 | } | ||
2618 | |||
2619 | rcu_read_unlock(); | ||
2620 | } | ||
2621 | |||
2622 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | ||
2623 | freq, beacon); | ||
2624 | if (!bss) | ||
2625 | return; | ||
2626 | |||
2627 | /* was just updated in ieee80211_bss_info_update */ | ||
2628 | beacon_timestamp = bss->timestamp; | ||
2629 | |||
2592 | /* | 2630 | /* |
2593 | * In STA mode, the remaining parameters should not be overridden | 2631 | * In STA mode, the remaining parameters should not be overridden |
2594 | * by beacons because they're not necessarily accurate there. | 2632 | * by beacons because they're not necessarily accurate there. |
@@ -2599,21 +2637,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
2599 | return; | 2637 | return; |
2600 | } | 2638 | } |
2601 | 2639 | ||
2602 | if (bss->ies == NULL || bss->ies_len < elems->total_len) { | ||
2603 | kfree(bss->ies); | ||
2604 | bss->ies = kmalloc(elems->total_len, GFP_ATOMIC); | ||
2605 | } | ||
2606 | if (bss->ies) { | ||
2607 | memcpy(bss->ies, elems->ie_start, elems->total_len); | ||
2608 | bss->ies_len = elems->total_len; | ||
2609 | } else | ||
2610 | bss->ies_len = 0; | ||
2611 | |||
2612 | bss->wmm_used = elems->wmm_param || elems->wmm_info; | ||
2613 | |||
2614 | /* check if we need to merge IBSS */ | 2640 | /* check if we need to merge IBSS */ |
2615 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && | 2641 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && |
2616 | !local->sta_sw_scanning && !local->sta_hw_scanning && | ||
2617 | bss->capability & WLAN_CAPABILITY_IBSS && | 2642 | bss->capability & WLAN_CAPABILITY_IBSS && |
2618 | bss->freq == local->oper_channel->center_freq && | 2643 | bss->freq == local->oper_channel->center_freq && |
2619 | elems->ssid_len == sdata->u.sta.ssid_len && | 2644 | elems->ssid_len == sdata->u.sta.ssid_len && |
@@ -2690,7 +2715,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
2690 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 2715 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
2691 | &elems); | 2716 | &elems); |
2692 | 2717 | ||
2693 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2718 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
2694 | 2719 | ||
2695 | /* direct probe may be part of the association flow */ | 2720 | /* direct probe may be part of the association flow */ |
2696 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, | 2721 | if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE, |
@@ -2721,7 +2746,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2721 | 2746 | ||
2722 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 2747 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); |
2723 | 2748 | ||
2724 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems); | 2749 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true); |
2725 | 2750 | ||
2726 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | 2751 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) |
2727 | return; | 2752 | return; |
@@ -2731,15 +2756,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
2731 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) | 2756 | memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) |
2732 | return; | 2757 | return; |
2733 | 2758 | ||
2734 | /* Do not send changes to driver if we are scanning. This removes | ||
2735 | * requirement that a driver's bss_info_changed/conf_tx functions | ||
2736 | * need to be atomic. | ||
2737 | * This is really ugly code, we should rewrite scanning and make | ||
2738 | * all this more understandable for humans. | ||
2739 | */ | ||
2740 | if (local->sta_sw_scanning || local->sta_hw_scanning) | ||
2741 | return; | ||
2742 | |||
2743 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 2759 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
2744 | elems.wmm_param_len); | 2760 | elems.wmm_param_len); |
2745 | 2761 | ||
@@ -2982,41 +2998,6 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
2982 | } | 2998 | } |
2983 | 2999 | ||
2984 | 3000 | ||
2985 | ieee80211_rx_result | ||
2986 | ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
2987 | struct ieee80211_rx_status *rx_status) | ||
2988 | { | ||
2989 | struct ieee80211_mgmt *mgmt; | ||
2990 | __le16 fc; | ||
2991 | |||
2992 | if (skb->len < 2) | ||
2993 | return RX_DROP_UNUSABLE; | ||
2994 | |||
2995 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
2996 | fc = mgmt->frame_control; | ||
2997 | |||
2998 | if (ieee80211_is_ctl(fc)) | ||
2999 | return RX_CONTINUE; | ||
3000 | |||
3001 | if (skb->len < 24) | ||
3002 | return RX_DROP_MONITOR; | ||
3003 | |||
3004 | if (ieee80211_is_probe_resp(fc)) { | ||
3005 | ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len, rx_status); | ||
3006 | dev_kfree_skb(skb); | ||
3007 | return RX_QUEUED; | ||
3008 | } | ||
3009 | |||
3010 | if (ieee80211_is_beacon(fc)) { | ||
3011 | ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len, rx_status); | ||
3012 | dev_kfree_skb(skb); | ||
3013 | return RX_QUEUED; | ||
3014 | } | ||
3015 | |||
3016 | return RX_CONTINUE; | ||
3017 | } | ||
3018 | |||
3019 | |||
3020 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | 3001 | static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) |
3021 | { | 3002 | { |
3022 | struct ieee80211_local *local = sdata->local; | 3003 | struct ieee80211_local *local = sdata->local; |
@@ -3233,7 +3214,7 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, | |||
3233 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", | 3214 | printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", |
3234 | sdata->dev->name, print_mac(mac, bssid)); | 3215 | sdata->dev->name, print_mac(mac, bssid)); |
3235 | 3216 | ||
3236 | bss = ieee80211_rx_bss_add(sdata, bssid, | 3217 | bss = ieee80211_rx_bss_add(local, bssid, |
3237 | local->hw.conf.channel->center_freq, | 3218 | local->hw.conf.channel->center_freq, |
3238 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); | 3219 | sdata->u.sta.ssid, sdata->u.sta.ssid_len); |
3239 | if (!bss) | 3220 | if (!bss) |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 68fa782acd75..2848ba3a08e3 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -23,6 +23,74 @@ | |||
23 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) | 23 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) |
24 | 24 | ||
25 | 25 | ||
26 | ieee80211_rx_result | ||
27 | ieee80211_sta_rx_scan(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | ||
28 | struct ieee80211_rx_status *rx_status) | ||
29 | { | ||
30 | struct ieee80211_mgmt *mgmt; | ||
31 | struct ieee80211_sta_bss *bss; | ||
32 | u8 *elements; | ||
33 | struct ieee80211_channel *channel; | ||
34 | size_t baselen; | ||
35 | int freq; | ||
36 | __le16 fc; | ||
37 | bool presp, beacon = false; | ||
38 | struct ieee802_11_elems elems; | ||
39 | |||
40 | if (skb->len < 2) | ||
41 | return RX_DROP_UNUSABLE; | ||
42 | |||
43 | mgmt = (struct ieee80211_mgmt *) skb->data; | ||
44 | fc = mgmt->frame_control; | ||
45 | |||
46 | if (ieee80211_is_ctl(fc)) | ||
47 | return RX_CONTINUE; | ||
48 | |||
49 | if (skb->len < 24) | ||
50 | return RX_DROP_MONITOR; | ||
51 | |||
52 | presp = ieee80211_is_probe_resp(fc); | ||
53 | if (presp) { | ||
54 | /* ignore ProbeResp to foreign address */ | ||
55 | if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN)) | ||
56 | return RX_DROP_MONITOR; | ||
57 | |||
58 | presp = true; | ||
59 | elements = mgmt->u.probe_resp.variable; | ||
60 | baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); | ||
61 | } else { | ||
62 | beacon = ieee80211_is_beacon(fc); | ||
63 | baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); | ||
64 | elements = mgmt->u.beacon.variable; | ||
65 | } | ||
66 | |||
67 | if (!presp && !beacon) | ||
68 | return RX_CONTINUE; | ||
69 | |||
70 | if (baselen > skb->len) | ||
71 | return RX_DROP_MONITOR; | ||
72 | |||
73 | ieee802_11_parse_elems(elements, skb->len - baselen, &elems); | ||
74 | |||
75 | if (elems.ds_params && elems.ds_params_len == 1) | ||
76 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | ||
77 | else | ||
78 | freq = rx_status->freq; | ||
79 | |||
80 | channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); | ||
81 | |||
82 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | ||
83 | return RX_DROP_MONITOR; | ||
84 | |||
85 | bss = ieee80211_bss_info_update(sdata->local, rx_status, | ||
86 | mgmt, skb->len, &elems, | ||
87 | freq, beacon); | ||
88 | ieee80211_rx_bss_put(sdata->local, bss); | ||
89 | |||
90 | dev_kfree_skb(skb); | ||
91 | return RX_QUEUED; | ||
92 | } | ||
93 | |||
26 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, | 94 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, |
27 | struct ieee80211_sub_if_data *sdata, | 95 | struct ieee80211_sub_if_data *sdata, |
28 | int powersave) | 96 | int powersave) |