aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-09-08 11:44:26 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-09-11 15:53:37 -0400
commit98c8fccfaea838e62ffde2f2e44568844e0e5472 (patch)
treec69552d4be03dd8321b6f90b3fbb17c607fa9940
parent0a51b27e956bd9580296c48191b78175ed8b5971 (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.h9
-rw-r--r--net/mac80211/mlme.c253
-rw-r--r--net/mac80211/scan.c68
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,
937void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); 937void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
938int ieee80211_sta_start_scan(struct ieee80211_sub_if_data *scan_sdata, 938int 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);
940struct ieee80211_sta_bss *
941ieee80211_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);
947void 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
942void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); 951void 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
130static struct ieee80211_sta_bss * 130static struct ieee80211_sta_bss *
131ieee80211_rx_bss_add(struct ieee80211_sub_if_data *sdata, u8 *bssid, int freq, 131ieee80211_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
233static void ieee80211_rx_bss_put(struct ieee80211_local *local, 232void 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
2446static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, 2445struct ieee80211_sta_bss *
2447 struct ieee80211_mgmt *mgmt, 2446ieee80211_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
2553static 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
2985ieee80211_rx_result
2986ieee80211_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
3020static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) 3001static 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
26ieee80211_rx_result
27ieee80211_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
26static void ieee80211_send_nullfunc(struct ieee80211_local *local, 94static 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)