diff options
author | Luis Carlos Cobo <luisca@cozybit.com> | 2008-02-23 09:17:12 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-06 15:30:41 -0500 |
commit | f709fc696d72d31273a77b82aa32cb6d19857011 (patch) | |
tree | f10a435b01cd3edf0f350c66de750984370872c4 /net/mac80211/ieee80211_sta.c | |
parent | ee3858551ae6d044578f598f8001db5f1a9fd52e (diff) |
mac80211: mesh changes to the MLME
This includes support for mesh network scanning. The ugly code in
ieee80211_sta_scan_result() is my approach to work around wext. This has been
tested with wireless tools version 29 and works as expected (the new interface
mode is just not shown).
Signed-off-by: Luis Carlos Cobo <luisca@cozybit.com>
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211_sta.c')
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 322 |
1 files changed, 263 insertions, 59 deletions
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index b4b498ae60f2..d2dedcb5a954 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -31,12 +31,16 @@ | |||
31 | #include "ieee80211_i.h" | 31 | #include "ieee80211_i.h" |
32 | #include "ieee80211_rate.h" | 32 | #include "ieee80211_rate.h" |
33 | #include "ieee80211_led.h" | 33 | #include "ieee80211_led.h" |
34 | #ifdef CONFIG_MAC80211_MESH | ||
35 | #include "mesh.h" | ||
36 | #endif | ||
34 | 37 | ||
35 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | 38 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) |
36 | #define IEEE80211_AUTH_MAX_TRIES 3 | 39 | #define IEEE80211_AUTH_MAX_TRIES 3 |
37 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | 40 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) |
38 | #define IEEE80211_ASSOC_MAX_TRIES 3 | 41 | #define IEEE80211_ASSOC_MAX_TRIES 3 |
39 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) | 42 | #define IEEE80211_MONITORING_INTERVAL (2 * HZ) |
43 | #define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) | ||
40 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) | 44 | #define IEEE80211_PROBE_INTERVAL (60 * HZ) |
41 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) | 45 | #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) |
42 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) | 46 | #define IEEE80211_SCAN_INTERVAL (2 * HZ) |
@@ -49,6 +53,7 @@ | |||
49 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) | 53 | #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) |
50 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) | 54 | #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) |
51 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) | 55 | #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) |
56 | #define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) | ||
52 | 57 | ||
53 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 | 58 | #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 |
54 | 59 | ||
@@ -1891,8 +1896,15 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, | |||
1891 | struct ieee80211_sta_bss *bss) | 1896 | struct ieee80211_sta_bss *bss) |
1892 | { | 1897 | { |
1893 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 1898 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
1894 | bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)]; | 1899 | u8 hash_idx; |
1895 | local->sta_bss_hash[STA_HASH(bss->bssid)] = bss; | 1900 | #ifdef CONFIG_MAC80211_MESH |
1901 | if (bss->mesh_cfg) | ||
1902 | hash_idx = mesh_id_hash(bss->mesh_id, bss->mesh_id_len); | ||
1903 | else | ||
1904 | #endif | ||
1905 | hash_idx = STA_HASH(bss->bssid); | ||
1906 | bss->hnext = local->sta_bss_hash[hash_idx]; | ||
1907 | local->sta_bss_hash[hash_idx] = bss; | ||
1896 | } | 1908 | } |
1897 | 1909 | ||
1898 | 1910 | ||
@@ -1945,7 +1957,6 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, | |||
1945 | return bss; | 1957 | return bss; |
1946 | } | 1958 | } |
1947 | 1959 | ||
1948 | |||
1949 | static struct ieee80211_sta_bss * | 1960 | static struct ieee80211_sta_bss * |
1950 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | 1961 | ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, |
1951 | u8 *ssid, u8 ssid_len) | 1962 | u8 *ssid, u8 ssid_len) |
@@ -1956,7 +1967,7 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | |||
1956 | spin_lock_bh(&local->sta_bss_lock); | 1967 | spin_lock_bh(&local->sta_bss_lock); |
1957 | bss = local->sta_bss_hash[STA_HASH(bssid)]; | 1968 | bss = local->sta_bss_hash[STA_HASH(bssid)]; |
1958 | while (bss) { | 1969 | while (bss) { |
1959 | if (!memcmp(bss->bssid, bssid, ETH_ALEN) && | 1970 | if (!bss->mesh_cfg && !memcmp(bss->bssid, bssid, ETH_ALEN) && |
1960 | bss->freq == freq && | 1971 | bss->freq == freq && |
1961 | bss->ssid_len == ssid_len && | 1972 | bss->ssid_len == ssid_len && |
1962 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { | 1973 | (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { |
@@ -1969,6 +1980,72 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, | |||
1969 | return bss; | 1980 | return bss; |
1970 | } | 1981 | } |
1971 | 1982 | ||
1983 | #ifdef CONFIG_MAC80211_MESH | ||
1984 | static struct ieee80211_sta_bss * | ||
1985 | ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, | ||
1986 | u8 *mesh_cfg, int freq) | ||
1987 | { | ||
1988 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1989 | struct ieee80211_sta_bss *bss; | ||
1990 | |||
1991 | spin_lock_bh(&local->sta_bss_lock); | ||
1992 | bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; | ||
1993 | while (bss) { | ||
1994 | if (bss->mesh_cfg && | ||
1995 | !memcmp(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN) && | ||
1996 | bss->freq == freq && | ||
1997 | mesh_id_len == bss->mesh_id_len && | ||
1998 | (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, | ||
1999 | mesh_id_len))) { | ||
2000 | atomic_inc(&bss->users); | ||
2001 | break; | ||
2002 | } | ||
2003 | bss = bss->hnext; | ||
2004 | } | ||
2005 | spin_unlock_bh(&local->sta_bss_lock); | ||
2006 | return bss; | ||
2007 | } | ||
2008 | |||
2009 | static struct ieee80211_sta_bss * | ||
2010 | ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, | ||
2011 | u8 *mesh_cfg, int freq) | ||
2012 | { | ||
2013 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
2014 | struct ieee80211_sta_bss *bss; | ||
2015 | |||
2016 | bss = kzalloc(sizeof(*bss), GFP_ATOMIC); | ||
2017 | if (!bss) | ||
2018 | return NULL; | ||
2019 | |||
2020 | bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); | ||
2021 | if (!bss->mesh_cfg) { | ||
2022 | kfree(bss); | ||
2023 | return NULL; | ||
2024 | } | ||
2025 | |||
2026 | if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { | ||
2027 | bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); | ||
2028 | if (!bss->mesh_id) { | ||
2029 | kfree(bss->mesh_cfg); | ||
2030 | kfree(bss); | ||
2031 | return NULL; | ||
2032 | } | ||
2033 | memcpy(bss->mesh_id, mesh_id, mesh_id_len); | ||
2034 | } | ||
2035 | |||
2036 | atomic_inc(&bss->users); | ||
2037 | atomic_inc(&bss->users); | ||
2038 | memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); | ||
2039 | bss->mesh_id_len = mesh_id_len; | ||
2040 | bss->freq = freq; | ||
2041 | spin_lock_bh(&local->sta_bss_lock); | ||
2042 | /* TODO: order by RSSI? */ | ||
2043 | list_add_tail(&bss->list, &local->sta_bss_list); | ||
2044 | __ieee80211_rx_bss_hash_add(dev, bss); | ||
2045 | spin_unlock_bh(&local->sta_bss_lock); | ||
2046 | return bss; | ||
2047 | } | ||
2048 | #endif | ||
1972 | 2049 | ||
1973 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | 2050 | static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) |
1974 | { | 2051 | { |
@@ -1976,6 +2053,10 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) | |||
1976 | kfree(bss->rsn_ie); | 2053 | kfree(bss->rsn_ie); |
1977 | kfree(bss->wmm_ie); | 2054 | kfree(bss->wmm_ie); |
1978 | kfree(bss->ht_ie); | 2055 | kfree(bss->ht_ie); |
2056 | #ifdef CONFIG_MAC80211_MESH | ||
2057 | kfree(bss->mesh_id); | ||
2058 | kfree(bss->mesh_cfg); | ||
2059 | #endif | ||
1979 | kfree(bss); | 2060 | kfree(bss); |
1980 | } | 2061 | } |
1981 | 2062 | ||
@@ -2171,6 +2252,42 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, | |||
2171 | return res; | 2252 | return res; |
2172 | } | 2253 | } |
2173 | 2254 | ||
2255 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
2256 | struct ieee802_11_elems *elems, | ||
2257 | enum ieee80211_band band) | ||
2258 | { | ||
2259 | struct ieee80211_supported_band *sband; | ||
2260 | struct ieee80211_rate *bitrates; | ||
2261 | size_t num_rates; | ||
2262 | u64 supp_rates; | ||
2263 | int i, j; | ||
2264 | sband = local->hw.wiphy->bands[band]; | ||
2265 | |||
2266 | if (!sband) { | ||
2267 | WARN_ON(1); | ||
2268 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
2269 | } | ||
2270 | |||
2271 | bitrates = sband->bitrates; | ||
2272 | num_rates = sband->n_bitrates; | ||
2273 | supp_rates = 0; | ||
2274 | for (i = 0; i < elems->supp_rates_len + | ||
2275 | elems->ext_supp_rates_len; i++) { | ||
2276 | u8 rate = 0; | ||
2277 | int own_rate; | ||
2278 | if (i < elems->supp_rates_len) | ||
2279 | rate = elems->supp_rates[i]; | ||
2280 | else if (elems->ext_supp_rates) | ||
2281 | rate = elems->ext_supp_rates | ||
2282 | [i - elems->supp_rates_len]; | ||
2283 | own_rate = 5 * (rate & 0x7f); | ||
2284 | for (j = 0; j < num_rates; j++) | ||
2285 | if (bitrates[j].bitrate == own_rate) | ||
2286 | supp_rates |= BIT(j); | ||
2287 | } | ||
2288 | return supp_rates; | ||
2289 | } | ||
2290 | |||
2174 | 2291 | ||
2175 | static void ieee80211_rx_bss_info(struct net_device *dev, | 2292 | static void ieee80211_rx_bss_info(struct net_device *dev, |
2176 | struct ieee80211_mgmt *mgmt, | 2293 | struct ieee80211_mgmt *mgmt, |
@@ -2205,41 +2322,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2205 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); | 2322 | beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); |
2206 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); | 2323 | ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); |
2207 | 2324 | ||
2325 | #ifdef CONFIG_MAC80211_MESH | ||
2326 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && elems.mesh_id | ||
2327 | && elems.mesh_config) | ||
2328 | if (mesh_matches_local(&elems, dev)) { | ||
2329 | u64 rates = ieee80211_sta_get_rates(local, &elems, | ||
2330 | rx_status->band); | ||
2331 | mesh_neighbour_update(mgmt->sa, rates, dev, | ||
2332 | mesh_peer_accepts_plinks(&elems, dev)); | ||
2333 | } | ||
2334 | #endif | ||
2335 | |||
2208 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && | 2336 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && |
2209 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && | 2337 | memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && |
2210 | (sta = sta_info_get(local, mgmt->sa))) { | 2338 | (sta = sta_info_get(local, mgmt->sa))) { |
2211 | struct ieee80211_supported_band *sband; | 2339 | u64 prev_rates; |
2212 | struct ieee80211_rate *bitrates; | 2340 | u64 supp_rates = ieee80211_sta_get_rates(local, &elems, |
2213 | size_t num_rates; | 2341 | rx_status->band); |
2214 | u64 supp_rates, prev_rates; | ||
2215 | int i, j; | ||
2216 | |||
2217 | sband = local->hw.wiphy->bands[rx_status->band]; | ||
2218 | |||
2219 | if (!sband) { | ||
2220 | WARN_ON(1); | ||
2221 | sband = local->hw.wiphy->bands[ | ||
2222 | local->hw.conf.channel->band]; | ||
2223 | } | ||
2224 | |||
2225 | bitrates = sband->bitrates; | ||
2226 | num_rates = sband->n_bitrates; | ||
2227 | |||
2228 | supp_rates = 0; | ||
2229 | for (i = 0; i < elems.supp_rates_len + | ||
2230 | elems.ext_supp_rates_len; i++) { | ||
2231 | u8 rate = 0; | ||
2232 | int own_rate; | ||
2233 | if (i < elems.supp_rates_len) | ||
2234 | rate = elems.supp_rates[i]; | ||
2235 | else if (elems.ext_supp_rates) | ||
2236 | rate = elems.ext_supp_rates | ||
2237 | [i - elems.supp_rates_len]; | ||
2238 | own_rate = 5 * (rate & 0x7f); | ||
2239 | for (j = 0; j < num_rates; j++) | ||
2240 | if (bitrates[j].bitrate == own_rate) | ||
2241 | supp_rates |= BIT(j); | ||
2242 | } | ||
2243 | 2342 | ||
2244 | prev_rates = sta->supp_rates[rx_status->band]; | 2343 | prev_rates = sta->supp_rates[rx_status->band]; |
2245 | sta->supp_rates[rx_status->band] &= supp_rates; | 2344 | sta->supp_rates[rx_status->band] &= supp_rates; |
@@ -2262,19 +2361,28 @@ static void ieee80211_rx_bss_info(struct net_device *dev, | |||
2262 | sta_info_put(sta); | 2361 | sta_info_put(sta); |
2263 | } | 2362 | } |
2264 | 2363 | ||
2265 | if (!elems.ssid) | ||
2266 | return; | ||
2267 | |||
2268 | if (elems.ds_params && elems.ds_params_len == 1) | 2364 | if (elems.ds_params && elems.ds_params_len == 1) |
2269 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); | 2365 | freq = ieee80211_channel_to_frequency(elems.ds_params[0]); |
2270 | else | 2366 | else |
2271 | freq = rx_status->freq; | 2367 | freq = rx_status->freq; |
2272 | 2368 | ||
2273 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, | 2369 | #ifdef CONFIG_MAC80211_MESH |
2274 | elems.ssid, elems.ssid_len); | 2370 | if (elems.mesh_config) |
2275 | if (!bss) { | 2371 | bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, |
2276 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, | 2372 | elems.mesh_id_len, elems.mesh_config, freq); |
2373 | else | ||
2374 | #endif | ||
2375 | bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, | ||
2277 | elems.ssid, elems.ssid_len); | 2376 | elems.ssid, elems.ssid_len); |
2377 | if (!bss) { | ||
2378 | #ifdef CONFIG_MAC80211_MESH | ||
2379 | if (elems.mesh_config) | ||
2380 | bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, | ||
2381 | elems.mesh_id_len, elems.mesh_config, freq); | ||
2382 | else | ||
2383 | #endif | ||
2384 | bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, | ||
2385 | elems.ssid, elems.ssid_len); | ||
2278 | if (!bss) | 2386 | if (!bss) |
2279 | return; | 2387 | return; |
2280 | } else { | 2388 | } else { |
@@ -2601,8 +2709,13 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, | |||
2601 | static void ieee80211_rx_mgmt_action(struct net_device *dev, | 2709 | static void ieee80211_rx_mgmt_action(struct net_device *dev, |
2602 | struct ieee80211_if_sta *ifsta, | 2710 | struct ieee80211_if_sta *ifsta, |
2603 | struct ieee80211_mgmt *mgmt, | 2711 | struct ieee80211_mgmt *mgmt, |
2604 | size_t len) | 2712 | size_t len, |
2713 | struct ieee80211_rx_status *rx_status) | ||
2605 | { | 2714 | { |
2715 | #ifdef CONFIG_MAC80211_MESH | ||
2716 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2717 | #endif | ||
2718 | |||
2606 | if (len < IEEE80211_MIN_ACTION_SIZE) | 2719 | if (len < IEEE80211_MIN_ACTION_SIZE) |
2607 | return; | 2720 | return; |
2608 | 2721 | ||
@@ -2634,7 +2747,21 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, | |||
2634 | break; | 2747 | break; |
2635 | } | 2748 | } |
2636 | break; | 2749 | break; |
2750 | #ifdef CONFIG_MAC80211_MESH | ||
2751 | case PLINK_CATEGORY: | ||
2752 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
2753 | mesh_rx_plink_frame(dev, mgmt, len, rx_status); | ||
2754 | break; | ||
2755 | |||
2756 | case MESH_PATH_SEL_CATEGORY: | ||
2757 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
2758 | mesh_rx_path_sel_frame(dev, mgmt, len); | ||
2759 | break; | ||
2760 | #endif | ||
2637 | default: | 2761 | default: |
2762 | if (net_ratelimit()) | ||
2763 | printk(KERN_DEBUG "%s: Rx unknown action frame - " | ||
2764 | "category=%d\n", dev->name, mgmt->u.action.category); | ||
2638 | break; | 2765 | break; |
2639 | } | 2766 | } |
2640 | } | 2767 | } |
@@ -2661,13 +2788,13 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, | |||
2661 | case IEEE80211_STYPE_PROBE_REQ: | 2788 | case IEEE80211_STYPE_PROBE_REQ: |
2662 | case IEEE80211_STYPE_PROBE_RESP: | 2789 | case IEEE80211_STYPE_PROBE_RESP: |
2663 | case IEEE80211_STYPE_BEACON: | 2790 | case IEEE80211_STYPE_BEACON: |
2791 | case IEEE80211_STYPE_ACTION: | ||
2664 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); | 2792 | memcpy(skb->cb, rx_status, sizeof(*rx_status)); |
2665 | case IEEE80211_STYPE_AUTH: | 2793 | case IEEE80211_STYPE_AUTH: |
2666 | case IEEE80211_STYPE_ASSOC_RESP: | 2794 | case IEEE80211_STYPE_ASSOC_RESP: |
2667 | case IEEE80211_STYPE_REASSOC_RESP: | 2795 | case IEEE80211_STYPE_REASSOC_RESP: |
2668 | case IEEE80211_STYPE_DEAUTH: | 2796 | case IEEE80211_STYPE_DEAUTH: |
2669 | case IEEE80211_STYPE_DISASSOC: | 2797 | case IEEE80211_STYPE_DISASSOC: |
2670 | case IEEE80211_STYPE_ACTION: | ||
2671 | skb_queue_tail(&ifsta->skb_queue, skb); | 2798 | skb_queue_tail(&ifsta->skb_queue, skb); |
2672 | queue_work(local->hw.workqueue, &ifsta->work); | 2799 | queue_work(local->hw.workqueue, &ifsta->work); |
2673 | return; | 2800 | return; |
@@ -2726,7 +2853,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, | |||
2726 | ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); | 2853 | ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); |
2727 | break; | 2854 | break; |
2728 | case IEEE80211_STYPE_ACTION: | 2855 | case IEEE80211_STYPE_ACTION: |
2729 | ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len); | 2856 | ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status); |
2730 | break; | 2857 | break; |
2731 | } | 2858 | } |
2732 | 2859 | ||
@@ -2791,7 +2918,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) | |||
2791 | } | 2918 | } |
2792 | 2919 | ||
2793 | 2920 | ||
2794 | static void ieee80211_sta_expire(struct net_device *dev) | 2921 | static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) |
2795 | { | 2922 | { |
2796 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | 2923 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); |
2797 | struct sta_info *sta, *tmp; | 2924 | struct sta_info *sta, *tmp; |
@@ -2800,8 +2927,7 @@ static void ieee80211_sta_expire(struct net_device *dev) | |||
2800 | 2927 | ||
2801 | write_lock_bh(&local->sta_lock); | 2928 | write_lock_bh(&local->sta_lock); |
2802 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 2929 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
2803 | if (time_after(jiffies, sta->last_rx + | 2930 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
2804 | IEEE80211_IBSS_INACTIVITY_LIMIT)) { | ||
2805 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", | 2931 | printk(KERN_DEBUG "%s: expiring inactive STA %s\n", |
2806 | dev->name, print_mac(mac, sta->addr)); | 2932 | dev->name, print_mac(mac, sta->addr)); |
2807 | __sta_info_get(sta); | 2933 | __sta_info_get(sta); |
@@ -2822,7 +2948,7 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, | |||
2822 | { | 2948 | { |
2823 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); | 2949 | mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); |
2824 | 2950 | ||
2825 | ieee80211_sta_expire(dev); | 2951 | ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT); |
2826 | if (ieee80211_sta_active_ibss(dev)) | 2952 | if (ieee80211_sta_active_ibss(dev)) |
2827 | return; | 2953 | return; |
2828 | 2954 | ||
@@ -2832,6 +2958,36 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, | |||
2832 | } | 2958 | } |
2833 | 2959 | ||
2834 | 2960 | ||
2961 | #ifdef CONFIG_MAC80211_MESH | ||
2962 | static void ieee80211_mesh_housekeeping(struct net_device *dev, | ||
2963 | struct ieee80211_if_sta *ifsta) | ||
2964 | { | ||
2965 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2966 | bool free_plinks; | ||
2967 | |||
2968 | ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); | ||
2969 | mesh_path_expire(dev); | ||
2970 | |||
2971 | free_plinks = mesh_plink_availables(sdata); | ||
2972 | if (free_plinks != sdata->u.sta.accepting_plinks) | ||
2973 | ieee80211_if_config_beacon(dev); | ||
2974 | |||
2975 | mod_timer(&ifsta->timer, jiffies + | ||
2976 | IEEE80211_MESH_HOUSEKEEPING_INTERVAL); | ||
2977 | } | ||
2978 | |||
2979 | |||
2980 | void ieee80211_start_mesh(struct net_device *dev) | ||
2981 | { | ||
2982 | struct ieee80211_if_sta *ifsta; | ||
2983 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
2984 | ifsta = &sdata->u.sta; | ||
2985 | ifsta->state = IEEE80211_MESH_UP; | ||
2986 | ieee80211_sta_timer((unsigned long)sdata); | ||
2987 | } | ||
2988 | #endif | ||
2989 | |||
2990 | |||
2835 | void ieee80211_sta_timer(unsigned long data) | 2991 | void ieee80211_sta_timer(unsigned long data) |
2836 | { | 2992 | { |
2837 | struct ieee80211_sub_if_data *sdata = | 2993 | struct ieee80211_sub_if_data *sdata = |
@@ -2843,7 +2999,6 @@ void ieee80211_sta_timer(unsigned long data) | |||
2843 | queue_work(local->hw.workqueue, &ifsta->work); | 2999 | queue_work(local->hw.workqueue, &ifsta->work); |
2844 | } | 3000 | } |
2845 | 3001 | ||
2846 | |||
2847 | void ieee80211_sta_work(struct work_struct *work) | 3002 | void ieee80211_sta_work(struct work_struct *work) |
2848 | { | 3003 | { |
2849 | struct ieee80211_sub_if_data *sdata = | 3004 | struct ieee80211_sub_if_data *sdata = |
@@ -2860,7 +3015,8 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2860 | return; | 3015 | return; |
2861 | 3016 | ||
2862 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | 3017 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && |
2863 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { | 3018 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS && |
3019 | sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { | ||
2864 | printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " | 3020 | printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " |
2865 | "(type=%d)\n", dev->name, sdata->vif.type); | 3021 | "(type=%d)\n", dev->name, sdata->vif.type); |
2866 | return; | 3022 | return; |
@@ -2870,6 +3026,12 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2870 | while ((skb = skb_dequeue(&ifsta->skb_queue))) | 3026 | while ((skb = skb_dequeue(&ifsta->skb_queue))) |
2871 | ieee80211_sta_rx_queued_mgmt(dev, skb); | 3027 | ieee80211_sta_rx_queued_mgmt(dev, skb); |
2872 | 3028 | ||
3029 | #ifdef CONFIG_MAC80211_MESH | ||
3030 | if (ifsta->preq_queue_len && time_after(jiffies, ifsta->last_preq + | ||
3031 | msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) | ||
3032 | mesh_path_start_discovery(dev); | ||
3033 | #endif | ||
3034 | |||
2873 | if (ifsta->state != IEEE80211_AUTHENTICATE && | 3035 | if (ifsta->state != IEEE80211_AUTHENTICATE && |
2874 | ifsta->state != IEEE80211_ASSOCIATE && | 3036 | ifsta->state != IEEE80211_ASSOCIATE && |
2875 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { | 3037 | test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { |
@@ -2905,6 +3067,11 @@ void ieee80211_sta_work(struct work_struct *work) | |||
2905 | case IEEE80211_IBSS_JOINED: | 3067 | case IEEE80211_IBSS_JOINED: |
2906 | ieee80211_sta_merge_ibss(dev, ifsta); | 3068 | ieee80211_sta_merge_ibss(dev, ifsta); |
2907 | break; | 3069 | break; |
3070 | #ifdef CONFIG_MAC80211_MESH | ||
3071 | case IEEE80211_MESH_UP: | ||
3072 | ieee80211_mesh_housekeeping(dev, ifsta); | ||
3073 | break; | ||
3074 | #endif | ||
2908 | default: | 3075 | default: |
2909 | printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", | 3076 | printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", |
2910 | ifsta->state); | 3077 | ifsta->state); |
@@ -3109,7 +3276,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, | |||
3109 | sband = local->hw.wiphy->bands[bss->band]; | 3276 | sband = local->hw.wiphy->bands[bss->band]; |
3110 | 3277 | ||
3111 | if (local->hw.conf.beacon_int == 0) | 3278 | if (local->hw.conf.beacon_int == 0) |
3112 | local->hw.conf.beacon_int = 100; | 3279 | local->hw.conf.beacon_int = 10000; |
3113 | bss->beacon_int = local->hw.conf.beacon_int; | 3280 | bss->beacon_int = local->hw.conf.beacon_int; |
3114 | bss->last_update = jiffies; | 3281 | bss->last_update = jiffies; |
3115 | bss->capability = WLAN_CAPABILITY_IBSS; | 3282 | bss->capability = WLAN_CAPABILITY_IBSS; |
@@ -3398,6 +3565,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) | |||
3398 | ieee80211_sta_timer((unsigned long)sdata); | 3565 | ieee80211_sta_timer((unsigned long)sdata); |
3399 | } | 3566 | } |
3400 | 3567 | ||
3568 | if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) | ||
3569 | ieee80211_sta_timer((unsigned long)sdata); | ||
3570 | |||
3401 | netif_wake_queue(sdata->dev); | 3571 | netif_wake_queue(sdata->dev); |
3402 | } | 3572 | } |
3403 | rcu_read_unlock(); | 3573 | rcu_read_unlock(); |
@@ -3640,15 +3810,27 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
3640 | 3810 | ||
3641 | memset(&iwe, 0, sizeof(iwe)); | 3811 | memset(&iwe, 0, sizeof(iwe)); |
3642 | iwe.cmd = SIOCGIWESSID; | 3812 | iwe.cmd = SIOCGIWESSID; |
3643 | iwe.u.data.length = bss->ssid_len; | 3813 | if (bss->mesh_cfg) { |
3644 | iwe.u.data.flags = 1; | 3814 | #ifdef CONFIG_MAC80211_MESH |
3645 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | 3815 | iwe.u.data.length = bss->mesh_id_len; |
3646 | bss->ssid); | 3816 | iwe.u.data.flags = 1; |
3817 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
3818 | bss->mesh_id); | ||
3819 | #endif | ||
3820 | } else { | ||
3821 | iwe.u.data.length = bss->ssid_len; | ||
3822 | iwe.u.data.flags = 1; | ||
3823 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
3824 | bss->ssid); | ||
3825 | } | ||
3647 | 3826 | ||
3648 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { | 3827 | if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS |
3828 | || bss->mesh_cfg)) { | ||
3649 | memset(&iwe, 0, sizeof(iwe)); | 3829 | memset(&iwe, 0, sizeof(iwe)); |
3650 | iwe.cmd = SIOCGIWMODE; | 3830 | iwe.cmd = SIOCGIWMODE; |
3651 | if (bss->capability & WLAN_CAPABILITY_ESS) | 3831 | if (bss->mesh_cfg) |
3832 | iwe.u.mode = IW_MODE_MESH; | ||
3833 | else if (bss->capability & WLAN_CAPABILITY_ESS) | ||
3652 | iwe.u.mode = IW_MODE_MASTER; | 3834 | iwe.u.mode = IW_MODE_MASTER; |
3653 | else | 3835 | else |
3654 | iwe.u.mode = IW_MODE_ADHOC; | 3836 | iwe.u.mode = IW_MODE_ADHOC; |
@@ -3737,6 +3919,28 @@ ieee80211_sta_scan_result(struct net_device *dev, | |||
3737 | } | 3919 | } |
3738 | } | 3920 | } |
3739 | 3921 | ||
3922 | if (bss->mesh_cfg) { | ||
3923 | char *buf; | ||
3924 | u8 *cfg = bss->mesh_cfg; | ||
3925 | buf = kmalloc(200, GFP_ATOMIC); | ||
3926 | if (buf) { | ||
3927 | memset(&iwe, 0, sizeof(iwe)); | ||
3928 | iwe.cmd = IWEVCUSTOM; | ||
3929 | sprintf(buf, "Mesh network (version %d)\n" | ||
3930 | "\t\t\tPath Selection Protocol ID: 0x%02X%02X%02X%02X\n" | ||
3931 | "\t\t\tPath Selection Metric ID: 0x%02X%02X%02X%02X\n" | ||
3932 | "\t\t\tCongestion Control Mode ID: 0x%02X%02X%02X%02X\n" | ||
3933 | "\t\t\tChannel Precedence: 0x%02X%02X%02X%02X", | ||
3934 | cfg[0], cfg[1], cfg[2], cfg[3], cfg[4], cfg[5], cfg[6], | ||
3935 | cfg[7], cfg[8], cfg[9], cfg[10], cfg[11], cfg[12], | ||
3936 | cfg[13], cfg[14], cfg[15], cfg[16]); | ||
3937 | iwe.u.data.length = strlen(buf); | ||
3938 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
3939 | &iwe, buf); | ||
3940 | kfree(buf); | ||
3941 | } | ||
3942 | } | ||
3943 | |||
3740 | return current_ev; | 3944 | return current_ev; |
3741 | } | 3945 | } |
3742 | 3946 | ||