]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - net/ieee80211/softmac/ieee80211softmac_auth.c
[PATCH] softmac: convert to use global workqueue
[linux-2.6.git] / net / ieee80211 / softmac / ieee80211softmac_auth.c
1 #include "ieee80211softmac_priv.h"
2
3 static void ieee80211softmac_auth_queue(void *data);
4
5 /* Queues an auth request to the desired AP */
6 int
7 ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, 
8         struct ieee80211softmac_network *net)
9 {
10         struct ieee80211softmac_auth_queue_item *auth;
11         unsigned long flags;
12         
13         function_enter();
14         
15         if (net->authenticating)
16                 return 0;
17
18         /* Add the network if it's not already added */
19         ieee80211softmac_add_network(mac, net);
20
21         dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
22         /* Queue the auth request */
23         auth = (struct ieee80211softmac_auth_queue_item *)
24                 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
25         if(auth == NULL)
26                 return -ENOMEM;
27
28         auth->net = net;
29         auth->mac = mac;
30         auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
31         auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
32         INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
33         
34         /* Lock (for list) */
35         spin_lock_irqsave(&mac->lock, flags);
36
37         /* add to list */
38         list_add_tail(&auth->list, &mac->auth_queue);
39         schedule_work(&auth->work);
40         spin_unlock_irqrestore(&mac->lock, flags);
41         
42         return 0;
43 }
44
45
46 /* Sends an auth request to the desired AP and handles timeouts */
47 static void
48 ieee80211softmac_auth_queue(void *data)
49 {
50         struct ieee80211softmac_device *mac;
51         struct ieee80211softmac_auth_queue_item *auth;
52         struct ieee80211softmac_network *net;
53         unsigned long flags;
54
55         function_enter();
56         
57         auth = (struct ieee80211softmac_auth_queue_item *)data;
58         net = auth->net;
59         mac = auth->mac;
60
61         if(auth->retry > 0) {
62                 /* Switch to correct channel for this network */
63                 mac->set_channel(mac->dev, net->channel);
64                 
65                 /* Lock and set flags */
66                 spin_lock_irqsave(&mac->lock, flags);
67                 net->authenticated = 0;
68                 net->authenticating = 1;
69                 /* add a timeout call so we eventually give up waiting for an auth reply */
70                 schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
71                 auth->retry--;
72                 spin_unlock_irqrestore(&mac->lock, flags);
73                 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
74                         dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
75                 else
76                         dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
77                 return;
78         }
79
80         printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
81         /* Remove this item from the queue */
82         spin_lock_irqsave(&mac->lock, flags);
83         ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
84         cancel_delayed_work(&auth->work); /* just to make sure... */
85         list_del(&auth->list);
86         spin_unlock_irqrestore(&mac->lock, flags);
87         /* Free it */
88         kfree(auth);
89 }
90
91 /* Handle the auth response from the AP
92  * This should be registered with ieee80211 as handle_auth 
93  */
94 int 
95 ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
96 {       
97
98         struct list_head *list_ptr;
99         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
100         struct ieee80211softmac_auth_queue_item *aq = NULL;
101         struct ieee80211softmac_network *net = NULL;
102         unsigned long flags;
103         u8 * data;
104         
105         function_enter();
106         
107         /* Find correct auth queue item */
108         spin_lock_irqsave(&mac->lock, flags);
109         list_for_each(list_ptr, &mac->auth_queue) {
110                 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
111                 net = aq->net;
112                 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
113                         break;
114                 else
115                         aq = NULL;
116         }
117         spin_unlock_irqrestore(&mac->lock, flags);
118         
119         /* Make sure that we've got an auth queue item for this request */
120         if(aq == NULL)
121         {
122                 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
123                 /* Error #? */
124                 return -1;
125         }                       
126         
127         /* Check for out of order authentication */
128         if(!net->authenticating)
129         {
130                 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
131                 return -1;
132         }
133
134         /* Parse the auth packet */
135         switch(auth->algorithm) {
136         case WLAN_AUTH_OPEN:
137                 /* Check the status code of the response */
138
139                 switch(auth->status) {
140                 case WLAN_STATUS_SUCCESS:
141                         /* Update the status to Authenticated */
142                         spin_lock_irqsave(&mac->lock, flags);
143                         net->authenticating = 0;
144                         net->authenticated = 1;
145                         spin_unlock_irqrestore(&mac->lock, flags);
146                         
147                         /* Send event */
148                         printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
149                         ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
150                         break;
151                 default:
152                         /* Lock and reset flags */
153                         spin_lock_irqsave(&mac->lock, flags);
154                         net->authenticated = 0;
155                         net->authenticating = 0;
156                         spin_unlock_irqrestore(&mac->lock, flags);
157                         
158                         printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n", 
159                                 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
160                         /* Count the error? */
161                         break;
162                 }
163                 goto free_aq;
164                 break;
165         case WLAN_AUTH_SHARED_KEY:
166                 /* Figure out where we are in the process */
167                 switch(auth->transaction) {
168                 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
169                         /* Check to make sure we have a challenge IE */
170                         data = (u8 *)auth->info_element;
171                         if(*data++ != MFIE_TYPE_CHALLENGE){
172                                 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
173                                 break;  
174                         }
175                         /* Save the challenge */
176                         spin_lock_irqsave(&mac->lock, flags);
177                         net->challenge_len = *data++;   
178                         if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
179                                 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
180                         if(net->challenge != NULL)
181                                 kfree(net->challenge);
182                         net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
183                         memcpy(net->challenge, data, net->challenge_len);
184                         aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; 
185                         spin_unlock_irqrestore(&mac->lock, flags);
186
187                         /* Switch to correct channel for this network */
188                         mac->set_channel(mac->dev, net->channel);
189                         
190                         /* Send our response (How to encrypt?) */
191                         ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
192                         break;
193                 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
194                         /* Check the status code of the response */
195                         switch(auth->status) {
196                         case WLAN_STATUS_SUCCESS:
197                                 /* Update the status to Authenticated */        
198                                 spin_lock_irqsave(&mac->lock, flags);
199                                 net->authenticating = 0;
200                                 net->authenticated = 1;
201                                 spin_unlock_irqrestore(&mac->lock, flags);
202                                 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", 
203                                         MAC_ARG(net->bssid));
204                                 break;
205                         default:
206                                 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", 
207                                         MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
208                                 /* Lock and reset flags */
209                                 spin_lock_irqsave(&mac->lock, flags);
210                                 net->authenticating = 0;
211                                 net->authenticated = 0;
212                                 spin_unlock_irqrestore(&mac->lock, flags);
213                                 /* Count the error? */
214                                 break;
215                         }
216                         goto free_aq;
217                         break;
218                 default:
219                         printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
220                         break;
221                 }
222                 goto free_aq;
223                 break;
224         default:
225                 /* ERROR */     
226                 goto free_aq;
227                 break;
228         }
229         return 0;
230 free_aq:
231         /* Cancel the timeout */
232         spin_lock_irqsave(&mac->lock, flags);
233         cancel_delayed_work(&aq->work);
234         /* Remove this item from the queue */
235         list_del(&aq->list);
236         spin_unlock_irqrestore(&mac->lock, flags);
237
238         /* Free it */
239         kfree(aq);
240         return 0;
241 }
242
243 /*
244  * Handle deauthorization
245  */
246 static void
247 ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
248         struct ieee80211softmac_network *net)
249 {
250         struct ieee80211softmac_auth_queue_item *aq = NULL;
251         struct list_head *list_ptr;
252         unsigned long flags;
253
254         function_enter();
255         
256         /* Lock and reset status flags */
257         spin_lock_irqsave(&mac->lock, flags);
258         net->authenticating = 0;
259         net->authenticated = 0;
260         
261         /* Find correct auth queue item, if it exists */
262         list_for_each(list_ptr, &mac->auth_queue) {
263                 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
264                 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
265                         break;
266                 else
267                         aq = NULL;
268         }
269         
270         /* Cancel pending work */
271         if(aq != NULL)
272                 /* Not entirely safe?  What about running work? */
273                 cancel_delayed_work(&aq->work);
274
275         /* Free our network ref */
276         ieee80211softmac_del_network_locked(mac, net);
277         if(net->challenge != NULL)
278                 kfree(net->challenge);
279         kfree(net);
280         
281         /* let's try to re-associate */
282         schedule_work(&mac->associnfo.work);
283         spin_unlock_irqrestore(&mac->lock, flags);
284 }
285
286 /* 
287  * Sends a deauth request to the desired AP
288  */
289 int 
290 ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, 
291         struct ieee80211softmac_network *net, int reason)
292 {
293         int ret;
294         
295         function_enter();
296
297         /* Make sure the network is authenticated */
298         if (!net->authenticated)
299         {
300                 printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
301                 /* Error okay? */
302                 return -EPERM;
303         }
304         
305         /* Send the de-auth packet */
306         if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
307                 return ret;
308         
309         ieee80211softmac_deauth_from_net(mac, net);
310         return 0;
311 }
312  
313 /*
314  * This should be registered with ieee80211 as handle_deauth
315  */
316 int 
317 ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_auth *auth)
318 {
319         
320         struct ieee80211softmac_network *net = NULL;
321         struct ieee80211softmac_device *mac = ieee80211_priv(dev);
322         
323         function_enter();
324         
325         if (!auth) {
326                 dprintk("deauth without deauth packet. eek!\n");
327                 return 0;
328         }
329
330         net = ieee80211softmac_get_network_by_bssid(mac, auth->header.addr2);
331         
332         if (net == NULL) {
333                 printkl(KERN_DEBUG PFX "Recieved deauthentication packet from "MAC_FMT", but that network is unknown.\n",
334                         MAC_ARG(auth->header.addr2));
335                 return 0;
336         }
337
338         /* Make sure the network is authenticated */
339         if(!net->authenticated)
340         {
341                 printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
342                 /* Error okay? */
343                 return -EPERM;
344         }
345
346         ieee80211softmac_deauth_from_net(mac, net);
347         return 0;
348 }