diff options
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); | ||