diff options
Diffstat (limited to 'net/ieee80211/softmac/ieee80211softmac_assoc.c')
-rw-r--r-- | net/ieee80211/softmac/ieee80211softmac_assoc.c | 96 |
1 files changed, 58 insertions, 38 deletions
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c index 57ea9f6f465c..5e9a90651d04 100644 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c | |||
@@ -82,51 +82,52 @@ ieee80211softmac_assoc_timeout(void *d) | |||
82 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL); | 82 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL); |
83 | } | 83 | } |
84 | 84 | ||
85 | /* Sends out a disassociation request to the desired AP */ | 85 | void |
86 | static void | 86 | ieee80211softmac_disassoc(struct ieee80211softmac_device *mac) |
87 | ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason) | ||
88 | { | 87 | { |
89 | unsigned long flags; | 88 | unsigned long flags; |
89 | |||
90 | spin_lock_irqsave(&mac->lock, flags); | ||
91 | if (mac->associnfo.associating) | ||
92 | cancel_delayed_work(&mac->associnfo.timeout); | ||
93 | |||
94 | netif_carrier_off(mac->dev); | ||
95 | |||
96 | mac->associated = 0; | ||
97 | mac->associnfo.bssvalid = 0; | ||
98 | mac->associnfo.associating = 0; | ||
99 | ieee80211softmac_init_txrates(mac); | ||
100 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
101 | spin_unlock_irqrestore(&mac->lock, flags); | ||
102 | } | ||
103 | |||
104 | /* Sends out a disassociation request to the desired AP */ | ||
105 | void | ||
106 | ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason) | ||
107 | { | ||
90 | struct ieee80211softmac_network *found; | 108 | struct ieee80211softmac_network *found; |
91 | 109 | ||
92 | if (mac->associnfo.bssvalid && mac->associated) { | 110 | if (mac->associnfo.bssvalid && mac->associated) { |
93 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | 111 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); |
94 | if (found) | 112 | if (found) |
95 | ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); | 113 | ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); |
96 | } else if (mac->associnfo.associating) { | ||
97 | cancel_delayed_work(&mac->associnfo.timeout); | ||
98 | } | 114 | } |
99 | 115 | ||
100 | /* Change our state */ | 116 | ieee80211softmac_disassoc(mac); |
101 | spin_lock_irqsave(&mac->lock, flags); | ||
102 | /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */ | ||
103 | mac->associated = 0; | ||
104 | mac->associnfo.associating = 0; | ||
105 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
106 | spin_unlock_irqrestore(&mac->lock, flags); | ||
107 | } | 117 | } |
108 | 118 | ||
109 | static inline int | 119 | static inline int |
110 | we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) | 120 | we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) |
111 | { | 121 | { |
112 | int idx, search, found; | 122 | int idx; |
113 | u8 rate, search_rate; | 123 | u8 rate; |
114 | 124 | ||
115 | for (idx = 0; idx < (from_len); idx++) { | 125 | for (idx = 0; idx < (from_len); idx++) { |
116 | rate = (from)[idx]; | 126 | rate = (from)[idx]; |
117 | if (!(rate & IEEE80211_BASIC_RATE_MASK)) | 127 | if (!(rate & IEEE80211_BASIC_RATE_MASK)) |
118 | continue; | 128 | continue; |
119 | found = 0; | ||
120 | rate &= ~IEEE80211_BASIC_RATE_MASK; | 129 | rate &= ~IEEE80211_BASIC_RATE_MASK; |
121 | for (search = 0; search < mac->ratesinfo.count; search++) { | 130 | if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) |
122 | search_rate = mac->ratesinfo.rates[search]; | ||
123 | search_rate &= ~IEEE80211_BASIC_RATE_MASK; | ||
124 | if (rate == search_rate) { | ||
125 | found = 1; | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | if (!found) | ||
130 | return 0; | 131 | return 0; |
131 | } | 132 | } |
132 | return 1; | 133 | return 1; |
@@ -163,12 +164,28 @@ network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_ne | |||
163 | } | 164 | } |
164 | 165 | ||
165 | static void | 166 | static void |
166 | ieee80211softmac_assoc_notify(struct net_device *dev, void *context) | 167 | ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context) |
167 | { | 168 | { |
168 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | 169 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); |
169 | ieee80211softmac_assoc_work((void*)mac); | 170 | ieee80211softmac_assoc_work((void*)mac); |
170 | } | 171 | } |
171 | 172 | ||
173 | static void | ||
174 | ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context) | ||
175 | { | ||
176 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | ||
177 | |||
178 | switch (event_type) { | ||
179 | case IEEE80211SOFTMAC_EVENT_AUTHENTICATED: | ||
180 | ieee80211softmac_assoc_work((void*)mac); | ||
181 | break; | ||
182 | case IEEE80211SOFTMAC_EVENT_AUTH_FAILED: | ||
183 | case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT: | ||
184 | ieee80211softmac_disassoc(mac); | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | |||
172 | /* This function is called to handle userspace requests (asynchronously) */ | 189 | /* This function is called to handle userspace requests (asynchronously) */ |
173 | void | 190 | void |
174 | ieee80211softmac_assoc_work(void *d) | 191 | ieee80211softmac_assoc_work(void *d) |
@@ -176,14 +193,18 @@ ieee80211softmac_assoc_work(void *d) | |||
176 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; | 193 | struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d; |
177 | struct ieee80211softmac_network *found = NULL; | 194 | struct ieee80211softmac_network *found = NULL; |
178 | struct ieee80211_network *net = NULL, *best = NULL; | 195 | struct ieee80211_network *net = NULL, *best = NULL; |
196 | int bssvalid; | ||
179 | unsigned long flags; | 197 | unsigned long flags; |
180 | 198 | ||
199 | /* ieee80211_disassoc might clear this */ | ||
200 | bssvalid = mac->associnfo.bssvalid; | ||
201 | |||
181 | /* meh */ | 202 | /* meh */ |
182 | if (mac->associated) | 203 | if (mac->associated) |
183 | ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); | 204 | ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); |
184 | 205 | ||
185 | /* try to find the requested network in our list, if we found one already */ | 206 | /* try to find the requested network in our list, if we found one already */ |
186 | if (mac->associnfo.bssvalid || mac->associnfo.bssfixed) | 207 | if (bssvalid || mac->associnfo.bssfixed) |
187 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); | 208 | found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); |
188 | 209 | ||
189 | /* Search the ieee80211 networks for this network if we didn't find it by bssid, | 210 | /* Search the ieee80211 networks for this network if we didn't find it by bssid, |
@@ -244,7 +265,7 @@ ieee80211softmac_assoc_work(void *d) | |||
244 | * Maybe we can hope to have more memory after scanning finishes ;) | 265 | * Maybe we can hope to have more memory after scanning finishes ;) |
245 | */ | 266 | */ |
246 | dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); | 267 | dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); |
247 | ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL); | 268 | ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL); |
248 | if (ieee80211softmac_start_scan(mac)) | 269 | if (ieee80211softmac_start_scan(mac)) |
249 | dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); | 270 | dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); |
250 | return; | 271 | return; |
@@ -279,7 +300,7 @@ ieee80211softmac_assoc_work(void *d) | |||
279 | * otherwise adding the notification would be racy. */ | 300 | * otherwise adding the notification would be racy. */ |
280 | if (!ieee80211softmac_auth_req(mac, found)) { | 301 | if (!ieee80211softmac_auth_req(mac, found)) { |
281 | dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); | 302 | dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); |
282 | ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL); | 303 | ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); |
283 | } else { | 304 | } else { |
284 | printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); | 305 | printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); |
285 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); | 306 | ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); |
@@ -297,6 +318,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac, | |||
297 | struct ieee80211softmac_network *net) | 318 | struct ieee80211softmac_network *net) |
298 | { | 319 | { |
299 | mac->associnfo.associating = 0; | 320 | mac->associnfo.associating = 0; |
321 | mac->associnfo.supported_rates = net->supported_rates; | ||
322 | ieee80211softmac_recalc_txrates(mac); | ||
323 | |||
300 | mac->associated = 1; | 324 | mac->associated = 1; |
301 | if (mac->set_bssid_filter) | 325 | if (mac->set_bssid_filter) |
302 | mac->set_bssid_filter(mac->dev, net->bssid); | 326 | mac->set_bssid_filter(mac->dev, net->bssid); |
@@ -380,7 +404,6 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
380 | struct ieee80211_disassoc *disassoc) | 404 | struct ieee80211_disassoc *disassoc) |
381 | { | 405 | { |
382 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); | 406 | struct ieee80211softmac_device *mac = ieee80211_priv(dev); |
383 | unsigned long flags; | ||
384 | 407 | ||
385 | if (unlikely(!mac->running)) | 408 | if (unlikely(!mac->running)) |
386 | return -ENODEV; | 409 | return -ENODEV; |
@@ -392,14 +415,11 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, | |||
392 | return 0; | 415 | return 0; |
393 | 416 | ||
394 | dprintk(KERN_INFO PFX "got disassoc frame\n"); | 417 | dprintk(KERN_INFO PFX "got disassoc frame\n"); |
395 | netif_carrier_off(dev); | 418 | ieee80211softmac_disassoc(mac); |
396 | spin_lock_irqsave(&mac->lock, flags); | 419 | |
397 | mac->associnfo.bssvalid = 0; | 420 | /* try to reassociate */ |
398 | mac->associated = 0; | ||
399 | ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); | ||
400 | schedule_work(&mac->associnfo.work); | 421 | schedule_work(&mac->associnfo.work); |
401 | spin_unlock_irqrestore(&mac->lock, flags); | 422 | |
402 | |||
403 | return 0; | 423 | return 0; |
404 | } | 424 | } |
405 | 425 | ||