aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee80211/softmac
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee80211/softmac')
-rw-r--r--net/ieee80211/softmac/Kconfig1
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c96
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c15
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c30
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c169
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c117
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h5
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c36
8 files changed, 293 insertions, 176 deletions
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
index f2a27cc6ecb1..2811651cb134 100644
--- a/net/ieee80211/softmac/Kconfig
+++ b/net/ieee80211/softmac/Kconfig
@@ -2,6 +2,7 @@ config IEEE80211_SOFTMAC
2 tristate "Software MAC add-on to the IEEE 802.11 networking stack" 2 tristate "Software MAC add-on to the IEEE 802.11 networking stack"
3 depends on IEEE80211 && EXPERIMENTAL 3 depends on IEEE80211 && EXPERIMENTAL
4 select WIRELESS_EXT 4 select WIRELESS_EXT
5 select IEEE80211_CRYPT_WEP
5 ---help--- 6 ---help---
6 This option enables the hardware independent software MAC addon 7 This option enables the hardware independent software MAC addon
7 for the IEEE 802.11 networking stack. 8 for the IEEE 802.11 networking stack.
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 */ 85void
86static void 86ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
87ieee80211softmac_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 */
105void
106ieee80211softmac_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
109static inline int 119static inline int
110we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) 120we_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
165static void 166static void
166ieee80211softmac_assoc_notify(struct net_device *dev, void *context) 167ieee80211softmac_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
173static void
174ieee80211softmac_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) */
173void 190void
174ieee80211softmac_assoc_work(void *d) 191ieee80211softmac_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
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 06e332624665..90b8484e509b 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -107,6 +107,7 @@ ieee80211softmac_auth_queue(void *data)
107 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid)); 107 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
108 /* Remove this item from the queue */ 108 /* Remove this item from the queue */
109 spin_lock_irqsave(&mac->lock, flags); 109 spin_lock_irqsave(&mac->lock, flags);
110 net->authenticating = 0;
110 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); 111 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
111 cancel_delayed_work(&auth->work); /* just to make sure... */ 112 cancel_delayed_work(&auth->work); /* just to make sure... */
112 list_del(&auth->list); 113 list_del(&auth->list);
@@ -212,13 +213,13 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
212 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; 213 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
213 spin_unlock_irqrestore(&mac->lock, flags); 214 spin_unlock_irqrestore(&mac->lock, flags);
214 215
215 /* Switch to correct channel for this network */ 216 /* Send our response */
216 mac->set_channel(mac->dev, net->channel);
217
218 /* Send our response (How to encrypt?) */
219 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); 217 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
220 break; 218 return 0;
221 case IEEE80211SOFTMAC_AUTH_SHARED_PASS: 219 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
220 kfree(net->challenge);
221 net->challenge = NULL;
222 net->challenge_len = 0;
222 /* Check the status code of the response */ 223 /* Check the status code of the response */
223 switch(auth->status) { 224 switch(auth->status) {
224 case WLAN_STATUS_SUCCESS: 225 case WLAN_STATUS_SUCCESS:
@@ -229,6 +230,7 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
229 spin_unlock_irqrestore(&mac->lock, flags); 230 spin_unlock_irqrestore(&mac->lock, flags);
230 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n", 231 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
231 MAC_ARG(net->bssid)); 232 MAC_ARG(net->bssid));
233 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
232 break; 234 break;
233 default: 235 default:
234 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n", 236 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
@@ -279,6 +281,9 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
279 struct list_head *list_ptr; 281 struct list_head *list_ptr;
280 unsigned long flags; 282 unsigned long flags;
281 283
284 /* deauthentication implies disassociation */
285 ieee80211softmac_disassoc(mac);
286
282 /* Lock and reset status flags */ 287 /* Lock and reset status flags */
283 spin_lock_irqsave(&mac->lock, flags); 288 spin_lock_irqsave(&mac->lock, flags);
284 net->authenticating = 0; 289 net->authenticating = 0;
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
index 8cc8f3f0f8e7..f34fa2ef666b 100644
--- a/net/ieee80211/softmac/ieee80211softmac_event.c
+++ b/net/ieee80211/softmac/ieee80211softmac_event.c
@@ -38,7 +38,8 @@
38 * The event context is private and can only be used from 38 * The event context is private and can only be used from
39 * within this module. Its meaning varies with the event 39 * within this module. Its meaning varies with the event
40 * type: 40 * type:
41 * SCAN_FINISHED: no special meaning 41 * SCAN_FINISHED,
42 * DISASSOCIATED: NULL
42 * ASSOCIATED, 43 * ASSOCIATED,
43 * ASSOCIATE_FAILED, 44 * ASSOCIATE_FAILED,
44 * ASSOCIATE_TIMEOUT, 45 * ASSOCIATE_TIMEOUT,
@@ -59,15 +60,15 @@
59 */ 60 */
60 61
61static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { 62static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
62 "scan finished", 63 NULL, /* scan finished */
63 "associated", 64 NULL, /* associated */
64 "associating failed", 65 "associating failed",
65 "associating timed out", 66 "associating timed out",
66 "authenticated", 67 "authenticated",
67 "authenticating failed", 68 "authenticating failed",
68 "authenticating timed out", 69 "authenticating timed out",
69 "associating failed because no suitable network was found", 70 "associating failed because no suitable network was found",
70 "disassociated", 71 NULL, /* disassociated */
71}; 72};
72 73
73 74
@@ -77,7 +78,7 @@ ieee80211softmac_notify_callback(void *d)
77 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d; 78 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
78 kfree(d); 79 kfree(d);
79 80
80 event.fun(event.mac->dev, event.context); 81 event.fun(event.mac->dev, event.event_type, event.context);
81} 82}
82 83
83int 84int
@@ -136,30 +137,24 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve
136 int we_event; 137 int we_event;
137 char *msg = NULL; 138 char *msg = NULL;
138 139
140 memset(&wrqu, '\0', sizeof (union iwreq_data));
141
139 switch(event) { 142 switch(event) {
140 case IEEE80211SOFTMAC_EVENT_ASSOCIATED: 143 case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
141 network = (struct ieee80211softmac_network *)event_ctx; 144 network = (struct ieee80211softmac_network *)event_ctx;
142 wrqu.data.length = 0;
143 wrqu.data.flags = 0;
144 memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); 145 memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
145 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 146 /* fall through */
146 we_event = SIOCGIWAP;
147 break;
148 case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: 147 case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
149 wrqu.data.length = 0;
150 wrqu.data.flags = 0;
151 memset(&wrqu, '\0', sizeof (union iwreq_data));
152 wrqu.ap_addr.sa_family = ARPHRD_ETHER; 148 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
153 we_event = SIOCGIWAP; 149 we_event = SIOCGIWAP;
154 break; 150 break;
155 case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: 151 case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
156 wrqu.data.length = 0;
157 wrqu.data.flags = 0;
158 memset(&wrqu, '\0', sizeof (union iwreq_data));
159 we_event = SIOCGIWSCAN; 152 we_event = SIOCGIWSCAN;
160 break; 153 break;
161 default: 154 default:
162 msg = event_descriptions[event]; 155 msg = event_descriptions[event];
156 if (!msg)
157 msg = "SOFTMAC EVENT BUG";
163 wrqu.data.length = strlen(msg); 158 wrqu.data.length = strlen(msg);
164 we_event = IWEVCUSTOM; 159 we_event = IWEVCUSTOM;
165 break; 160 break;
@@ -172,6 +167,9 @@ ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int eve
172 if ((eventptr->event_type == event || eventptr->event_type == -1) 167 if ((eventptr->event_type == event || eventptr->event_type == -1)
173 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { 168 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
174 list_del(&eventptr->list); 169 list_del(&eventptr->list);
170 /* User may have subscribed to ANY event, so
171 * we tell them which event triggered it. */
172 eventptr->event_type = event;
175 schedule_work(&eventptr->work); 173 schedule_work(&eventptr->work);
176 } 174 }
177 } 175 }
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index cc6cd56c85b1..09541611e48c 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -149,6 +149,56 @@ ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
149 * shouldn't the sequence number be in ieee80211? */ 149 * shouldn't the sequence number be in ieee80211? */
150} 150}
151 151
152static u16
153ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
154 struct ieee80211softmac_network *net)
155{
156 u16 capability = 0;
157
158 /* ESS and IBSS bits are set according to the current mode */
159 switch (mac->ieee->iw_mode) {
160 case IW_MODE_INFRA:
161 capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
162 break;
163 case IW_MODE_ADHOC:
164 capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
165 break;
166 case IW_MODE_AUTO:
167 capability = net->capabilities &
168 (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS);
169 break;
170 default:
171 /* bleh. we don't ever go to these modes */
172 printk(KERN_ERR PFX "invalid iw_mode!\n");
173 break;
174 }
175
176 /* CF Pollable / CF Poll Request */
177 /* Needs to be implemented, for now, the 0's == not supported */
178
179 /* Privacy Bit */
180 capability |= mac->ieee->sec.level ?
181 cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
182
183 /* Short Preamble */
184 /* Always supported: we probably won't ever be powering devices which
185 * dont support this... */
186 capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
187
188 /* PBCC */
189 /* Not widely used */
190
191 /* Channel Agility */
192 /* Not widely used */
193
194 /* Short Slot */
195 /* Will be implemented later */
196
197 /* DSSS-OFDM */
198 /* Not widely used */
199
200 return capability;
201}
152 202
153/***************************************************************************** 203/*****************************************************************************
154 * Create Management packets 204 * Create Management packets
@@ -179,27 +229,6 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
179 return 0; 229 return 0;
180 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); 230 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
181 231
182 /* Fill in capability Info */
183 switch (mac->ieee->iw_mode) {
184 case IW_MODE_INFRA:
185 (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
186 break;
187 case IW_MODE_ADHOC:
188 (*pkt)->capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
189 break;
190 case IW_MODE_AUTO:
191 (*pkt)->capability = net->capabilities & (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS);
192 break;
193 default:
194 /* bleh. we don't ever go to these modes */
195 printk(KERN_ERR PFX "invalid iw_mode!\n");
196 break;
197 }
198 /* Need to add this
199 (*pkt)->capability |= mac->ieee->short_slot ?
200 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
201 */
202 (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
203 /* Fill in Listen Interval (?) */ 232 /* Fill in Listen Interval (?) */
204 (*pkt)->listen_interval = cpu_to_le16(10); 233 (*pkt)->listen_interval = cpu_to_le16(10);
205 234
@@ -239,17 +268,9 @@ ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
239 return 0; 268 return 0;
240 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid); 269 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
241 270
242 /* Fill in capability Info */ 271 /* Fill in the capabilities */
243 (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ? 272 (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
244 cpu_to_le16(WLAN_CAPABILITY_ESS) : 273
245 cpu_to_le16(WLAN_CAPABILITY_IBSS);
246 /*
247 (*pkt)->capability |= mac->ieee->short_slot ?
248 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
249 */
250 (*pkt)->capability |= mac->ieee->sec.level ?
251 cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
252
253 /* Fill in Listen Interval (?) */ 274 /* Fill in Listen Interval (?) */
254 (*pkt)->listen_interval = cpu_to_le16(10); 275 (*pkt)->listen_interval = cpu_to_le16(10);
255 /* Fill in the current AP MAC */ 276 /* Fill in the current AP MAC */
@@ -268,26 +289,27 @@ ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
268static u32 289static u32
269ieee80211softmac_auth(struct ieee80211_auth **pkt, 290ieee80211softmac_auth(struct ieee80211_auth **pkt,
270 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, 291 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
271 u16 transaction, u16 status) 292 u16 transaction, u16 status, int *encrypt_mpdu)
272{ 293{
273 u8 *data; 294 u8 *data;
295 int auth_mode = mac->ieee->sec.auth_mode;
296 int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
297 && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
298
274 /* Allocate Packet */ 299 /* Allocate Packet */
275 (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( 300 (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
276 2 + /* Auth Algorithm */ 301 2 + /* Auth Algorithm */
277 2 + /* Auth Transaction Seq */ 302 2 + /* Auth Transaction Seq */
278 2 + /* Status Code */ 303 2 + /* Status Code */
279 /* Challenge Text IE */ 304 /* Challenge Text IE */
280 mac->ieee->open_wep ? 0 : 305 is_shared_response ? 0 : 1 + 1 + net->challenge_len
281 1 + 1 + WLAN_AUTH_CHALLENGE_LEN 306 );
282 );
283 if (unlikely((*pkt) == NULL)) 307 if (unlikely((*pkt) == NULL))
284 return 0; 308 return 0;
285 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); 309 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
286 310
287 /* Algorithm */ 311 /* Algorithm */
288 (*pkt)->algorithm = mac->ieee->open_wep ? 312 (*pkt)->algorithm = cpu_to_le16(auth_mode);
289 cpu_to_le16(WLAN_AUTH_OPEN) :
290 cpu_to_le16(WLAN_AUTH_SHARED_KEY);
291 /* Transaction */ 313 /* Transaction */
292 (*pkt)->transaction = cpu_to_le16(transaction); 314 (*pkt)->transaction = cpu_to_le16(transaction);
293 /* Status */ 315 /* Status */
@@ -295,18 +317,20 @@ ieee80211softmac_auth(struct ieee80211_auth **pkt,
295 317
296 data = (u8 *)(*pkt)->info_element; 318 data = (u8 *)(*pkt)->info_element;
297 /* Challenge Text */ 319 /* Challenge Text */
298 if(!mac->ieee->open_wep){ 320 if (is_shared_response) {
299 *data = MFIE_TYPE_CHALLENGE; 321 *data = MFIE_TYPE_CHALLENGE;
300 data++; 322 data++;
301 323
302 /* Copy the challenge in */ 324 /* Copy the challenge in */
303 // *data = challenge length 325 *data = net->challenge_len;
304 // data += sizeof(u16); 326 data++;
305 // memcpy(data, challenge, challenge length); 327 memcpy(data, net->challenge, net->challenge_len);
306 // data += challenge length; 328 data += net->challenge_len;
307 329
308 /* Add the full size to the packet length */ 330 /* Make sure this frame gets encrypted with the shared key */
309 } 331 *encrypt_mpdu = 1;
332 } else
333 *encrypt_mpdu = 0;
310 334
311 /* Return the packet size */ 335 /* Return the packet size */
312 return (data - (u8 *)(*pkt)); 336 return (data - (u8 *)(*pkt));
@@ -396,6 +420,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
396{ 420{
397 void *pkt = NULL; 421 void *pkt = NULL;
398 u32 pkt_size = 0; 422 u32 pkt_size = 0;
423 int encrypt_mpdu = 0;
399 424
400 switch(type) { 425 switch(type) {
401 case IEEE80211_STYPE_ASSOC_REQ: 426 case IEEE80211_STYPE_ASSOC_REQ:
@@ -405,7 +430,7 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
405 pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); 430 pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
406 break; 431 break;
407 case IEEE80211_STYPE_AUTH: 432 case IEEE80211_STYPE_AUTH:
408 pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16)); 433 pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
409 break; 434 break;
410 case IEEE80211_STYPE_DISASSOC: 435 case IEEE80211_STYPE_DISASSOC:
411 case IEEE80211_STYPE_DEAUTH: 436 case IEEE80211_STYPE_DEAUTH:
@@ -434,52 +459,8 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
434 * or get rid of it alltogether? 459 * or get rid of it alltogether?
435 * Does this work for you now? 460 * Does this work for you now?
436 */ 461 */
437 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size); 462 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
438 463 IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
439 kfree(pkt);
440 return 0;
441}
442
443
444/* Create an rts/cts frame */
445static u32
446ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt,
447 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
448 u32 type)
449{
450 /* Allocate Packet */
451 (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC);
452 memset(*pkt, 0, IEEE80211_2ADDR_LEN);
453 if((*pkt) == NULL)
454 return 0;
455 ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid);
456 return IEEE80211_2ADDR_LEN;
457}
458
459
460/* Sends a control packet */
461static int
462ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac,
463 struct ieee80211softmac_network *net, u32 type, u32 arg)
464{
465 void *pkt = NULL;
466 u32 pkt_size = 0;
467
468 switch(type) {
469 case IEEE80211_STYPE_RTS:
470 case IEEE80211_STYPE_CTS:
471 pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type);
472 break;
473 default:
474 printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type);
475 return -EINVAL;
476 }
477
478 if(pkt_size == 0)
479 return -ENOMEM;
480
481 /* Send the packet to the ieee80211 layer for tx */
482 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size);
483 464
484 kfree(pkt); 465 kfree(pkt);
485 return 0; 466 return 0;
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 6252be2c0db9..4b2e57d12418 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -26,6 +26,7 @@
26 26
27#include "ieee80211softmac_priv.h" 27#include "ieee80211softmac_priv.h"
28#include <linux/sort.h> 28#include <linux/sort.h>
29#include <linux/etherdevice.h>
29 30
30struct net_device *alloc_ieee80211softmac(int sizeof_priv) 31struct net_device *alloc_ieee80211softmac(int sizeof_priv)
31{ 32{
@@ -61,14 +62,6 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
61 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; 62 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
62 softmac->stop_scan = ieee80211softmac_stop_scan_implementation; 63 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
63 64
64 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
65 // It has to be set to the highest rate all stations in the current network can handle.
66 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
67 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
68 /* This is reassigned in ieee80211softmac_start to sane values. */
69 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
70 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
71
72 /* to start with, we can't send anything ... */ 65 /* to start with, we can't send anything ... */
73 netif_carrier_off(dev); 66 netif_carrier_off(dev);
74 67
@@ -170,15 +163,82 @@ static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *m
170 } 163 }
171} 164}
172 165
173void ieee80211softmac_start(struct net_device *dev) 166int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
167{
168 int search;
169 u8 search_rate;
170
171 for (search = 0; search < ri->count; search++) {
172 search_rate = ri->rates[search];
173 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
174 if (rate == search_rate)
175 return 1;
176 }
177
178 return 0;
179}
180
181/* Finds the highest rate which is:
182 * 1. Present in ri (optionally a basic rate)
183 * 2. Supported by the device
184 * 3. Less than or equal to the user-defined rate
185 */
186static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
187 struct ieee80211softmac_ratesinfo *ri, int basic_only)
188{
189 u8 user_rate = mac->txrates.user_rate;
190 int i;
191
192 if (ri->count == 0) {
193 dprintk(KERN_ERR PFX "empty ratesinfo?\n");
194 return IEEE80211_CCK_RATE_1MB;
195 }
196
197 for (i = ri->count - 1; i >= 0; i--) {
198 u8 rate = ri->rates[i];
199 if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
200 continue;
201 rate &= ~IEEE80211_BASIC_RATE_MASK;
202 if (rate > user_rate)
203 continue;
204 if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
205 return rate;
206 }
207
208 /* If we haven't found a suitable rate by now, just trust the user */
209 return user_rate;
210}
211
212void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
213{
214 struct ieee80211softmac_txrates *txrates = &mac->txrates;
215 struct ieee80211softmac_txrates oldrates;
216 u32 change = 0;
217
218 if (mac->txrates_change)
219 oldrates = mac->txrates;
220
221 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
222 txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
223
224 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
225 txrates->default_fallback = lower_rate(mac, txrates->default_rate);
226
227 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
228 txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
229
230 if (mac->txrates_change)
231 mac->txrates_change(mac->dev, change, &oldrates);
232
233}
234
235void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
174{ 236{
175 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
176 struct ieee80211_device *ieee = mac->ieee; 237 struct ieee80211_device *ieee = mac->ieee;
177 u32 change = 0; 238 u32 change = 0;
239 struct ieee80211softmac_txrates *txrates = &mac->txrates;
178 struct ieee80211softmac_txrates oldrates; 240 struct ieee80211softmac_txrates oldrates;
179 241
180 ieee80211softmac_start_check_rates(mac);
181
182 /* TODO: We need some kind of state machine to lower the default rates 242 /* TODO: We need some kind of state machine to lower the default rates
183 * if we loose too many packets. 243 * if we loose too many packets.
184 */ 244 */
@@ -193,22 +253,37 @@ void ieee80211softmac_start(struct net_device *dev)
193 more reliable. Note similar logic in 253 more reliable. Note similar logic in
194 ieee80211softmac_wx_set_rate() */ 254 ieee80211softmac_wx_set_rate() */
195 if (ieee->modulation & IEEE80211_CCK_MODULATION) { 255 if (ieee->modulation & IEEE80211_CCK_MODULATION) {
196 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB; 256 txrates->user_rate = IEEE80211_CCK_RATE_11MB;
197 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
198 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
199 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
200 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) { 257 } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
201 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB; 258 txrates->user_rate = IEEE80211_OFDM_RATE_54MB;
202 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
203 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
204 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
205 } else 259 } else
206 assert(0); 260 assert(0);
261
262 txrates->default_rate = IEEE80211_CCK_RATE_1MB;
263 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
264
265 txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
266 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
267
268 txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
269 change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
270
271 txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
272 change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
273
207 if (mac->txrates_change) 274 if (mac->txrates_change)
208 mac->txrates_change(dev, change, &oldrates); 275 mac->txrates_change(mac->dev, change, &oldrates);
209 276
210 mac->running = 1; 277 mac->running = 1;
211} 278}
279
280void ieee80211softmac_start(struct net_device *dev)
281{
282 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
283
284 ieee80211softmac_start_check_rates(mac);
285 ieee80211softmac_init_txrates(mac);
286}
212EXPORT_SYMBOL_GPL(ieee80211softmac_start); 287EXPORT_SYMBOL_GPL(ieee80211softmac_start);
213 288
214void ieee80211softmac_stop(struct net_device *dev) 289void ieee80211softmac_stop(struct net_device *dev)
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index 65d9816c8ecc..fa1f8e3acfc0 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -116,7 +116,10 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
116 struct ieee80211softmac_essid *essid); 116 struct ieee80211softmac_essid *essid);
117 117
118/* Rates related */ 118/* Rates related */
119int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
119u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); 120u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
121void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
122void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
120static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { 123static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
121 return ieee80211softmac_lower_rate_delta(mac, rate, 1); 124 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
122} 125}
@@ -150,6 +153,8 @@ int ieee80211softmac_handle_disassoc(struct net_device * dev,
150int ieee80211softmac_handle_reassoc_req(struct net_device * dev, 153int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
151 struct ieee80211_reassoc_request * reassoc); 154 struct ieee80211_reassoc_request * reassoc);
152void ieee80211softmac_assoc_timeout(void *d); 155void ieee80211softmac_assoc_timeout(void *d);
156void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
157void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
153 158
154/* some helper functions */ 159/* some helper functions */
155static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) 160static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 27edb2b5581a..22aa6199185b 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -211,8 +211,8 @@ ieee80211softmac_wx_set_rate(struct net_device *net_dev,
211 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) 211 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
212 goto out_unlock; 212 goto out_unlock;
213 213
214 mac->txrates.default_rate = rate; 214 mac->txrates.user_rate = rate;
215 mac->txrates.default_fallback = lower_rate(mac, rate); 215 ieee80211softmac_recalc_txrates(mac);
216 err = 0; 216 err = 0;
217 217
218out_unlock: 218out_unlock:
@@ -431,3 +431,35 @@ ieee80211softmac_wx_get_genie(struct net_device *dev,
431} 431}
432EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); 432EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
433 433
434int
435ieee80211softmac_wx_set_mlme(struct net_device *dev,
436 struct iw_request_info *info,
437 union iwreq_data *wrqu,
438 char *extra)
439{
440 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
441 struct iw_mlme *mlme = (struct iw_mlme *)extra;
442 u16 reason = cpu_to_le16(mlme->reason_code);
443 struct ieee80211softmac_network *net;
444
445 if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
446 printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
447 return -EINVAL;
448 }
449
450 switch (mlme->cmd) {
451 case IW_MLME_DEAUTH:
452 net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
453 if (!net) {
454 printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
455 return -EINVAL;
456 }
457 return ieee80211softmac_deauth_req(mac, net, reason);
458 case IW_MLME_DISASSOC:
459 ieee80211softmac_send_disassoc_req(mac, reason);
460 return 0;
461 default:
462 return -EOPNOTSUPP;
463 }
464}
465EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);