blob: 4ef5b9e00c770b1235636f298a445304be011b03 [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
2 * This file contains ioctl functions
3 */
4#include <linux/ctype.h>
5#include <linux/delay.h>
6#include <linux/if.h>
7#include <linux/if_arp.h>
8#include <linux/wireless.h>
9#include <linux/bitops.h>
10
11#include <net/ieee80211.h>
12#include <net/iw_handler.h>
13
14#include "host.h"
15#include "radiotap.h"
16#include "decl.h"
17#include "defs.h"
18#include "dev.h"
19#include "join.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020020#include "wext.h"
21#include "assoc.h"
22
23
Holger Schurig9f9dac22007-10-26 10:12:14 +020024static inline void libertas_postpone_association_work(wlan_private *priv)
25{
26 if (priv->adapter->surpriseremoved)
27 return;
28 cancel_delayed_work(&priv->assoc_work);
29 queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
30}
31
32static inline void libertas_cancel_association_work(wlan_private *priv)
33{
34 cancel_delayed_work(&priv->assoc_work);
35 if (priv->adapter->pending_assoc_req) {
36 kfree(priv->adapter->pending_assoc_req);
37 priv->adapter->pending_assoc_req = NULL;
38 }
39}
40
41
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020042/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020043 * @brief Find the channel frequency power info with specific channel
44 *
45 * @param adapter A pointer to wlan_adapter structure
46 * @param band it can be BAND_A, BAND_G or BAND_B
47 * @param channel the channel for looking
48 * @return A pointer to struct chan_freq_power structure or NULL if not find.
49 */
50struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
51 u8 band, u16 channel)
52{
53 struct chan_freq_power *cfp = NULL;
54 struct region_channel *rc;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020055 int i, j;
56
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +020057 for (j = 0; !cfp && (j < ARRAY_SIZE(adapter->region_channel)); j++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020058 rc = &adapter->region_channel[j];
59
60 if (adapter->enable11d)
61 rc = &adapter->universal_channel[j];
62 if (!rc->valid || !rc->CFP)
63 continue;
64 if (rc->band != band)
65 continue;
66 for (i = 0; i < rc->nrcfp; i++) {
67 if (rc->CFP[i].channel == channel) {
68 cfp = &rc->CFP[i];
69 break;
70 }
71 }
72 }
73
74 if (!cfp && channel)
Holger Schurig9012b282007-05-25 11:27:16 -040075 lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find "
76 "cfp by band %d / channel %d\n", band, channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020077
78 return cfp;
79}
80
81/**
82 * @brief Find the channel frequency power info with specific frequency
83 *
84 * @param adapter A pointer to wlan_adapter structure
85 * @param band it can be BAND_A, BAND_G or BAND_B
86 * @param freq the frequency for looking
87 * @return A pointer to struct chan_freq_power structure or NULL if not find.
88 */
89static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
90 u8 band, u32 freq)
91{
92 struct chan_freq_power *cfp = NULL;
93 struct region_channel *rc;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020094 int i, j;
95
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +020096 for (j = 0; !cfp && (j < ARRAY_SIZE(adapter->region_channel)); j++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020097 rc = &adapter->region_channel[j];
98
99 if (adapter->enable11d)
100 rc = &adapter->universal_channel[j];
101 if (!rc->valid || !rc->CFP)
102 continue;
103 if (rc->band != band)
104 continue;
105 for (i = 0; i < rc->nrcfp; i++) {
106 if (rc->CFP[i].freq == freq) {
107 cfp = &rc->CFP[i];
108 break;
109 }
110 }
111 }
112
113 if (!cfp && freq)
Holger Schurig9012b282007-05-25 11:27:16 -0400114 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
115 "band %d / freq %d\n", band, freq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200116
117 return cfp;
118}
119
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200120
121/**
122 * @brief Set Radio On/OFF
123 *
124 * @param priv A pointer to wlan_private structure
125 * @option Radio Option
126 * @return 0 --success, otherwise fail
127 */
Holger Schurigac558ca2007-08-02 11:49:06 -0400128static int wlan_radio_ioctl(wlan_private * priv, u8 option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200129{
130 int ret = 0;
131 wlan_adapter *adapter = priv->adapter;
132
Holger Schurig9012b282007-05-25 11:27:16 -0400133 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200134
135 if (adapter->radioon != option) {
Holger Schurig9012b282007-05-25 11:27:16 -0400136 lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200137 adapter->radioon = option;
138
139 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400140 CMD_802_11_RADIO_CONTROL,
141 CMD_ACT_SET,
142 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200143 }
144
Holger Schurig9012b282007-05-25 11:27:16 -0400145 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200146 return ret;
147}
148
149/**
Dan Williams8c512762007-08-02 11:40:45 -0400150 * @brief Copy active data rates based on adapter mode and status
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200151 *
152 * @param adapter A pointer to wlan_adapter structure
153 * @param rate The buf to return the active rates
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200154 */
Dan Williams8c512762007-08-02 11:40:45 -0400155static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156{
Holger Schurig9012b282007-05-25 11:27:16 -0400157 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200158
Dan Williams8c512762007-08-02 11:40:45 -0400159 if (adapter->connect_status != LIBERTAS_CONNECTED)
160 memcpy(rates, libertas_bg_rates, MAX_RATES);
161 else
162 memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200163
Dan Williams8c512762007-08-02 11:40:45 -0400164 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200165}
166
167static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
168 char *cwrq, char *extra)
169{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200170
Holger Schurig9012b282007-05-25 11:27:16 -0400171 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200172
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400173 /* We could add support for 802.11n here as needed. Jean II */
174 snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200175
Holger Schurig9012b282007-05-25 11:27:16 -0400176 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200177 return 0;
178}
179
180static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
181 struct iw_freq *fwrq, char *extra)
182{
183 wlan_private *priv = dev->priv;
184 wlan_adapter *adapter = priv->adapter;
185 struct chan_freq_power *cfp;
186
Holger Schurig9012b282007-05-25 11:27:16 -0400187 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200188
189 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
190 adapter->curbssparams.channel);
191
192 if (!cfp) {
193 if (adapter->curbssparams.channel)
Holger Schurig9012b282007-05-25 11:27:16 -0400194 lbs_deb_wext("invalid channel %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200195 adapter->curbssparams.channel);
196 return -EINVAL;
197 }
198
199 fwrq->m = (long)cfp->freq * 100000;
200 fwrq->e = 1;
201
Holger Schurig9012b282007-05-25 11:27:16 -0400202 lbs_deb_wext("freq %u\n", fwrq->m);
203 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200204 return 0;
205}
206
207static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
208 struct sockaddr *awrq, char *extra)
209{
210 wlan_private *priv = dev->priv;
211 wlan_adapter *adapter = priv->adapter;
212
Holger Schurig9012b282007-05-25 11:27:16 -0400213 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200214
Dan Williams0aef64d2007-08-02 11:31:18 -0400215 if (adapter->connect_status == LIBERTAS_CONNECTED) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200216 memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
217 } else {
218 memset(awrq->sa_data, 0, ETH_ALEN);
219 }
220 awrq->sa_family = ARPHRD_ETHER;
221
Holger Schurig9012b282007-05-25 11:27:16 -0400222 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200223 return 0;
224}
225
226static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
227 struct iw_point *dwrq, char *extra)
228{
229 wlan_private *priv = dev->priv;
230 wlan_adapter *adapter = priv->adapter;
231
Holger Schurig9012b282007-05-25 11:27:16 -0400232 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200233
234 /*
235 * Check the size of the string
236 */
237
238 if (dwrq->length > 16) {
239 return -E2BIG;
240 }
241
242 mutex_lock(&adapter->lock);
243 memset(adapter->nodename, 0, sizeof(adapter->nodename));
244 memcpy(adapter->nodename, extra, dwrq->length);
245 mutex_unlock(&adapter->lock);
246
Holger Schurig9012b282007-05-25 11:27:16 -0400247 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200248 return 0;
249}
250
251static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
252 struct iw_point *dwrq, char *extra)
253{
Holger Schurig04799fa2007-10-09 15:04:14 +0200254 wlan_private *priv = dev->priv;
255 wlan_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200256
Holger Schurig9012b282007-05-25 11:27:16 -0400257 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200258
Holger Schurig04799fa2007-10-09 15:04:14 +0200259 dwrq->length = strlen(adapter->nodename);
260 memcpy(extra, adapter->nodename, dwrq->length);
261 extra[dwrq->length] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200262
Holger Schurig04799fa2007-10-09 15:04:14 +0200263 dwrq->flags = 1; /* active */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200264
Holger Schurig9012b282007-05-25 11:27:16 -0400265 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200266 return 0;
267}
268
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400269static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
270 struct iw_point *dwrq, char *extra)
271{
272 wlan_private *priv = dev->priv;
273 wlan_adapter *adapter = priv->adapter;
274
275 lbs_deb_enter(LBS_DEB_WEXT);
276
277 /* Use nickname to indicate that mesh is on */
278
Dan Williams0aef64d2007-08-02 11:31:18 -0400279 if (adapter->connect_status == LIBERTAS_CONNECTED) {
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400280 strncpy(extra, "Mesh", 12);
281 extra[12] = '\0';
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400282 dwrq->length = strlen(extra);
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400283 }
284
285 else {
286 extra[0] = '\0';
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400287 dwrq->length = 0;
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400288 }
289
290 lbs_deb_leave(LBS_DEB_WEXT);
291 return 0;
292}
Holger Schurig04799fa2007-10-09 15:04:14 +0200293
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200294static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
295 struct iw_param *vwrq, char *extra)
296{
297 int ret = 0;
298 wlan_private *priv = dev->priv;
299 wlan_adapter *adapter = priv->adapter;
David Woodhouse981f1872007-05-25 23:36:54 -0400300 u32 rthr = vwrq->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200301
Holger Schurig9012b282007-05-25 11:27:16 -0400302 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200303
304 if (vwrq->disabled) {
305 adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
306 } else {
307 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
308 return -EINVAL;
309 adapter->rtsthsd = rthr;
310 }
311
Dan Williams0aef64d2007-08-02 11:31:18 -0400312 ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
313 CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200314 OID_802_11_RTS_THRESHOLD, &rthr);
315
Holger Schurig9012b282007-05-25 11:27:16 -0400316 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200317 return ret;
318}
319
320static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
321 struct iw_param *vwrq, char *extra)
322{
323 int ret = 0;
324 wlan_private *priv = dev->priv;
325 wlan_adapter *adapter = priv->adapter;
326
Holger Schurig9012b282007-05-25 11:27:16 -0400327 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200328
329 adapter->rtsthsd = 0;
Dan Williams0aef64d2007-08-02 11:31:18 -0400330 ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
331 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200332 OID_802_11_RTS_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400333 if (ret)
334 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200335
336 vwrq->value = adapter->rtsthsd;
337 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
338 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
339 vwrq->fixed = 1;
340
Holger Schurig9012b282007-05-25 11:27:16 -0400341out:
342 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
343 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200344}
345
346static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
347 struct iw_param *vwrq, char *extra)
348{
349 int ret = 0;
David Woodhouse981f1872007-05-25 23:36:54 -0400350 u32 fthr = vwrq->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200351 wlan_private *priv = dev->priv;
352 wlan_adapter *adapter = priv->adapter;
353
Holger Schurig9012b282007-05-25 11:27:16 -0400354 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200355
356 if (vwrq->disabled) {
357 adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
358 } else {
359 if (fthr < MRVDRV_FRAG_MIN_VALUE
360 || fthr > MRVDRV_FRAG_MAX_VALUE)
361 return -EINVAL;
362 adapter->fragthsd = fthr;
363 }
364
Dan Williams0aef64d2007-08-02 11:31:18 -0400365 ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
366 CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200367 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
Holger Schurig9012b282007-05-25 11:27:16 -0400368
369 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200370 return ret;
371}
372
373static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
374 struct iw_param *vwrq, char *extra)
375{
376 int ret = 0;
377 wlan_private *priv = dev->priv;
378 wlan_adapter *adapter = priv->adapter;
379
Holger Schurig9012b282007-05-25 11:27:16 -0400380 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200381
382 adapter->fragthsd = 0;
383 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400384 CMD_802_11_SNMP_MIB,
385 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200386 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400387 if (ret)
388 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200389
390 vwrq->value = adapter->fragthsd;
391 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
392 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
393 vwrq->fixed = 1;
394
Holger Schurig9012b282007-05-25 11:27:16 -0400395out:
396 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200397 return ret;
398}
399
400static int wlan_get_mode(struct net_device *dev,
401 struct iw_request_info *info, u32 * uwrq, char *extra)
402{
403 wlan_private *priv = dev->priv;
404 wlan_adapter *adapter = priv->adapter;
405
Holger Schurig9012b282007-05-25 11:27:16 -0400406 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200407
Dan Williams0dc5a292007-05-10 22:58:02 -0400408 *uwrq = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200409
Holger Schurig9012b282007-05-25 11:27:16 -0400410 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200411 return 0;
412}
413
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400414static int mesh_wlan_get_mode(struct net_device *dev,
415 struct iw_request_info *info, u32 * uwrq,
416 char *extra)
417{
418 lbs_deb_enter(LBS_DEB_WEXT);
419
420 *uwrq = IW_MODE_REPEAT ;
421
422 lbs_deb_leave(LBS_DEB_WEXT);
423 return 0;
424}
425
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426static int wlan_get_txpow(struct net_device *dev,
427 struct iw_request_info *info,
428 struct iw_param *vwrq, char *extra)
429{
430 int ret = 0;
431 wlan_private *priv = dev->priv;
432 wlan_adapter *adapter = priv->adapter;
433
Holger Schurig9012b282007-05-25 11:27:16 -0400434 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200435
436 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400437 CMD_802_11_RF_TX_POWER,
438 CMD_ACT_TX_POWER_OPT_GET,
439 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200440
Holger Schurig9012b282007-05-25 11:27:16 -0400441 if (ret)
442 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200443
Holger Schurig9012b282007-05-25 11:27:16 -0400444 lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200445 vwrq->value = adapter->txpowerlevel;
446 vwrq->fixed = 1;
447 if (adapter->radioon) {
448 vwrq->disabled = 0;
449 vwrq->flags = IW_TXPOW_DBM;
450 } else {
451 vwrq->disabled = 1;
452 }
453
Holger Schurig9012b282007-05-25 11:27:16 -0400454out:
455 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
456 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200457}
458
459static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
460 struct iw_param *vwrq, char *extra)
461{
462 int ret = 0;
463 wlan_private *priv = dev->priv;
464 wlan_adapter *adapter = priv->adapter;
465
Holger Schurig9012b282007-05-25 11:27:16 -0400466 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467
468 if (vwrq->flags == IW_RETRY_LIMIT) {
469 /* The MAC has a 4-bit Total_Tx_Count register
470 Total_Tx_Count = 1 + Tx_Retry_Count */
471#define TX_RETRY_MIN 0
472#define TX_RETRY_MAX 14
473 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
474 return -EINVAL;
475
476 /* Adding 1 to convert retry count to try count */
477 adapter->txretrycount = vwrq->value + 1;
478
Dan Williams0aef64d2007-08-02 11:31:18 -0400479 ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
480 CMD_ACT_SET,
481 CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 OID_802_11_TX_RETRYCOUNT, NULL);
483
Holger Schurig9012b282007-05-25 11:27:16 -0400484 if (ret)
485 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200486 } else {
487 return -EOPNOTSUPP;
488 }
489
Holger Schurig9012b282007-05-25 11:27:16 -0400490out:
491 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
492 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200493}
494
495static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
496 struct iw_param *vwrq, char *extra)
497{
498 wlan_private *priv = dev->priv;
499 wlan_adapter *adapter = priv->adapter;
500 int ret = 0;
501
Holger Schurig9012b282007-05-25 11:27:16 -0400502 lbs_deb_enter(LBS_DEB_WEXT);
503
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200504 adapter->txretrycount = 0;
505 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400506 CMD_802_11_SNMP_MIB,
507 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200508 OID_802_11_TX_RETRYCOUNT, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400509 if (ret)
510 goto out;
511
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200512 vwrq->disabled = 0;
513 if (!vwrq->flags) {
514 vwrq->flags = IW_RETRY_LIMIT;
515 /* Subtract 1 to convert try count to retry count */
516 vwrq->value = adapter->txretrycount - 1;
517 }
518
Holger Schurig9012b282007-05-25 11:27:16 -0400519out:
520 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
521 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200522}
523
524static inline void sort_channels(struct iw_freq *freq, int num)
525{
526 int i, j;
527 struct iw_freq temp;
528
529 for (i = 0; i < num; i++)
530 for (j = i + 1; j < num; j++)
531 if (freq[i].i > freq[j].i) {
532 temp.i = freq[i].i;
533 temp.m = freq[i].m;
534
535 freq[i].i = freq[j].i;
536 freq[i].m = freq[j].m;
537
538 freq[j].i = temp.i;
539 freq[j].m = temp.m;
540 }
541}
542
543/* data rate listing
544 MULTI_BANDS:
545 abg a b b/g
546 Infra G(12) A(8) B(4) G(12)
547 Adhoc A+B(12) A(8) B(4) B(4)
548
549 non-MULTI_BANDS:
550 b b/g
551 Infra B(4) G(12)
552 Adhoc B(4) B(4)
553 */
554/**
555 * @brief Get Range Info
556 *
557 * @param dev A pointer to net_device structure
558 * @param info A pointer to iw_request_info structure
559 * @param vwrq A pointer to iw_param structure
560 * @param extra A pointer to extra data buf
561 * @return 0 --success, otherwise fail
562 */
563static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
564 struct iw_point *dwrq, char *extra)
565{
566 int i, j;
567 wlan_private *priv = dev->priv;
568 wlan_adapter *adapter = priv->adapter;
569 struct iw_range *range = (struct iw_range *)extra;
570 struct chan_freq_power *cfp;
Dan Williams8c512762007-08-02 11:40:45 -0400571 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200572
573 u8 flag = 0;
574
Holger Schurig9012b282007-05-25 11:27:16 -0400575 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200576
577 dwrq->length = sizeof(struct iw_range);
578 memset(range, 0, sizeof(struct iw_range));
579
580 range->min_nwid = 0;
581 range->max_nwid = 0;
582
583 memset(rates, 0, sizeof(rates));
Dan Williams8c512762007-08-02 11:40:45 -0400584 copy_active_data_rates(adapter, rates);
585 range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
586 for (i = 0; i < range->num_bitrates; i++)
587 range->bitrate[i] = rates[i] * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588 range->num_bitrates = i;
Holger Schurig9012b282007-05-25 11:27:16 -0400589 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200590 range->num_bitrates);
591
592 range->num_frequency = 0;
593 if (priv->adapter->enable11d &&
Dan Williams0aef64d2007-08-02 11:31:18 -0400594 adapter->connect_status == LIBERTAS_CONNECTED) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200595 u8 chan_no;
596 u8 band;
597
598 struct parsed_region_chan_11d *parsed_region_chan =
599 &adapter->parsed_region_chan;
600
601 if (parsed_region_chan == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -0400602 lbs_deb_wext("11d: parsed_region_chan is NULL\n");
603 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 }
605 band = parsed_region_chan->band;
Holger Schurig9012b282007-05-25 11:27:16 -0400606 lbs_deb_wext("band %d, nr_char %d\n", band,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200607 parsed_region_chan->nr_chan);
608
609 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
610 && (i < parsed_region_chan->nr_chan); i++) {
611 chan_no = parsed_region_chan->chanpwr[i].chan;
Holger Schurig9012b282007-05-25 11:27:16 -0400612 lbs_deb_wext("chan_no %d\n", chan_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200613 range->freq[range->num_frequency].i = (long)chan_no;
614 range->freq[range->num_frequency].m =
615 (long)libertas_chan_2_freq(chan_no, band) * 100000;
616 range->freq[range->num_frequency].e = 1;
617 range->num_frequency++;
618 }
619 flag = 1;
620 }
621 if (!flag) {
622 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
Alejandro Martinez Ruizc00acf42007-10-18 10:16:33 +0200623 && (j < ARRAY_SIZE(adapter->region_channel)); j++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200624 cfp = adapter->region_channel[j].CFP;
625 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
626 && adapter->region_channel[j].valid
627 && cfp
628 && (i < adapter->region_channel[j].nrcfp); i++) {
629 range->freq[range->num_frequency].i =
630 (long)cfp->channel;
631 range->freq[range->num_frequency].m =
632 (long)cfp->freq * 100000;
633 range->freq[range->num_frequency].e = 1;
634 cfp++;
635 range->num_frequency++;
636 }
637 }
638 }
639
Holger Schurig9012b282007-05-25 11:27:16 -0400640 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200641 IW_MAX_FREQUENCIES, range->num_frequency);
642
643 range->num_channels = range->num_frequency;
644
645 sort_channels(&range->freq[0], range->num_frequency);
646
647 /*
648 * Set an indication of the max TCP throughput in bit/s that we can
649 * expect using this interface
650 */
651 if (i > 2)
652 range->throughput = 5000 * 1000;
653 else
654 range->throughput = 1500 * 1000;
655
656 range->min_rts = MRVDRV_RTS_MIN_VALUE;
657 range->max_rts = MRVDRV_RTS_MAX_VALUE;
658 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
659 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
660
661 range->encoding_size[0] = 5;
662 range->encoding_size[1] = 13;
663 range->num_encoding_sizes = 2;
664 range->max_encoding_tokens = 4;
665
666 range->min_pmp = 1000000;
667 range->max_pmp = 120000000;
668 range->min_pmt = 1000;
669 range->max_pmt = 1000000;
670 range->pmp_flags = IW_POWER_PERIOD;
671 range->pmt_flags = IW_POWER_TIMEOUT;
672 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
673
674 /*
675 * Minimum version we recommend
676 */
677 range->we_version_source = 15;
678
679 /*
680 * Version we are compiled with
681 */
682 range->we_version_compiled = WIRELESS_EXT;
683
684 range->retry_capa = IW_RETRY_LIMIT;
685 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
686
687 range->min_retry = TX_RETRY_MIN;
688 range->max_retry = TX_RETRY_MAX;
689
690 /*
691 * Set the qual, level and noise range values
692 */
693 range->max_qual.qual = 100;
694 range->max_qual.level = 0;
695 range->max_qual.noise = 0;
696 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
697
698 range->avg_qual.qual = 70;
699 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
700 range->avg_qual.level = 0;
701 range->avg_qual.noise = 0;
702 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
703
704 range->sensitivity = 0;
705
706 /*
707 * Setup the supported power level ranges
708 */
709 memset(range->txpower, 0, sizeof(range->txpower));
710 range->txpower[0] = 5;
711 range->txpower[1] = 7;
712 range->txpower[2] = 9;
713 range->txpower[3] = 11;
714 range->txpower[4] = 13;
715 range->txpower[5] = 15;
716 range->txpower[6] = 17;
717 range->txpower[7] = 19;
718
719 range->num_txpower = 8;
720 range->txpower_capa = IW_TXPOW_DBM;
721 range->txpower_capa |= IW_TXPOW_RANGE;
722
723 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
724 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
725 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
726 range->event_capa[1] = IW_EVENT_CAPA_K_1;
727
728 if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
729 range->enc_capa = IW_ENC_CAPA_WPA
730 | IW_ENC_CAPA_WPA2
731 | IW_ENC_CAPA_CIPHER_TKIP
732 | IW_ENC_CAPA_CIPHER_CCMP;
733 }
734
Holger Schurig9012b282007-05-25 11:27:16 -0400735out:
736 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200737 return 0;
738}
739
740static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
741 struct iw_param *vwrq, char *extra)
742{
743 wlan_private *priv = dev->priv;
744 wlan_adapter *adapter = priv->adapter;
745
Holger Schurig9012b282007-05-25 11:27:16 -0400746 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200747
748 /* PS is currently supported only in Infrastructure mode
749 * Remove this check if it is to be supported in IBSS mode also
750 */
751
752 if (vwrq->disabled) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400753 adapter->psmode = WLAN802_11POWERMODECAM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200754 if (adapter->psstate != PS_STATE_FULL_POWER) {
Dan Williams0aef64d2007-08-02 11:31:18 -0400755 libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200756 }
757
758 return 0;
759 }
760
761 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
Holger Schurig9012b282007-05-25 11:27:16 -0400762 lbs_deb_wext(
763 "setting power timeout is not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200764 return -EINVAL;
765 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
Holger Schurig9012b282007-05-25 11:27:16 -0400766 lbs_deb_wext("setting power period not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200767 return -EINVAL;
768 }
769
Dan Williams0aef64d2007-08-02 11:31:18 -0400770 if (adapter->psmode != WLAN802_11POWERMODECAM) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200771 return 0;
772 }
773
Dan Williams0aef64d2007-08-02 11:31:18 -0400774 adapter->psmode = WLAN802_11POWERMODEMAX_PSP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200775
Dan Williams0aef64d2007-08-02 11:31:18 -0400776 if (adapter->connect_status == LIBERTAS_CONNECTED) {
777 libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200778 }
779
Holger Schurig9012b282007-05-25 11:27:16 -0400780 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200781 return 0;
782}
783
784static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
785 struct iw_param *vwrq, char *extra)
786{
787 wlan_private *priv = dev->priv;
788 wlan_adapter *adapter = priv->adapter;
789 int mode;
790
Holger Schurig9012b282007-05-25 11:27:16 -0400791 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200792
793 mode = adapter->psmode;
794
Dan Williams0aef64d2007-08-02 11:31:18 -0400795 if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM))
796 || adapter->connect_status == LIBERTAS_DISCONNECTED)
Holger Schurig9012b282007-05-25 11:27:16 -0400797 {
798 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200799 }
800
801 vwrq->value = 0;
802
Holger Schurig9012b282007-05-25 11:27:16 -0400803out:
804 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200805 return 0;
806}
807
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200808static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
809{
810 enum {
811 POOR = 30,
812 FAIR = 60,
813 GOOD = 80,
814 VERY_GOOD = 90,
815 EXCELLENT = 95,
816 PERFECT = 100
817 };
818 wlan_private *priv = dev->priv;
819 wlan_adapter *adapter = priv->adapter;
820 u32 rssi_qual;
821 u32 tx_qual;
822 u32 quality = 0;
823 int stats_valid = 0;
824 u8 rssi;
825 u32 tx_retries;
826
Holger Schurig9012b282007-05-25 11:27:16 -0400827 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200828
Dan Williams0dc5a292007-05-10 22:58:02 -0400829 priv->wstats.status = adapter->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200830
831 /* If we're not associated, all quality values are meaningless */
Dan Williams0aef64d2007-08-02 11:31:18 -0400832 if (adapter->connect_status != LIBERTAS_CONNECTED)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200833 goto out;
834
835 /* Quality by RSSI */
836 priv->wstats.qual.level =
837 CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
838 adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
839
840 if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
841 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
842 } else {
843 priv->wstats.qual.noise =
844 CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
845 }
846
Holger Schurig9012b282007-05-25 11:27:16 -0400847 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
848 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200849
850 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
851 if (rssi < 15)
852 rssi_qual = rssi * POOR / 10;
853 else if (rssi < 20)
854 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
855 else if (rssi < 30)
856 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
857 else if (rssi < 40)
858 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
859 10 + GOOD;
860 else
861 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
862 10 + VERY_GOOD;
863 quality = rssi_qual;
864
865 /* Quality by TX errors */
866 priv->wstats.discard.retries = priv->stats.tx_errors;
867
Dan Williams8362cd42007-08-03 09:40:55 -0400868 tx_retries = le32_to_cpu(adapter->logmsg.retry);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200869
870 if (tx_retries > 75)
871 tx_qual = (90 - tx_retries) * POOR / 15;
872 else if (tx_retries > 70)
873 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
874 else if (tx_retries > 65)
875 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
876 else if (tx_retries > 50)
877 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
878 15 + GOOD;
879 else
880 tx_qual = (50 - tx_retries) *
881 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
882 quality = min(quality, tx_qual);
883
Dan Williams8362cd42007-08-03 09:40:55 -0400884 priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
885 priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200886 priv->wstats.discard.retries = tx_retries;
Dan Williams8362cd42007-08-03 09:40:55 -0400887 priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200888
889 /* Calculate quality */
Holger Schurigcad9d9b2007-08-02 13:07:15 -0400890 priv->wstats.qual.qual = min_t(u8, quality, 100);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200891 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
892 stats_valid = 1;
893
894 /* update stats asynchronously for future calls */
Dan Williams0aef64d2007-08-02 11:31:18 -0400895 libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200896 0, 0, NULL);
Dan Williams0aef64d2007-08-02 11:31:18 -0400897 libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200898 0, 0, NULL);
899out:
900 if (!stats_valid) {
901 priv->wstats.miss.beacon = 0;
902 priv->wstats.discard.retries = 0;
903 priv->wstats.qual.qual = 0;
904 priv->wstats.qual.level = 0;
905 priv->wstats.qual.noise = 0;
906 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
907 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
908 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
909 }
910
Holger Schurig9012b282007-05-25 11:27:16 -0400911 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200912 return &priv->wstats;
913
914
915}
916
917static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
918 struct iw_freq *fwrq, char *extra)
919{
Dan Williamsef9a2642007-05-25 16:46:33 -0400920 int ret = -EINVAL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200921 wlan_private *priv = dev->priv;
922 wlan_adapter *adapter = priv->adapter;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200923 struct chan_freq_power *cfp;
Dan Williamsef9a2642007-05-25 16:46:33 -0400924 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200925
Holger Schurig9012b282007-05-25 11:27:16 -0400926 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200927
Dan Williamsef9a2642007-05-25 16:46:33 -0400928 mutex_lock(&adapter->lock);
929 assoc_req = wlan_get_association_request(adapter);
930 if (!assoc_req) {
931 ret = -ENOMEM;
932 goto out;
933 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200934
Dan Williamsef9a2642007-05-25 16:46:33 -0400935 /* If setting by frequency, convert to a channel */
936 if (fwrq->e == 1) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200937 long f = fwrq->m / 100000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200938
939 cfp = find_cfp_by_band_and_freq(adapter, 0, f);
940 if (!cfp) {
Holger Schurig9012b282007-05-25 11:27:16 -0400941 lbs_deb_wext("invalid freq %ld\n", f);
Dan Williamsef9a2642007-05-25 16:46:33 -0400942 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200943 }
944
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200945 fwrq->e = 0;
Dan Williamsef9a2642007-05-25 16:46:33 -0400946 fwrq->m = (int) cfp->channel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200947 }
948
Dan Williamsef9a2642007-05-25 16:46:33 -0400949 /* Setting by channel number */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200950 if (fwrq->m > 1000 || fwrq->e > 0) {
Dan Williamsef9a2642007-05-25 16:46:33 -0400951 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200952 }
953
Dan Williamsef9a2642007-05-25 16:46:33 -0400954 cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m);
955 if (!cfp) {
956 goto out;
957 }
958
959 assoc_req->channel = fwrq->m;
960 ret = 0;
961
Holger Schurig9012b282007-05-25 11:27:16 -0400962out:
Dan Williamsef9a2642007-05-25 16:46:33 -0400963 if (ret == 0) {
964 set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +0200965 libertas_postpone_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400966 } else {
Holger Schurig9f9dac22007-10-26 10:12:14 +0200967 libertas_cancel_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400968 }
969 mutex_unlock(&adapter->lock);
970
971 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
972 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200973}
974
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200975static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
976 struct iw_param *vwrq, char *extra)
977{
978 wlan_private *priv = dev->priv;
979 wlan_adapter *adapter = priv->adapter;
Dan Williams8c512762007-08-02 11:40:45 -0400980 u32 new_rate;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200981 u16 action;
Dan Williams8c512762007-08-02 11:40:45 -0400982 int ret = -EINVAL;
983 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200984
Holger Schurig9012b282007-05-25 11:27:16 -0400985 lbs_deb_enter(LBS_DEB_WEXT);
Holger Schurig9012b282007-05-25 11:27:16 -0400986 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200987
Dan Williams8c512762007-08-02 11:40:45 -0400988 /* Auto rate? */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200989 if (vwrq->value == -1) {
Dan Williams8c512762007-08-02 11:40:45 -0400990 action = CMD_ACT_SET_TX_AUTO;
991 adapter->auto_rate = 1;
992 adapter->cur_rate = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200993 } else {
Dan Williams8c512762007-08-02 11:40:45 -0400994 if (vwrq->value % 100000)
995 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200996
997 memset(rates, 0, sizeof(rates));
Dan Williams8c512762007-08-02 11:40:45 -0400998 copy_active_data_rates(adapter, rates);
999 new_rate = vwrq->value / 500000;
1000 if (!memchr(rates, new_rate, sizeof(rates))) {
1001 lbs_pr_alert("fixed data rate 0x%X out of range\n",
1002 new_rate);
1003 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001004 }
1005
Dan Williams8c512762007-08-02 11:40:45 -04001006 adapter->cur_rate = new_rate;
Dan Williamsffcae952007-08-02 11:35:46 -04001007 action = CMD_ACT_SET_TX_FIX_RATE;
Dan Williams8c512762007-08-02 11:40:45 -04001008 adapter->auto_rate = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001009 }
1010
Dan Williams0aef64d2007-08-02 11:31:18 -04001011 ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
1012 action, CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001013
Dan Williams8c512762007-08-02 11:40:45 -04001014out:
Holger Schurig9012b282007-05-25 11:27:16 -04001015 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001016 return ret;
1017}
1018
1019static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
1020 struct iw_param *vwrq, char *extra)
1021{
1022 wlan_private *priv = dev->priv;
1023 wlan_adapter *adapter = priv->adapter;
1024
Holger Schurig9012b282007-05-25 11:27:16 -04001025 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001026
Dan Williams8c512762007-08-02 11:40:45 -04001027 if (adapter->connect_status == LIBERTAS_CONNECTED) {
1028 vwrq->value = adapter->cur_rate * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001029
Dan Williams8c512762007-08-02 11:40:45 -04001030 if (adapter->auto_rate)
1031 vwrq->fixed = 0;
1032 else
1033 vwrq->fixed = 1;
1034
1035 } else {
1036 vwrq->fixed = 0;
1037 vwrq->value = 0;
1038 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001039
Holger Schurig9012b282007-05-25 11:27:16 -04001040 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001041 return 0;
1042}
1043
1044static int wlan_set_mode(struct net_device *dev,
1045 struct iw_request_info *info, u32 * uwrq, char *extra)
1046{
1047 int ret = 0;
1048 wlan_private *priv = dev->priv;
1049 wlan_adapter *adapter = priv->adapter;
1050 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001051
Holger Schurig9012b282007-05-25 11:27:16 -04001052 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001053
Dan Williams0dc5a292007-05-10 22:58:02 -04001054 if ( (*uwrq != IW_MODE_ADHOC)
1055 && (*uwrq != IW_MODE_INFRA)
1056 && (*uwrq != IW_MODE_AUTO)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001057 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
Dan Williams0dc5a292007-05-10 22:58:02 -04001058 ret = -EINVAL;
1059 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001060 }
1061
1062 mutex_lock(&adapter->lock);
1063 assoc_req = wlan_get_association_request(adapter);
1064 if (!assoc_req) {
1065 ret = -ENOMEM;
Holger Schurig9f9dac22007-10-26 10:12:14 +02001066 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001067 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001068 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001069 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001070 libertas_postpone_association_work(priv);
Holger Schurig9012b282007-05-25 11:27:16 -04001071 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001072 }
1073 mutex_unlock(&adapter->lock);
1074
Dan Williams0dc5a292007-05-10 22:58:02 -04001075out:
Holger Schurig9012b282007-05-25 11:27:16 -04001076 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001077 return ret;
1078}
1079
1080
1081/**
1082 * @brief Get Encryption key
1083 *
1084 * @param dev A pointer to net_device structure
1085 * @param info A pointer to iw_request_info structure
1086 * @param vwrq A pointer to iw_param structure
1087 * @param extra A pointer to extra data buf
1088 * @return 0 --success, otherwise fail
1089 */
1090static int wlan_get_encode(struct net_device *dev,
1091 struct iw_request_info *info,
1092 struct iw_point *dwrq, u8 * extra)
1093{
1094 wlan_private *priv = dev->priv;
1095 wlan_adapter *adapter = priv->adapter;
1096 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1097
Holger Schurig9012b282007-05-25 11:27:16 -04001098 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001099
Holger Schurig9012b282007-05-25 11:27:16 -04001100 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001101 dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
1102
1103 dwrq->flags = 0;
1104
1105 /* Authentication method */
Dan Williams6affe782007-05-10 22:56:42 -04001106 switch (adapter->secinfo.auth_mode) {
1107 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001108 dwrq->flags = IW_ENCODE_OPEN;
1109 break;
1110
Dan Williams6affe782007-05-10 22:56:42 -04001111 case IW_AUTH_ALG_SHARED_KEY:
1112 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001113 dwrq->flags = IW_ENCODE_RESTRICTED;
1114 break;
1115 default:
1116 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1117 break;
1118 }
1119
Dan Williams889c05b2007-05-10 22:57:23 -04001120 if ( adapter->secinfo.wep_enabled
1121 || adapter->secinfo.WPAenabled
1122 || adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001123 dwrq->flags &= ~IW_ENCODE_DISABLED;
1124 } else {
1125 dwrq->flags |= IW_ENCODE_DISABLED;
1126 }
1127
1128 memset(extra, 0, 16);
1129
1130 mutex_lock(&adapter->lock);
1131
1132 /* Default to returning current transmit key */
1133 if (index < 0)
1134 index = adapter->wep_tx_keyidx;
1135
Dan Williams889c05b2007-05-10 22:57:23 -04001136 if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001137 memcpy(extra, adapter->wep_keys[index].key,
1138 adapter->wep_keys[index].len);
1139 dwrq->length = adapter->wep_keys[index].len;
1140
1141 dwrq->flags |= (index + 1);
1142 /* Return WEP enabled */
1143 dwrq->flags &= ~IW_ENCODE_DISABLED;
1144 } else if ((adapter->secinfo.WPAenabled)
1145 || (adapter->secinfo.WPA2enabled)) {
1146 /* return WPA enabled */
1147 dwrq->flags &= ~IW_ENCODE_DISABLED;
1148 } else {
1149 dwrq->flags |= IW_ENCODE_DISABLED;
1150 }
1151
1152 mutex_unlock(&adapter->lock);
1153
1154 dwrq->flags |= IW_ENCODE_NOKEY;
1155
Joe Perches0795af52007-10-03 17:59:30 -07001156 lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001157 extra[0], extra[1], extra[2],
1158 extra[3], extra[4], extra[5], dwrq->length);
1159
Holger Schurig9012b282007-05-25 11:27:16 -04001160 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001161
Holger Schurig9012b282007-05-25 11:27:16 -04001162 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001163 return 0;
1164}
1165
1166/**
1167 * @brief Set Encryption key (internal)
1168 *
1169 * @param priv A pointer to private card structure
1170 * @param key_material A pointer to key material
1171 * @param key_length length of key material
1172 * @param index key index to set
1173 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1174 * @return 0 --success, otherwise fail
1175 */
1176static int wlan_set_wep_key(struct assoc_request *assoc_req,
1177 const char *key_material,
1178 u16 key_length,
1179 u16 index,
1180 int set_tx_key)
1181{
Holger Schurig9012b282007-05-25 11:27:16 -04001182 int ret = 0;
Dan Williams1443b652007-08-02 10:45:55 -04001183 struct enc_key *pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001184
Holger Schurig9012b282007-05-25 11:27:16 -04001185 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001186
1187 /* Paranoid validation of key index */
1188 if (index > 3) {
Holger Schurig9012b282007-05-25 11:27:16 -04001189 ret = -EINVAL;
1190 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001191 }
1192
1193 /* validate max key length */
1194 if (key_length > KEY_LEN_WEP_104) {
Holger Schurig9012b282007-05-25 11:27:16 -04001195 ret = -EINVAL;
1196 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001197 }
1198
1199 pkey = &assoc_req->wep_keys[index];
1200
1201 if (key_length > 0) {
Dan Williams1443b652007-08-02 10:45:55 -04001202 memset(pkey, 0, sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001203 pkey->type = KEY_TYPE_ID_WEP;
1204
1205 /* Standardize the key length */
1206 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1207 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1208 memcpy(pkey->key, key_material, key_length);
1209 }
1210
1211 if (set_tx_key) {
1212 /* Ensure the chosen key is valid */
1213 if (!pkey->len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001214 lbs_deb_wext("key not set, so cannot enable it\n");
1215 ret = -EINVAL;
1216 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001217 }
1218 assoc_req->wep_tx_keyidx = index;
1219 }
1220
Dan Williams889c05b2007-05-10 22:57:23 -04001221 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001222
Holger Schurig9012b282007-05-25 11:27:16 -04001223out:
1224 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1225 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001226}
1227
1228static int validate_key_index(u16 def_index, u16 raw_index,
1229 u16 *out_index, u16 *is_default)
1230{
1231 if (!out_index || !is_default)
1232 return -EINVAL;
1233
1234 /* Verify index if present, otherwise use default TX key index */
1235 if (raw_index > 0) {
1236 if (raw_index > 4)
1237 return -EINVAL;
1238 *out_index = raw_index - 1;
1239 } else {
1240 *out_index = def_index;
1241 *is_default = 1;
1242 }
1243 return 0;
1244}
1245
1246static void disable_wep(struct assoc_request *assoc_req)
1247{
1248 int i;
1249
Dan Williams90a42212007-05-25 23:01:24 -04001250 lbs_deb_enter(LBS_DEB_WEXT);
1251
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001252 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001253 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001254
1255 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001256 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001257 for (i = 0; i < 4; i++)
1258 assoc_req->wep_keys[i].len = 0;
1259
1260 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1261 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
Dan Williams90a42212007-05-25 23:01:24 -04001262
1263 lbs_deb_leave(LBS_DEB_WEXT);
1264}
1265
1266static void disable_wpa(struct assoc_request *assoc_req)
1267{
1268 lbs_deb_enter(LBS_DEB_WEXT);
1269
Dan Williams1443b652007-08-02 10:45:55 -04001270 memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001271 assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1272 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1273
Dan Williams1443b652007-08-02 10:45:55 -04001274 memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001275 assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1276 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1277
1278 assoc_req->secinfo.WPAenabled = 0;
1279 assoc_req->secinfo.WPA2enabled = 0;
1280 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1281
1282 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001283}
1284
1285/**
1286 * @brief Set Encryption key
1287 *
1288 * @param dev A pointer to net_device structure
1289 * @param info A pointer to iw_request_info structure
1290 * @param vwrq A pointer to iw_param structure
1291 * @param extra A pointer to extra data buf
1292 * @return 0 --success, otherwise fail
1293 */
1294static int wlan_set_encode(struct net_device *dev,
1295 struct iw_request_info *info,
1296 struct iw_point *dwrq, char *extra)
1297{
1298 int ret = 0;
1299 wlan_private *priv = dev->priv;
1300 wlan_adapter *adapter = priv->adapter;
1301 struct assoc_request * assoc_req;
1302 u16 is_default = 0, index = 0, set_tx_key = 0;
1303
Holger Schurig9012b282007-05-25 11:27:16 -04001304 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001305
1306 mutex_lock(&adapter->lock);
1307 assoc_req = wlan_get_association_request(adapter);
1308 if (!assoc_req) {
1309 ret = -ENOMEM;
1310 goto out;
1311 }
1312
1313 if (dwrq->flags & IW_ENCODE_DISABLED) {
1314 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001315 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001316 goto out;
1317 }
1318
1319 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1320 (dwrq->flags & IW_ENCODE_INDEX),
1321 &index, &is_default);
1322 if (ret) {
1323 ret = -EINVAL;
1324 goto out;
1325 }
1326
1327 /* If WEP isn't enabled, or if there is no key data but a valid
1328 * index, set the TX key.
1329 */
Dan Williams889c05b2007-05-10 22:57:23 -04001330 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001331 set_tx_key = 1;
1332
1333 ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
1334 if (ret)
1335 goto out;
1336
1337 if (dwrq->length)
1338 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1339 if (set_tx_key)
1340 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1341
1342 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001343 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001344 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001345 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001346 }
1347
1348out:
1349 if (ret == 0) {
1350 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001351 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001352 } else {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001353 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001354 }
1355 mutex_unlock(&adapter->lock);
1356
Holger Schurig9012b282007-05-25 11:27:16 -04001357 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001358 return ret;
1359}
1360
1361/**
1362 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1363 *
1364 * @param dev A pointer to net_device structure
1365 * @param info A pointer to iw_request_info structure
1366 * @param vwrq A pointer to iw_param structure
1367 * @param extra A pointer to extra data buf
1368 * @return 0 on success, otherwise failure
1369 */
1370static int wlan_get_encodeext(struct net_device *dev,
1371 struct iw_request_info *info,
1372 struct iw_point *dwrq,
1373 char *extra)
1374{
1375 int ret = -EINVAL;
1376 wlan_private *priv = dev->priv;
1377 wlan_adapter *adapter = priv->adapter;
1378 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1379 int index, max_key_len;
1380
Holger Schurig9012b282007-05-25 11:27:16 -04001381 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001382
1383 max_key_len = dwrq->length - sizeof(*ext);
1384 if (max_key_len < 0)
1385 goto out;
1386
1387 index = dwrq->flags & IW_ENCODE_INDEX;
1388 if (index) {
1389 if (index < 1 || index > 4)
1390 goto out;
1391 index--;
1392 } else {
1393 index = adapter->wep_tx_keyidx;
1394 }
1395
Roel Kluinf59d9782007-10-26 21:51:26 +02001396 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001397 ext->alg != IW_ENCODE_ALG_WEP) {
Dan Williams0dc5a292007-05-10 22:58:02 -04001398 if (index != 0 || adapter->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001399 goto out;
1400 }
1401
1402 dwrq->flags = index + 1;
1403 memset(ext, 0, sizeof(*ext));
1404
Dan Williams889c05b2007-05-10 22:57:23 -04001405 if ( !adapter->secinfo.wep_enabled
1406 && !adapter->secinfo.WPAenabled
1407 && !adapter->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001408 ext->alg = IW_ENCODE_ALG_NONE;
1409 ext->key_len = 0;
1410 dwrq->flags |= IW_ENCODE_DISABLED;
1411 } else {
1412 u8 *key = NULL;
1413
Dan Williams889c05b2007-05-10 22:57:23 -04001414 if ( adapter->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001415 && !adapter->secinfo.WPAenabled
1416 && !adapter->secinfo.WPA2enabled) {
Dan Williams90a42212007-05-25 23:01:24 -04001417 /* WEP */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001418 ext->alg = IW_ENCODE_ALG_WEP;
1419 ext->key_len = adapter->wep_keys[index].len;
1420 key = &adapter->wep_keys[index].key[0];
Dan Williams889c05b2007-05-10 22:57:23 -04001421 } else if ( !adapter->secinfo.wep_enabled
1422 && (adapter->secinfo.WPAenabled ||
1423 adapter->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001424 /* WPA */
Dan Williams1443b652007-08-02 10:45:55 -04001425 struct enc_key * pkey = NULL;
Dan Williams90a42212007-05-25 23:01:24 -04001426
1427 if ( adapter->wpa_mcast_key.len
1428 && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1429 pkey = &adapter->wpa_mcast_key;
1430 else if ( adapter->wpa_unicast_key.len
1431 && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1432 pkey = &adapter->wpa_unicast_key;
1433
1434 if (pkey) {
1435 if (pkey->type == KEY_TYPE_ID_AES) {
1436 ext->alg = IW_ENCODE_ALG_CCMP;
1437 } else {
1438 ext->alg = IW_ENCODE_ALG_TKIP;
1439 }
1440 ext->key_len = pkey->len;
1441 key = &pkey->key[0];
1442 } else {
1443 ext->alg = IW_ENCODE_ALG_TKIP;
1444 ext->key_len = 0;
1445 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001446 } else {
1447 goto out;
1448 }
1449
1450 if (ext->key_len > max_key_len) {
1451 ret = -E2BIG;
1452 goto out;
1453 }
1454
1455 if (ext->key_len)
1456 memcpy(ext->key, key, ext->key_len);
1457 else
1458 dwrq->flags |= IW_ENCODE_NOKEY;
1459 dwrq->flags |= IW_ENCODE_ENABLED;
1460 }
1461 ret = 0;
1462
1463out:
Holger Schurig9012b282007-05-25 11:27:16 -04001464 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001465 return ret;
1466}
1467
1468/**
1469 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1470 *
1471 * @param dev A pointer to net_device structure
1472 * @param info A pointer to iw_request_info structure
1473 * @param vwrq A pointer to iw_param structure
1474 * @param extra A pointer to extra data buf
1475 * @return 0 --success, otherwise fail
1476 */
1477static int wlan_set_encodeext(struct net_device *dev,
1478 struct iw_request_info *info,
1479 struct iw_point *dwrq,
1480 char *extra)
1481{
1482 int ret = 0;
1483 wlan_private *priv = dev->priv;
1484 wlan_adapter *adapter = priv->adapter;
1485 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1486 int alg = ext->alg;
1487 struct assoc_request * assoc_req;
1488
Holger Schurig9012b282007-05-25 11:27:16 -04001489 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001490
1491 mutex_lock(&adapter->lock);
1492 assoc_req = wlan_get_association_request(adapter);
1493 if (!assoc_req) {
1494 ret = -ENOMEM;
1495 goto out;
1496 }
1497
1498 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1499 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001500 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001501 } else if (alg == IW_ENCODE_ALG_WEP) {
1502 u16 is_default = 0, index, set_tx_key = 0;
1503
1504 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1505 (dwrq->flags & IW_ENCODE_INDEX),
1506 &index, &is_default);
1507 if (ret)
1508 goto out;
1509
1510 /* If WEP isn't enabled, or if there is no key data but a valid
1511 * index, or if the set-TX-key flag was passed, set the TX key.
1512 */
Dan Williams889c05b2007-05-10 22:57:23 -04001513 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001514 || (dwrq->length == 0 && !is_default)
1515 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1516 set_tx_key = 1;
1517
1518 /* Copy key to driver */
1519 ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
1520 set_tx_key);
1521 if (ret)
1522 goto out;
1523
1524 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001525 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001526 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001527 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001528 }
1529
1530 /* Mark the various WEP bits as modified */
1531 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1532 if (dwrq->length)
1533 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1534 if (set_tx_key)
1535 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001536 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
Dan Williams1443b652007-08-02 10:45:55 -04001537 struct enc_key * pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001538
1539 /* validate key length */
1540 if (((alg == IW_ENCODE_ALG_TKIP)
1541 && (ext->key_len != KEY_LEN_WPA_TKIP))
1542 || ((alg == IW_ENCODE_ALG_CCMP)
1543 && (ext->key_len != KEY_LEN_WPA_AES))) {
Joe Perches8376e7a2007-11-19 17:48:27 -08001544 lbs_deb_wext("invalid size %d for key of alg "
Holger Schurig9012b282007-05-25 11:27:16 -04001545 "type %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001546 ext->key_len,
1547 alg);
1548 ret = -EINVAL;
1549 goto out;
1550 }
1551
Dan Williams90a42212007-05-25 23:01:24 -04001552 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001553 pkey = &assoc_req->wpa_mcast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001554 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1555 } else {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001556 pkey = &assoc_req->wpa_unicast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001557 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1558 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001559
Dan Williams1443b652007-08-02 10:45:55 -04001560 memset(pkey, 0, sizeof (struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001561 memcpy(pkey->key, ext->key, ext->key_len);
1562 pkey->len = ext->key_len;
Dan Williams90a42212007-05-25 23:01:24 -04001563 if (pkey->len)
1564 pkey->flags |= KEY_INFO_WPA_ENABLED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001565
Dan Williams90a42212007-05-25 23:01:24 -04001566 /* Do this after zeroing key structure */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001567 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1568 pkey->flags |= KEY_INFO_WPA_MCAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001569 } else {
1570 pkey->flags |= KEY_INFO_WPA_UNICAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001571 }
1572
Dan Williams90a42212007-05-25 23:01:24 -04001573 if (alg == IW_ENCODE_ALG_TKIP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001574 pkey->type = KEY_TYPE_ID_TKIP;
Dan Williams90a42212007-05-25 23:01:24 -04001575 } else if (alg == IW_ENCODE_ALG_CCMP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001576 pkey->type = KEY_TYPE_ID_AES;
Dan Williams90a42212007-05-25 23:01:24 -04001577 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001578
1579 /* If WPA isn't enabled yet, do that now */
1580 if ( assoc_req->secinfo.WPAenabled == 0
1581 && assoc_req->secinfo.WPA2enabled == 0) {
1582 assoc_req->secinfo.WPAenabled = 1;
1583 assoc_req->secinfo.WPA2enabled = 1;
1584 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1585 }
1586
1587 disable_wep (assoc_req);
1588 }
1589
1590out:
1591 if (ret == 0) {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001592 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001593 } else {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001594 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001595 }
1596 mutex_unlock(&adapter->lock);
1597
Holger Schurig9012b282007-05-25 11:27:16 -04001598 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001599 return ret;
1600}
1601
1602
1603static int wlan_set_genie(struct net_device *dev,
1604 struct iw_request_info *info,
1605 struct iw_point *dwrq,
1606 char *extra)
1607{
1608 wlan_private *priv = dev->priv;
1609 wlan_adapter *adapter = priv->adapter;
1610 int ret = 0;
1611 struct assoc_request * assoc_req;
1612
Holger Schurig9012b282007-05-25 11:27:16 -04001613 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001614
1615 mutex_lock(&adapter->lock);
1616 assoc_req = wlan_get_association_request(adapter);
1617 if (!assoc_req) {
1618 ret = -ENOMEM;
1619 goto out;
1620 }
1621
1622 if (dwrq->length > MAX_WPA_IE_LEN ||
1623 (dwrq->length && extra == NULL)) {
1624 ret = -EINVAL;
1625 goto out;
1626 }
1627
1628 if (dwrq->length) {
1629 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1630 assoc_req->wpa_ie_len = dwrq->length;
1631 } else {
1632 memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
1633 assoc_req->wpa_ie_len = 0;
1634 }
1635
1636out:
1637 if (ret == 0) {
1638 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001639 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001640 } else {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001641 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001642 }
1643 mutex_unlock(&adapter->lock);
1644
Holger Schurig9012b282007-05-25 11:27:16 -04001645 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001646 return ret;
1647}
1648
1649static int wlan_get_genie(struct net_device *dev,
1650 struct iw_request_info *info,
1651 struct iw_point *dwrq,
1652 char *extra)
1653{
Holger Schurig9012b282007-05-25 11:27:16 -04001654 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001655 wlan_private *priv = dev->priv;
1656 wlan_adapter *adapter = priv->adapter;
1657
Holger Schurig9012b282007-05-25 11:27:16 -04001658 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001659
1660 if (adapter->wpa_ie_len == 0) {
1661 dwrq->length = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001662 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001663 }
1664
1665 if (dwrq->length < adapter->wpa_ie_len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001666 ret = -E2BIG;
1667 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001668 }
1669
1670 dwrq->length = adapter->wpa_ie_len;
1671 memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
1672
Holger Schurig9012b282007-05-25 11:27:16 -04001673out:
1674 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1675 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001676}
1677
1678
1679static int wlan_set_auth(struct net_device *dev,
1680 struct iw_request_info *info,
1681 struct iw_param *dwrq,
1682 char *extra)
1683{
1684 wlan_private *priv = dev->priv;
1685 wlan_adapter *adapter = priv->adapter;
1686 struct assoc_request * assoc_req;
1687 int ret = 0;
1688 int updated = 0;
1689
Holger Schurig9012b282007-05-25 11:27:16 -04001690 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001691
1692 mutex_lock(&adapter->lock);
1693 assoc_req = wlan_get_association_request(adapter);
1694 if (!assoc_req) {
1695 ret = -ENOMEM;
1696 goto out;
1697 }
1698
1699 switch (dwrq->flags & IW_AUTH_INDEX) {
1700 case IW_AUTH_TKIP_COUNTERMEASURES:
1701 case IW_AUTH_CIPHER_PAIRWISE:
1702 case IW_AUTH_CIPHER_GROUP:
1703 case IW_AUTH_KEY_MGMT:
Dan Williams90a42212007-05-25 23:01:24 -04001704 case IW_AUTH_DROP_UNENCRYPTED:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001705 /*
1706 * libertas does not use these parameters
1707 */
1708 break;
1709
1710 case IW_AUTH_WPA_VERSION:
1711 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1712 assoc_req->secinfo.WPAenabled = 0;
1713 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001714 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001715 }
1716 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1717 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001718 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001719 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001720 }
1721 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1722 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001723 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001724 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001725 }
1726 updated = 1;
1727 break;
1728
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001729 case IW_AUTH_80211_AUTH_ALG:
1730 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04001731 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001732 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04001733 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001734 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04001735 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001736 } else {
1737 ret = -EINVAL;
1738 }
1739 updated = 1;
1740 break;
1741
1742 case IW_AUTH_WPA_ENABLED:
1743 if (dwrq->value) {
1744 if (!assoc_req->secinfo.WPAenabled &&
1745 !assoc_req->secinfo.WPA2enabled) {
1746 assoc_req->secinfo.WPAenabled = 1;
1747 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001748 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001749 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001750 }
1751 } else {
1752 assoc_req->secinfo.WPAenabled = 0;
1753 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001754 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001755 }
1756 updated = 1;
1757 break;
1758
1759 default:
1760 ret = -EOPNOTSUPP;
1761 break;
1762 }
1763
1764out:
1765 if (ret == 0) {
1766 if (updated)
1767 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001768 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001769 } else if (ret != -EOPNOTSUPP) {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001770 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001771 }
1772 mutex_unlock(&adapter->lock);
1773
Holger Schurig9012b282007-05-25 11:27:16 -04001774 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001775 return ret;
1776}
1777
1778static int wlan_get_auth(struct net_device *dev,
1779 struct iw_request_info *info,
1780 struct iw_param *dwrq,
1781 char *extra)
1782{
Holger Schurig9012b282007-05-25 11:27:16 -04001783 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001784 wlan_private *priv = dev->priv;
1785 wlan_adapter *adapter = priv->adapter;
1786
Holger Schurig9012b282007-05-25 11:27:16 -04001787 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001788
1789 switch (dwrq->flags & IW_AUTH_INDEX) {
1790 case IW_AUTH_WPA_VERSION:
1791 dwrq->value = 0;
1792 if (adapter->secinfo.WPAenabled)
1793 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
1794 if (adapter->secinfo.WPA2enabled)
1795 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1796 if (!dwrq->value)
1797 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1798 break;
1799
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001800 case IW_AUTH_80211_AUTH_ALG:
Dan Williams6affe782007-05-10 22:56:42 -04001801 dwrq->value = adapter->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001802 break;
1803
1804 case IW_AUTH_WPA_ENABLED:
1805 if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
1806 dwrq->value = 1;
1807 break;
1808
1809 default:
Holger Schurig9012b282007-05-25 11:27:16 -04001810 ret = -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001811 }
1812
Holger Schurig9012b282007-05-25 11:27:16 -04001813 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1814 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001815}
1816
1817
1818static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
1819 struct iw_param *vwrq, char *extra)
1820{
1821 int ret = 0;
1822 wlan_private *priv = dev->priv;
1823 wlan_adapter *adapter = priv->adapter;
1824
1825 u16 dbm;
1826
Holger Schurig9012b282007-05-25 11:27:16 -04001827 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001828
1829 if (vwrq->disabled) {
1830 wlan_radio_ioctl(priv, RADIO_OFF);
1831 return 0;
1832 }
1833
Dan Williams0aef64d2007-08-02 11:31:18 -04001834 adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001835
1836 wlan_radio_ioctl(priv, RADIO_ON);
1837
Jean Tourrilhes9483f032007-08-02 13:16:30 -04001838 /* Userspace check in iwrange if it should use dBm or mW,
1839 * therefore this should never happen... Jean II */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001840 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
Jean Tourrilhes9483f032007-08-02 13:16:30 -04001841 return -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001842 } else
1843 dbm = (u16) vwrq->value;
1844
1845 /* auto tx power control */
1846
1847 if (vwrq->fixed == 0)
1848 dbm = 0xffff;
1849
Holger Schurig9012b282007-05-25 11:27:16 -04001850 lbs_deb_wext("txpower set %d dbm\n", dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001851
1852 ret = libertas_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001853 CMD_802_11_RF_TX_POWER,
1854 CMD_ACT_TX_POWER_OPT_SET_LOW,
1855 CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001856
Holger Schurig9012b282007-05-25 11:27:16 -04001857 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001858 return ret;
1859}
1860
1861static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
1862 struct iw_point *dwrq, char *extra)
1863{
1864 wlan_private *priv = dev->priv;
1865 wlan_adapter *adapter = priv->adapter;
1866
Holger Schurig9012b282007-05-25 11:27:16 -04001867 lbs_deb_enter(LBS_DEB_WEXT);
1868
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001869 /*
1870 * Note : if dwrq->flags != 0, we should get the relevant SSID from
1871 * the SSID list...
1872 */
1873
1874 /*
1875 * Get the current SSID
1876 */
Dan Williams0aef64d2007-08-02 11:31:18 -04001877 if (adapter->connect_status == LIBERTAS_CONNECTED) {
Dan Williamsd8efea22007-05-28 23:54:55 -04001878 memcpy(extra, adapter->curbssparams.ssid,
1879 adapter->curbssparams.ssid_len);
1880 extra[adapter->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001881 } else {
1882 memset(extra, 0, 32);
Dan Williamsd8efea22007-05-28 23:54:55 -04001883 extra[adapter->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001884 }
1885 /*
1886 * If none, we may want to get the one that was set
1887 */
1888
Jean Tourrilhes9483f032007-08-02 13:16:30 -04001889 dwrq->length = adapter->curbssparams.ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001890
1891 dwrq->flags = 1; /* active */
1892
Holger Schurig9012b282007-05-25 11:27:16 -04001893 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001894 return 0;
1895}
1896
1897static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
1898 struct iw_point *dwrq, char *extra)
1899{
1900 wlan_private *priv = dev->priv;
1901 wlan_adapter *adapter = priv->adapter;
1902 int ret = 0;
Dan Williamsd8efea22007-05-28 23:54:55 -04001903 u8 ssid[IW_ESSID_MAX_SIZE];
1904 u8 ssid_len = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001905 struct assoc_request * assoc_req;
Dan Williamsd8efea22007-05-28 23:54:55 -04001906 int in_ssid_len = dwrq->length;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001907
Holger Schurig9012b282007-05-25 11:27:16 -04001908 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001909
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001910 /* Check the size of the string */
Dan Williamsd8efea22007-05-28 23:54:55 -04001911 if (in_ssid_len > IW_ESSID_MAX_SIZE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001912 ret = -E2BIG;
1913 goto out;
1914 }
1915
Dan Williamsd8efea22007-05-28 23:54:55 -04001916 memset(&ssid, 0, sizeof(ssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001917
Dan Williamsd8efea22007-05-28 23:54:55 -04001918 if (!dwrq->flags || !in_ssid_len) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001919 /* "any" SSID requested; leave SSID blank */
1920 } else {
1921 /* Specific SSID requested */
Dan Williamsd8efea22007-05-28 23:54:55 -04001922 memcpy(&ssid, extra, in_ssid_len);
1923 ssid_len = in_ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001924 }
1925
Dan Williamsd8efea22007-05-28 23:54:55 -04001926 if (!ssid_len) {
1927 lbs_deb_wext("requested any SSID\n");
1928 } else {
1929 lbs_deb_wext("requested SSID '%s'\n",
1930 escape_essid(ssid, ssid_len));
1931 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001932
1933out:
1934 mutex_lock(&adapter->lock);
1935 if (ret == 0) {
1936 /* Get or create the current association request */
1937 assoc_req = wlan_get_association_request(adapter);
1938 if (!assoc_req) {
1939 ret = -ENOMEM;
1940 } else {
1941 /* Copy the SSID to the association request */
Dan Williamsd8efea22007-05-28 23:54:55 -04001942 memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
1943 assoc_req->ssid_len = ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001944 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001945 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001946 }
1947 }
1948
1949 /* Cancel the association request if there was an error */
1950 if (ret != 0) {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001951 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001952 }
1953
1954 mutex_unlock(&adapter->lock);
1955
Holger Schurig9012b282007-05-25 11:27:16 -04001956 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001957 return ret;
1958}
1959
1960/**
1961 * @brief Connect to the AP or Ad-hoc Network with specific bssid
1962 *
1963 * @param dev A pointer to net_device structure
1964 * @param info A pointer to iw_request_info structure
1965 * @param awrq A pointer to iw_param structure
1966 * @param extra A pointer to extra data buf
1967 * @return 0 --success, otherwise fail
1968 */
1969static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
1970 struct sockaddr *awrq, char *extra)
1971{
1972 wlan_private *priv = dev->priv;
1973 wlan_adapter *adapter = priv->adapter;
1974 struct assoc_request * assoc_req;
1975 int ret = 0;
Joe Perches0795af52007-10-03 17:59:30 -07001976 DECLARE_MAC_BUF(mac);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001977
Holger Schurig9012b282007-05-25 11:27:16 -04001978 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001979
1980 if (awrq->sa_family != ARPHRD_ETHER)
1981 return -EINVAL;
1982
Joe Perches0795af52007-10-03 17:59:30 -07001983 lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001984
1985 mutex_lock(&adapter->lock);
1986
1987 /* Get or create the current association request */
1988 assoc_req = wlan_get_association_request(adapter);
1989 if (!assoc_req) {
Holger Schurig9f9dac22007-10-26 10:12:14 +02001990 libertas_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001991 ret = -ENOMEM;
1992 } else {
1993 /* Copy the BSSID to the association request */
1994 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
1995 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
Holger Schurig9f9dac22007-10-26 10:12:14 +02001996 libertas_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001997 }
1998
1999 mutex_unlock(&adapter->lock);
2000
2001 return ret;
2002}
2003
2004void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
2005{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002006 char fwver[32];
2007
2008 mutex_lock(&adapter->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002009
David Woodhousee5b3d472007-05-25 23:40:21 -04002010 if (adapter->fwreleasenumber[3] == 0)
2011 sprintf(fwver, "%u.%u.%u",
2012 adapter->fwreleasenumber[2],
2013 adapter->fwreleasenumber[1],
2014 adapter->fwreleasenumber[0]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002015 else
2016 sprintf(fwver, "%u.%u.%u.p%u",
David Woodhousee5b3d472007-05-25 23:40:21 -04002017 adapter->fwreleasenumber[2],
2018 adapter->fwreleasenumber[1],
2019 adapter->fwreleasenumber[0],
2020 adapter->fwreleasenumber[3]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002021
David Woodhousee5b3d472007-05-25 23:40:21 -04002022 mutex_unlock(&adapter->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002023 snprintf(fwversion, maxlen, fwver);
2024}
2025
2026
2027/*
2028 * iwconfig settable callbacks
2029 */
2030static const iw_handler wlan_handler[] = {
2031 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2032 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2033 (iw_handler) NULL, /* SIOCSIWNWID */
2034 (iw_handler) NULL, /* SIOCGIWNWID */
2035 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2036 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2037 (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
2038 (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
2039 (iw_handler) NULL, /* SIOCSIWSENS */
2040 (iw_handler) NULL, /* SIOCGIWSENS */
2041 (iw_handler) NULL, /* SIOCSIWRANGE */
2042 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2043 (iw_handler) NULL, /* SIOCSIWPRIV */
2044 (iw_handler) NULL, /* SIOCGIWPRIV */
2045 (iw_handler) NULL, /* SIOCSIWSTATS */
2046 (iw_handler) NULL, /* SIOCGIWSTATS */
2047 iw_handler_set_spy, /* SIOCSIWSPY */
2048 iw_handler_get_spy, /* SIOCGIWSPY */
2049 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2050 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2051 (iw_handler) wlan_set_wap, /* SIOCSIWAP */
2052 (iw_handler) wlan_get_wap, /* SIOCGIWAP */
2053 (iw_handler) NULL, /* SIOCSIWMLME */
2054 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2055 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2056 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2057 (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
2058 (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
2059 (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
2060 (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
2061 (iw_handler) NULL, /* -- hole -- */
2062 (iw_handler) NULL, /* -- hole -- */
2063 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2064 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2065 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2066 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2067 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2068 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2069 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2070 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2071 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2072 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2073 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2074 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2075 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2076 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2077 (iw_handler) NULL, /* -- hole -- */
2078 (iw_handler) NULL, /* -- hole -- */
2079 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2080 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2081 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2082 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2083 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2084 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2085 (iw_handler) NULL, /* SIOCSIWPMKSA */
2086};
2087
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002088static const iw_handler mesh_wlan_handler[] = {
2089 (iw_handler) NULL, /* SIOCSIWCOMMIT */
2090 (iw_handler) wlan_get_name, /* SIOCGIWNAME */
2091 (iw_handler) NULL, /* SIOCSIWNWID */
2092 (iw_handler) NULL, /* SIOCGIWNWID */
2093 (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
2094 (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
2095 (iw_handler) NULL, /* SIOCSIWMODE */
2096 (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
2097 (iw_handler) NULL, /* SIOCSIWSENS */
2098 (iw_handler) NULL, /* SIOCGIWSENS */
2099 (iw_handler) NULL, /* SIOCSIWRANGE */
2100 (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
2101 (iw_handler) NULL, /* SIOCSIWPRIV */
2102 (iw_handler) NULL, /* SIOCGIWPRIV */
2103 (iw_handler) NULL, /* SIOCSIWSTATS */
2104 (iw_handler) NULL, /* SIOCGIWSTATS */
2105 iw_handler_set_spy, /* SIOCSIWSPY */
2106 iw_handler_get_spy, /* SIOCGIWSPY */
2107 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2108 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2109 (iw_handler) NULL, /* SIOCSIWAP */
2110 (iw_handler) NULL, /* SIOCGIWAP */
2111 (iw_handler) NULL, /* SIOCSIWMLME */
2112 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
2113 (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
2114 (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
2115 (iw_handler) NULL, /* SIOCSIWESSID */
2116 (iw_handler) NULL, /* SIOCGIWESSID */
2117 (iw_handler) NULL, /* SIOCSIWNICKN */
2118 (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
2119 (iw_handler) NULL, /* -- hole -- */
2120 (iw_handler) NULL, /* -- hole -- */
2121 (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
2122 (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
2123 (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
2124 (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
2125 (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
2126 (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
2127 (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
2128 (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
2129 (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
2130 (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
2131 (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
2132 (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
2133 (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
2134 (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
2135 (iw_handler) NULL, /* -- hole -- */
2136 (iw_handler) NULL, /* -- hole -- */
2137 (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
2138 (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
2139 (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
2140 (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
2141 (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
2142 (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
2143 (iw_handler) NULL, /* SIOCSIWPMKSA */
2144};
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002145struct iw_handler_def libertas_handler_def = {
Denis Chengff8ac602007-09-02 18:30:18 +08002146 .num_standard = ARRAY_SIZE(wlan_handler),
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002147 .standard = (iw_handler *) wlan_handler,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002148 .get_wireless_stats = wlan_get_wireless_stats,
2149};
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002150
2151struct iw_handler_def mesh_handler_def = {
Denis Chengff8ac602007-09-02 18:30:18 +08002152 .num_standard = ARRAY_SIZE(mesh_wlan_handler),
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002153 .standard = (iw_handler *) mesh_wlan_handler,
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002154 .get_wireless_stats = wlan_get_wireless_stats,
2155};