diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-09-10 18:01:52 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-09-15 16:48:21 -0400 |
commit | 9c6bd79011b14a8bfe58aad0acfb51e4dca05eed (patch) | |
tree | 0101b96437b5fb9421e8f291e3a99d0a2bf300a9 /net/mac80211/mlme.c | |
parent | 5bc75728fd43bb15b46f16ef465bcf9d487393cf (diff) |
mac80211: reorder MLME code more
This way all the utility functions are at the top, then the
state machine and externally callable functions are moved to
the bottom. Also clean up ieee80211_i.h a bit and add a few
comments about which functions are called from where.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 624 |
1 files changed, 325 insertions, 299 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 19c7f21e49d1..e14830106526 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -93,44 +93,46 @@ static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | |||
93 | return count; | 93 | return count; |
94 | } | 94 | } |
95 | 95 | ||
96 | /* frame sending functions */ | 96 | /* also used by mesh code */ |
97 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 97 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, |
98 | struct ieee80211_if_sta *ifsta, | 98 | struct ieee802_11_elems *elems, |
99 | int transaction, u8 *extra, size_t extra_len, | 99 | enum ieee80211_band band) |
100 | int encrypt) | ||
101 | { | 100 | { |
102 | struct ieee80211_local *local = sdata->local; | 101 | struct ieee80211_supported_band *sband; |
103 | struct sk_buff *skb; | 102 | struct ieee80211_rate *bitrates; |
104 | struct ieee80211_mgmt *mgmt; | 103 | size_t num_rates; |
104 | u64 supp_rates; | ||
105 | int i, j; | ||
106 | sband = local->hw.wiphy->bands[band]; | ||
105 | 107 | ||
106 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 108 | if (!sband) { |
107 | sizeof(*mgmt) + 6 + extra_len); | 109 | WARN_ON(1); |
108 | if (!skb) { | 110 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; |
109 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
110 | "frame\n", sdata->dev->name); | ||
111 | return; | ||
112 | } | 111 | } |
113 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
114 | 112 | ||
115 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | 113 | bitrates = sband->bitrates; |
116 | memset(mgmt, 0, 24 + 6); | 114 | num_rates = sband->n_bitrates; |
117 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 115 | supp_rates = 0; |
118 | IEEE80211_STYPE_AUTH); | 116 | for (i = 0; i < elems->supp_rates_len + |
119 | if (encrypt) | 117 | elems->ext_supp_rates_len; i++) { |
120 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | 118 | u8 rate = 0; |
121 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | 119 | int own_rate; |
122 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 120 | if (i < elems->supp_rates_len) |
123 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | 121 | rate = elems->supp_rates[i]; |
124 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | 122 | else if (elems->ext_supp_rates) |
125 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | 123 | rate = elems->ext_supp_rates |
126 | ifsta->auth_transaction = transaction + 1; | 124 | [i - elems->supp_rates_len]; |
127 | mgmt->u.auth.status_code = cpu_to_le16(0); | 125 | own_rate = 5 * (rate & 0x7f); |
128 | if (extra) | 126 | for (j = 0; j < num_rates; j++) |
129 | memcpy(skb_put(skb, extra_len), extra, extra_len); | 127 | if (bitrates[j].bitrate == own_rate) |
130 | 128 | supp_rates |= BIT(j); | |
131 | ieee80211_tx_skb(sdata, skb, encrypt); | 129 | } |
130 | return supp_rates; | ||
132 | } | 131 | } |
133 | 132 | ||
133 | /* frame sending functions */ | ||
134 | |||
135 | /* also used by scanning code */ | ||
134 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 136 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, |
135 | u8 *ssid, size_t ssid_len) | 137 | u8 *ssid, size_t ssid_len) |
136 | { | 138 | { |
@@ -191,6 +193,43 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | |||
191 | ieee80211_tx_skb(sdata, skb, 0); | 193 | ieee80211_tx_skb(sdata, skb, 0); |
192 | } | 194 | } |
193 | 195 | ||
196 | static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
197 | struct ieee80211_if_sta *ifsta, | ||
198 | int transaction, u8 *extra, size_t extra_len, | ||
199 | int encrypt) | ||
200 | { | ||
201 | struct ieee80211_local *local = sdata->local; | ||
202 | struct sk_buff *skb; | ||
203 | struct ieee80211_mgmt *mgmt; | ||
204 | |||
205 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
206 | sizeof(*mgmt) + 6 + extra_len); | ||
207 | if (!skb) { | ||
208 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
209 | "frame\n", sdata->dev->name); | ||
210 | return; | ||
211 | } | ||
212 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
213 | |||
214 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
215 | memset(mgmt, 0, 24 + 6); | ||
216 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
217 | IEEE80211_STYPE_AUTH); | ||
218 | if (encrypt) | ||
219 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
220 | memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); | ||
221 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
222 | memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); | ||
223 | mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); | ||
224 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
225 | ifsta->auth_transaction = transaction + 1; | ||
226 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
227 | if (extra) | ||
228 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
229 | |||
230 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
231 | } | ||
232 | |||
194 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, | 233 | static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, |
195 | struct ieee80211_if_sta *ifsta) | 234 | struct ieee80211_if_sta *ifsta) |
196 | { | 235 | { |
@@ -1414,42 +1453,6 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | |||
1414 | return res; | 1453 | return res; |
1415 | } | 1454 | } |
1416 | 1455 | ||
1417 | u64 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
1418 | struct ieee802_11_elems *elems, | ||
1419 | enum ieee80211_band band) | ||
1420 | { | ||
1421 | struct ieee80211_supported_band *sband; | ||
1422 | struct ieee80211_rate *bitrates; | ||
1423 | size_t num_rates; | ||
1424 | u64 supp_rates; | ||
1425 | int i, j; | ||
1426 | sband = local->hw.wiphy->bands[band]; | ||
1427 | |||
1428 | if (!sband) { | ||
1429 | WARN_ON(1); | ||
1430 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
1431 | } | ||
1432 | |||
1433 | bitrates = sband->bitrates; | ||
1434 | num_rates = sband->n_bitrates; | ||
1435 | supp_rates = 0; | ||
1436 | for (i = 0; i < elems->supp_rates_len + | ||
1437 | elems->ext_supp_rates_len; i++) { | ||
1438 | u8 rate = 0; | ||
1439 | int own_rate; | ||
1440 | if (i < elems->supp_rates_len) | ||
1441 | rate = elems->supp_rates[i]; | ||
1442 | else if (elems->ext_supp_rates) | ||
1443 | rate = elems->ext_supp_rates | ||
1444 | [i - elems->supp_rates_len]; | ||
1445 | own_rate = 5 * (rate & 0x7f); | ||
1446 | for (j = 0; j < num_rates; j++) | ||
1447 | if (bitrates[j].bitrate == own_rate) | ||
1448 | supp_rates |= BIT(j); | ||
1449 | } | ||
1450 | return supp_rates; | ||
1451 | } | ||
1452 | |||
1453 | static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local, | 1456 | static u64 ieee80211_sta_get_mandatory_rates(struct ieee80211_local *local, |
1454 | enum ieee80211_band band) | 1457 | enum ieee80211_band band) |
1455 | { | 1458 | { |
@@ -1894,7 +1897,7 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata, | |||
1894 | } | 1897 | } |
1895 | 1898 | ||
1896 | 1899 | ||
1897 | void ieee80211_sta_timer(unsigned long data) | 1900 | static void ieee80211_sta_timer(unsigned long data) |
1898 | { | 1901 | { |
1899 | struct ieee80211_sub_if_data *sdata = | 1902 | struct ieee80211_sub_if_data *sdata = |
1900 | (struct ieee80211_sub_if_data *) data; | 1903 | (struct ieee80211_sub_if_data *) data; |
@@ -1937,28 +1940,6 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata, | |||
1937 | } | 1940 | } |
1938 | 1941 | ||
1939 | 1942 | ||
1940 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | ||
1941 | struct ieee80211_if_sta *ifsta) | ||
1942 | { | ||
1943 | struct ieee80211_local *local = sdata->local; | ||
1944 | |||
1945 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
1946 | return; | ||
1947 | |||
1948 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | ||
1949 | IEEE80211_STA_AUTO_BSSID_SEL)) && | ||
1950 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | ||
1951 | IEEE80211_STA_AUTO_SSID_SEL))) { | ||
1952 | |||
1953 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | ||
1954 | ieee80211_set_disassoc(sdata, ifsta, true, true, | ||
1955 | WLAN_REASON_DEAUTH_LEAVING); | ||
1956 | |||
1957 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
1958 | queue_work(local->hw.workqueue, &ifsta->work); | ||
1959 | } | ||
1960 | } | ||
1961 | |||
1962 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, | 1943 | static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, |
1963 | const char *ssid, int ssid_len) | 1944 | const char *ssid, int ssid_len) |
1964 | { | 1945 | { |
@@ -2160,159 +2141,6 @@ dont_join: | |||
2160 | } | 2141 | } |
2161 | 2142 | ||
2162 | 2143 | ||
2163 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | ||
2164 | { | ||
2165 | struct ieee80211_if_sta *ifsta; | ||
2166 | int res; | ||
2167 | |||
2168 | if (len > IEEE80211_MAX_SSID_LEN) | ||
2169 | return -EINVAL; | ||
2170 | |||
2171 | ifsta = &sdata->u.sta; | ||
2172 | |||
2173 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | ||
2174 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | ||
2175 | memcpy(ifsta->ssid, ssid, len); | ||
2176 | ifsta->ssid_len = len; | ||
2177 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
2178 | |||
2179 | res = 0; | ||
2180 | /* | ||
2181 | * Hack! MLME code needs to be cleaned up to have different | ||
2182 | * entry points for configuration and internal selection change | ||
2183 | */ | ||
2184 | if (netif_running(sdata->dev)) | ||
2185 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); | ||
2186 | if (res) { | ||
2187 | printk(KERN_DEBUG "%s: Failed to config new SSID to " | ||
2188 | "the low-level driver\n", sdata->dev->name); | ||
2189 | return res; | ||
2190 | } | ||
2191 | } | ||
2192 | |||
2193 | if (len) | ||
2194 | ifsta->flags |= IEEE80211_STA_SSID_SET; | ||
2195 | else | ||
2196 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | ||
2197 | |||
2198 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && | ||
2199 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { | ||
2200 | ifsta->ibss_join_req = jiffies; | ||
2201 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | ||
2202 | return ieee80211_sta_find_ibss(sdata, ifsta); | ||
2203 | } | ||
2204 | |||
2205 | return 0; | ||
2206 | } | ||
2207 | |||
2208 | |||
2209 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | ||
2210 | { | ||
2211 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2212 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | ||
2213 | *len = ifsta->ssid_len; | ||
2214 | return 0; | ||
2215 | } | ||
2216 | |||
2217 | |||
2218 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | ||
2219 | { | ||
2220 | struct ieee80211_if_sta *ifsta; | ||
2221 | int res; | ||
2222 | |||
2223 | ifsta = &sdata->u.sta; | ||
2224 | |||
2225 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | ||
2226 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | ||
2227 | res = 0; | ||
2228 | /* | ||
2229 | * Hack! See also ieee80211_sta_set_ssid. | ||
2230 | */ | ||
2231 | if (netif_running(sdata->dev)) | ||
2232 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
2233 | if (res) { | ||
2234 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
2235 | "the low-level driver\n", sdata->dev->name); | ||
2236 | return res; | ||
2237 | } | ||
2238 | } | ||
2239 | |||
2240 | if (is_valid_ether_addr(bssid)) | ||
2241 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | ||
2242 | else | ||
2243 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | ||
2244 | |||
2245 | return 0; | ||
2246 | } | ||
2247 | |||
2248 | |||
2249 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | ||
2250 | { | ||
2251 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2252 | |||
2253 | kfree(ifsta->extra_ie); | ||
2254 | if (len == 0) { | ||
2255 | ifsta->extra_ie = NULL; | ||
2256 | ifsta->extra_ie_len = 0; | ||
2257 | return 0; | ||
2258 | } | ||
2259 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | ||
2260 | if (!ifsta->extra_ie) { | ||
2261 | ifsta->extra_ie_len = 0; | ||
2262 | return -ENOMEM; | ||
2263 | } | ||
2264 | memcpy(ifsta->extra_ie, ie, len); | ||
2265 | ifsta->extra_ie_len = len; | ||
2266 | return 0; | ||
2267 | } | ||
2268 | |||
2269 | |||
2270 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
2271 | struct sk_buff *skb, u8 *bssid, | ||
2272 | u8 *addr, u64 supp_rates) | ||
2273 | { | ||
2274 | struct ieee80211_local *local = sdata->local; | ||
2275 | struct sta_info *sta; | ||
2276 | DECLARE_MAC_BUF(mac); | ||
2277 | int band = local->hw.conf.channel->band; | ||
2278 | |||
2279 | /* TODO: Could consider removing the least recently used entry and | ||
2280 | * allow new one to be added. */ | ||
2281 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
2282 | if (net_ratelimit()) { | ||
2283 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
2284 | "entry %s\n", sdata->dev->name, print_mac(mac, addr)); | ||
2285 | } | ||
2286 | return NULL; | ||
2287 | } | ||
2288 | |||
2289 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | ||
2290 | return NULL; | ||
2291 | |||
2292 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2293 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", | ||
2294 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name); | ||
2295 | #endif | ||
2296 | |||
2297 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
2298 | if (!sta) | ||
2299 | return NULL; | ||
2300 | |||
2301 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
2302 | |||
2303 | /* make sure mandatory rates are always added */ | ||
2304 | sta->supp_rates[band] = supp_rates | | ||
2305 | ieee80211_sta_get_mandatory_rates(local, band); | ||
2306 | |||
2307 | rate_control_rate_init(sta, local); | ||
2308 | |||
2309 | if (sta_info_insert(sta)) | ||
2310 | return NULL; | ||
2311 | |||
2312 | return sta; | ||
2313 | } | ||
2314 | |||
2315 | |||
2316 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | 2144 | static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, |
2317 | struct ieee80211_if_sta *ifsta) | 2145 | struct ieee80211_if_sta *ifsta) |
2318 | { | 2146 | { |
@@ -2392,61 +2220,7 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata, | |||
2392 | } | 2220 | } |
2393 | 2221 | ||
2394 | 2222 | ||
2395 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | 2223 | static void ieee80211_sta_work(struct work_struct *work) |
2396 | { | ||
2397 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2398 | |||
2399 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | ||
2400 | sdata->dev->name, reason); | ||
2401 | |||
2402 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
2403 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) | ||
2404 | return -EINVAL; | ||
2405 | |||
2406 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | ||
2407 | return 0; | ||
2408 | } | ||
2409 | |||
2410 | |||
2411 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | ||
2412 | { | ||
2413 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2414 | |||
2415 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | ||
2416 | sdata->dev->name, reason); | ||
2417 | |||
2418 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
2419 | return -EINVAL; | ||
2420 | |||
2421 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | ||
2422 | return -1; | ||
2423 | |||
2424 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | ||
2425 | return 0; | ||
2426 | } | ||
2427 | |||
2428 | void ieee80211_notify_mac(struct ieee80211_hw *hw, | ||
2429 | enum ieee80211_notification_types notif_type) | ||
2430 | { | ||
2431 | struct ieee80211_local *local = hw_to_local(hw); | ||
2432 | struct ieee80211_sub_if_data *sdata; | ||
2433 | |||
2434 | switch (notif_type) { | ||
2435 | case IEEE80211_NOTIFY_RE_ASSOC: | ||
2436 | rcu_read_lock(); | ||
2437 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
2438 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
2439 | continue; | ||
2440 | |||
2441 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | ||
2442 | } | ||
2443 | rcu_read_unlock(); | ||
2444 | break; | ||
2445 | } | ||
2446 | } | ||
2447 | EXPORT_SYMBOL(ieee80211_notify_mac); | ||
2448 | |||
2449 | void ieee80211_sta_work(struct work_struct *work) | ||
2450 | { | 2224 | { |
2451 | struct ieee80211_sub_if_data *sdata = | 2225 | struct ieee80211_sub_if_data *sdata = |
2452 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); | 2226 | container_of(work, struct ieee80211_sub_if_data, u.sta.work); |
@@ -2525,6 +2299,236 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) | |||
2525 | &sdata->u.sta.work); | 2299 | &sdata->u.sta.work); |
2526 | } | 2300 | } |
2527 | 2301 | ||
2302 | /* interface setup */ | ||
2303 | void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) | ||
2304 | { | ||
2305 | struct ieee80211_if_sta *ifsta; | ||
2306 | |||
2307 | ifsta = &sdata->u.sta; | ||
2308 | INIT_WORK(&ifsta->work, ieee80211_sta_work); | ||
2309 | setup_timer(&ifsta->timer, ieee80211_sta_timer, | ||
2310 | (unsigned long) sdata); | ||
2311 | skb_queue_head_init(&ifsta->skb_queue); | ||
2312 | |||
2313 | ifsta->capab = WLAN_CAPABILITY_ESS; | ||
2314 | ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | | ||
2315 | IEEE80211_AUTH_ALG_SHARED_KEY; | ||
2316 | ifsta->flags |= IEEE80211_STA_CREATE_IBSS | | ||
2317 | IEEE80211_STA_AUTO_BSSID_SEL | | ||
2318 | IEEE80211_STA_AUTO_CHANNEL_SEL; | ||
2319 | if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4) | ||
2320 | ifsta->flags |= IEEE80211_STA_WMM_ENABLED; | ||
2321 | } | ||
2322 | |||
2323 | /* | ||
2324 | * Add a new IBSS station, will also be called by the RX code when, | ||
2325 | * in IBSS mode, receiving a frame from a yet-unknown station, hence | ||
2326 | * must be callable in atomic context. | ||
2327 | */ | ||
2328 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||
2329 | struct sk_buff *skb, u8 *bssid, | ||
2330 | u8 *addr, u64 supp_rates) | ||
2331 | { | ||
2332 | struct ieee80211_local *local = sdata->local; | ||
2333 | struct sta_info *sta; | ||
2334 | DECLARE_MAC_BUF(mac); | ||
2335 | int band = local->hw.conf.channel->band; | ||
2336 | |||
2337 | /* TODO: Could consider removing the least recently used entry and | ||
2338 | * allow new one to be added. */ | ||
2339 | if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { | ||
2340 | if (net_ratelimit()) { | ||
2341 | printk(KERN_DEBUG "%s: No room for a new IBSS STA " | ||
2342 | "entry %s\n", sdata->dev->name, print_mac(mac, addr)); | ||
2343 | } | ||
2344 | return NULL; | ||
2345 | } | ||
2346 | |||
2347 | if (compare_ether_addr(bssid, sdata->u.sta.bssid)) | ||
2348 | return NULL; | ||
2349 | |||
2350 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
2351 | printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", | ||
2352 | wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name); | ||
2353 | #endif | ||
2354 | |||
2355 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | ||
2356 | if (!sta) | ||
2357 | return NULL; | ||
2358 | |||
2359 | set_sta_flags(sta, WLAN_STA_AUTHORIZED); | ||
2360 | |||
2361 | /* make sure mandatory rates are always added */ | ||
2362 | sta->supp_rates[band] = supp_rates | | ||
2363 | ieee80211_sta_get_mandatory_rates(local, band); | ||
2364 | |||
2365 | rate_control_rate_init(sta, local); | ||
2366 | |||
2367 | if (sta_info_insert(sta)) | ||
2368 | return NULL; | ||
2369 | |||
2370 | return sta; | ||
2371 | } | ||
2372 | |||
2373 | /* configuration hooks */ | ||
2374 | void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, | ||
2375 | struct ieee80211_if_sta *ifsta) | ||
2376 | { | ||
2377 | struct ieee80211_local *local = sdata->local; | ||
2378 | |||
2379 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
2380 | return; | ||
2381 | |||
2382 | if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | | ||
2383 | IEEE80211_STA_AUTO_BSSID_SEL)) && | ||
2384 | (ifsta->flags & (IEEE80211_STA_SSID_SET | | ||
2385 | IEEE80211_STA_AUTO_SSID_SEL))) { | ||
2386 | |||
2387 | if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) | ||
2388 | ieee80211_set_disassoc(sdata, ifsta, true, true, | ||
2389 | WLAN_REASON_DEAUTH_LEAVING); | ||
2390 | |||
2391 | set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); | ||
2392 | queue_work(local->hw.workqueue, &ifsta->work); | ||
2393 | } | ||
2394 | } | ||
2395 | |||
2396 | int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) | ||
2397 | { | ||
2398 | struct ieee80211_if_sta *ifsta; | ||
2399 | int res; | ||
2400 | |||
2401 | if (len > IEEE80211_MAX_SSID_LEN) | ||
2402 | return -EINVAL; | ||
2403 | |||
2404 | ifsta = &sdata->u.sta; | ||
2405 | |||
2406 | if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) { | ||
2407 | memset(ifsta->ssid, 0, sizeof(ifsta->ssid)); | ||
2408 | memcpy(ifsta->ssid, ssid, len); | ||
2409 | ifsta->ssid_len = len; | ||
2410 | ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; | ||
2411 | |||
2412 | res = 0; | ||
2413 | /* | ||
2414 | * Hack! MLME code needs to be cleaned up to have different | ||
2415 | * entry points for configuration and internal selection change | ||
2416 | */ | ||
2417 | if (netif_running(sdata->dev)) | ||
2418 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); | ||
2419 | if (res) { | ||
2420 | printk(KERN_DEBUG "%s: Failed to config new SSID to " | ||
2421 | "the low-level driver\n", sdata->dev->name); | ||
2422 | return res; | ||
2423 | } | ||
2424 | } | ||
2425 | |||
2426 | if (len) | ||
2427 | ifsta->flags |= IEEE80211_STA_SSID_SET; | ||
2428 | else | ||
2429 | ifsta->flags &= ~IEEE80211_STA_SSID_SET; | ||
2430 | |||
2431 | if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && | ||
2432 | !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { | ||
2433 | ifsta->ibss_join_req = jiffies; | ||
2434 | ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH; | ||
2435 | return ieee80211_sta_find_ibss(sdata, ifsta); | ||
2436 | } | ||
2437 | |||
2438 | return 0; | ||
2439 | } | ||
2440 | |||
2441 | int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len) | ||
2442 | { | ||
2443 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2444 | memcpy(ssid, ifsta->ssid, ifsta->ssid_len); | ||
2445 | *len = ifsta->ssid_len; | ||
2446 | return 0; | ||
2447 | } | ||
2448 | |||
2449 | int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid) | ||
2450 | { | ||
2451 | struct ieee80211_if_sta *ifsta; | ||
2452 | int res; | ||
2453 | |||
2454 | ifsta = &sdata->u.sta; | ||
2455 | |||
2456 | if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { | ||
2457 | memcpy(ifsta->bssid, bssid, ETH_ALEN); | ||
2458 | res = 0; | ||
2459 | /* | ||
2460 | * Hack! See also ieee80211_sta_set_ssid. | ||
2461 | */ | ||
2462 | if (netif_running(sdata->dev)) | ||
2463 | res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID); | ||
2464 | if (res) { | ||
2465 | printk(KERN_DEBUG "%s: Failed to config new BSSID to " | ||
2466 | "the low-level driver\n", sdata->dev->name); | ||
2467 | return res; | ||
2468 | } | ||
2469 | } | ||
2470 | |||
2471 | if (is_valid_ether_addr(bssid)) | ||
2472 | ifsta->flags |= IEEE80211_STA_BSSID_SET; | ||
2473 | else | ||
2474 | ifsta->flags &= ~IEEE80211_STA_BSSID_SET; | ||
2475 | |||
2476 | return 0; | ||
2477 | } | ||
2478 | |||
2479 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | ||
2480 | { | ||
2481 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2482 | |||
2483 | kfree(ifsta->extra_ie); | ||
2484 | if (len == 0) { | ||
2485 | ifsta->extra_ie = NULL; | ||
2486 | ifsta->extra_ie_len = 0; | ||
2487 | return 0; | ||
2488 | } | ||
2489 | ifsta->extra_ie = kmalloc(len, GFP_KERNEL); | ||
2490 | if (!ifsta->extra_ie) { | ||
2491 | ifsta->extra_ie_len = 0; | ||
2492 | return -ENOMEM; | ||
2493 | } | ||
2494 | memcpy(ifsta->extra_ie, ie, len); | ||
2495 | ifsta->extra_ie_len = len; | ||
2496 | return 0; | ||
2497 | } | ||
2498 | |||
2499 | int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason) | ||
2500 | { | ||
2501 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2502 | |||
2503 | printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", | ||
2504 | sdata->dev->name, reason); | ||
2505 | |||
2506 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA && | ||
2507 | sdata->vif.type != IEEE80211_IF_TYPE_IBSS) | ||
2508 | return -EINVAL; | ||
2509 | |||
2510 | ieee80211_set_disassoc(sdata, ifsta, true, true, reason); | ||
2511 | return 0; | ||
2512 | } | ||
2513 | |||
2514 | int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason) | ||
2515 | { | ||
2516 | struct ieee80211_if_sta *ifsta = &sdata->u.sta; | ||
2517 | |||
2518 | printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", | ||
2519 | sdata->dev->name, reason); | ||
2520 | |||
2521 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
2522 | return -EINVAL; | ||
2523 | |||
2524 | if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) | ||
2525 | return -1; | ||
2526 | |||
2527 | ieee80211_set_disassoc(sdata, ifsta, false, true, reason); | ||
2528 | return 0; | ||
2529 | } | ||
2530 | |||
2531 | /* scan finished notification */ | ||
2528 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | 2532 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) |
2529 | { | 2533 | { |
2530 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | 2534 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; |
@@ -2544,3 +2548,25 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) | |||
2544 | ieee80211_restart_sta_timer(sdata); | 2548 | ieee80211_restart_sta_timer(sdata); |
2545 | rcu_read_unlock(); | 2549 | rcu_read_unlock(); |
2546 | } | 2550 | } |
2551 | |||
2552 | /* driver notification call */ | ||
2553 | void ieee80211_notify_mac(struct ieee80211_hw *hw, | ||
2554 | enum ieee80211_notification_types notif_type) | ||
2555 | { | ||
2556 | struct ieee80211_local *local = hw_to_local(hw); | ||
2557 | struct ieee80211_sub_if_data *sdata; | ||
2558 | |||
2559 | switch (notif_type) { | ||
2560 | case IEEE80211_NOTIFY_RE_ASSOC: | ||
2561 | rcu_read_lock(); | ||
2562 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||
2563 | if (sdata->vif.type != IEEE80211_IF_TYPE_STA) | ||
2564 | continue; | ||
2565 | |||
2566 | ieee80211_sta_req_auth(sdata, &sdata->u.sta); | ||
2567 | } | ||
2568 | rcu_read_unlock(); | ||
2569 | break; | ||
2570 | } | ||
2571 | } | ||
2572 | EXPORT_SYMBOL(ieee80211_notify_mac); | ||