blob: 5ccb4e0c8d64aa2c79ec226b95124b418a1c6ad4 [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"
Dan Williams8e3c91b2007-12-11 15:50:59 -050022#include "cmd.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020023
24
Holger Schurig69f90322007-11-23 15:43:44 +010025static inline void lbs_postpone_association_work(struct lbs_private *priv)
Holger Schurig9f9dac22007-10-26 10:12:14 +020026{
David Woodhouseaa21c002007-12-08 20:04:36 +000027 if (priv->surpriseremoved)
Holger Schurig9f9dac22007-10-26 10:12:14 +020028 return;
29 cancel_delayed_work(&priv->assoc_work);
30 queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);
31}
32
Holger Schurig69f90322007-11-23 15:43:44 +010033static inline void lbs_cancel_association_work(struct lbs_private *priv)
Holger Schurig9f9dac22007-10-26 10:12:14 +020034{
35 cancel_delayed_work(&priv->assoc_work);
David Woodhouseaa21c002007-12-08 20:04:36 +000036 kfree(priv->pending_assoc_req);
37 priv->pending_assoc_req = NULL;
Holger Schurig9f9dac22007-10-26 10:12:14 +020038}
39
40
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020041/**
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020042 * @brief Find the channel frequency power info with specific channel
43 *
David Woodhouseaa21c002007-12-08 20:04:36 +000044 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020045 * @param band it can be BAND_A, BAND_G or BAND_B
46 * @param channel the channel for looking
47 * @return A pointer to struct chan_freq_power structure or NULL if not find.
48 */
Holger Schurig69f90322007-11-23 15:43:44 +010049struct chan_freq_power *lbs_find_cfp_by_band_and_channel(
David Woodhouseaa21c002007-12-08 20:04:36 +000050 struct lbs_private *priv,
Holger Schurig69f90322007-11-23 15:43:44 +010051 u8 band,
52 u16 channel)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020053{
54 struct chan_freq_power *cfp = NULL;
55 struct region_channel *rc;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020056 int i, j;
57
David Woodhouseaa21c002007-12-08 20:04:36 +000058 for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
59 rc = &priv->region_channel[j];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020060
David Woodhouseaa21c002007-12-08 20:04:36 +000061 if (priv->enable11d)
62 rc = &priv->universal_channel[j];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020063 if (!rc->valid || !rc->CFP)
64 continue;
65 if (rc->band != band)
66 continue;
67 for (i = 0; i < rc->nrcfp; i++) {
68 if (rc->CFP[i].channel == channel) {
69 cfp = &rc->CFP[i];
70 break;
71 }
72 }
73 }
74
75 if (!cfp && channel)
Holger Schurig10078322007-11-15 18:05:47 -050076 lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "
Holger Schurig9012b282007-05-25 11:27:16 -040077 "cfp by band %d / channel %d\n", band, channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020078
79 return cfp;
80}
81
82/**
83 * @brief Find the channel frequency power info with specific frequency
84 *
David Woodhouseaa21c002007-12-08 20:04:36 +000085 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020086 * @param band it can be BAND_A, BAND_G or BAND_B
87 * @param freq the frequency for looking
88 * @return A pointer to struct chan_freq_power structure or NULL if not find.
89 */
Holger Schurig69f90322007-11-23 15:43:44 +010090static struct chan_freq_power *find_cfp_by_band_and_freq(
David Woodhouseaa21c002007-12-08 20:04:36 +000091 struct lbs_private *priv,
Holger Schurig69f90322007-11-23 15:43:44 +010092 u8 band,
93 u32 freq)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020094{
95 struct chan_freq_power *cfp = NULL;
96 struct region_channel *rc;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020097 int i, j;
98
David Woodhouseaa21c002007-12-08 20:04:36 +000099 for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {
100 rc = &priv->region_channel[j];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200101
David Woodhouseaa21c002007-12-08 20:04:36 +0000102 if (priv->enable11d)
103 rc = &priv->universal_channel[j];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200104 if (!rc->valid || !rc->CFP)
105 continue;
106 if (rc->band != band)
107 continue;
108 for (i = 0; i < rc->nrcfp; i++) {
109 if (rc->CFP[i].freq == freq) {
110 cfp = &rc->CFP[i];
111 break;
112 }
113 }
114 }
115
116 if (!cfp && freq)
Holger Schurig9012b282007-05-25 11:27:16 -0400117 lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "
118 "band %d / freq %d\n", band, freq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200119
120 return cfp;
121}
122
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200123
124/**
125 * @brief Set Radio On/OFF
126 *
Holger Schurig69f90322007-11-23 15:43:44 +0100127 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200128 * @option Radio Option
129 * @return 0 --success, otherwise fail
130 */
Holger Schurig69f90322007-11-23 15:43:44 +0100131static int lbs_radio_ioctl(struct lbs_private *priv, u8 option)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200132{
133 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200134
Holger Schurig9012b282007-05-25 11:27:16 -0400135 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200136
David Woodhouseaa21c002007-12-08 20:04:36 +0000137 if (priv->radioon != option) {
Holger Schurig9012b282007-05-25 11:27:16 -0400138 lbs_deb_wext("switching radio %s\n", option ? "on" : "off");
David Woodhouseaa21c002007-12-08 20:04:36 +0000139 priv->radioon = option;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200140
Holger Schurig10078322007-11-15 18:05:47 -0500141 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400142 CMD_802_11_RADIO_CONTROL,
143 CMD_ACT_SET,
144 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200145 }
146
Holger Schurig9012b282007-05-25 11:27:16 -0400147 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200148 return ret;
149}
150
151/**
Dan Williams8c512762007-08-02 11:40:45 -0400152 * @brief Copy active data rates based on adapter mode and status
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200153 *
David Woodhouseaa21c002007-12-08 20:04:36 +0000154 * @param priv A pointer to struct lbs_private structure
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200155 * @param rate The buf to return the active rates
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200156 */
David Woodhouseaa21c002007-12-08 20:04:36 +0000157static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200158{
Holger Schurig9012b282007-05-25 11:27:16 -0400159 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200160
David Woodhouseaa21c002007-12-08 20:04:36 +0000161 if ((priv->connect_status != LBS_CONNECTED) &&
162 (priv->mesh_connect_status != LBS_CONNECTED))
Holger Schurig10078322007-11-15 18:05:47 -0500163 memcpy(rates, lbs_bg_rates, MAX_RATES);
Dan Williams8c512762007-08-02 11:40:45 -0400164 else
David Woodhouseaa21c002007-12-08 20:04:36 +0000165 memcpy(rates, priv->curbssparams.rates, MAX_RATES);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200166
Dan Williams8c512762007-08-02 11:40:45 -0400167 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200168}
169
Holger Schurig10078322007-11-15 18:05:47 -0500170static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200171 char *cwrq, char *extra)
172{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200173
Holger Schurig9012b282007-05-25 11:27:16 -0400174 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200175
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400176 /* We could add support for 802.11n here as needed. Jean II */
177 snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200178
Holger Schurig9012b282007-05-25 11:27:16 -0400179 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200180 return 0;
181}
182
Holger Schurig10078322007-11-15 18:05:47 -0500183static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200184 struct iw_freq *fwrq, char *extra)
185{
Holger Schurig69f90322007-11-23 15:43:44 +0100186 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200187 struct chan_freq_power *cfp;
188
Holger Schurig9012b282007-05-25 11:27:16 -0400189 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200190
David Woodhouseaa21c002007-12-08 20:04:36 +0000191 cfp = lbs_find_cfp_by_band_and_channel(priv, 0,
192 priv->curbssparams.channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200193
194 if (!cfp) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000195 if (priv->curbssparams.channel)
Holger Schurig9012b282007-05-25 11:27:16 -0400196 lbs_deb_wext("invalid channel %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +0000197 priv->curbssparams.channel);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200198 return -EINVAL;
199 }
200
201 fwrq->m = (long)cfp->freq * 100000;
202 fwrq->e = 1;
203
Holger Schurig9012b282007-05-25 11:27:16 -0400204 lbs_deb_wext("freq %u\n", fwrq->m);
205 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200206 return 0;
207}
208
Holger Schurig10078322007-11-15 18:05:47 -0500209static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200210 struct sockaddr *awrq, char *extra)
211{
Holger Schurig69f90322007-11-23 15:43:44 +0100212 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200213
Holger Schurig9012b282007-05-25 11:27:16 -0400214 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200215
David Woodhouseaa21c002007-12-08 20:04:36 +0000216 if (priv->connect_status == LBS_CONNECTED) {
217 memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200218 } else {
219 memset(awrq->sa_data, 0, ETH_ALEN);
220 }
221 awrq->sa_family = ARPHRD_ETHER;
222
Holger Schurig9012b282007-05-25 11:27:16 -0400223 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200224 return 0;
225}
226
Holger Schurig10078322007-11-15 18:05:47 -0500227static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200228 struct iw_point *dwrq, char *extra)
229{
Holger Schurig69f90322007-11-23 15:43:44 +0100230 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200231
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
David Woodhouseaa21c002007-12-08 20:04:36 +0000242 mutex_lock(&priv->lock);
243 memset(priv->nodename, 0, sizeof(priv->nodename));
244 memcpy(priv->nodename, extra, dwrq->length);
245 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200246
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
Holger Schurig10078322007-11-15 18:05:47 -0500251static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200252 struct iw_point *dwrq, char *extra)
253{
Holger Schurig69f90322007-11-23 15:43:44 +0100254 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200255
Holger Schurig9012b282007-05-25 11:27:16 -0400256 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200257
David Woodhouseaa21c002007-12-08 20:04:36 +0000258 dwrq->length = strlen(priv->nodename);
259 memcpy(extra, priv->nodename, dwrq->length);
Holger Schurig04799fa2007-10-09 15:04:14 +0200260 extra[dwrq->length] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200261
Holger Schurig04799fa2007-10-09 15:04:14 +0200262 dwrq->flags = 1; /* active */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200263
Holger Schurig9012b282007-05-25 11:27:16 -0400264 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200265 return 0;
266}
267
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400268static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
269 struct iw_point *dwrq, char *extra)
270{
Holger Schurig69f90322007-11-23 15:43:44 +0100271 struct lbs_private *priv = dev->priv;
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400272
273 lbs_deb_enter(LBS_DEB_WEXT);
274
275 /* Use nickname to indicate that mesh is on */
276
David Woodhouseaa21c002007-12-08 20:04:36 +0000277 if (priv->mesh_connect_status == LBS_CONNECTED) {
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400278 strncpy(extra, "Mesh", 12);
279 extra[12] = '\0';
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400280 dwrq->length = strlen(extra);
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400281 }
282
283 else {
284 extra[0] = '\0';
Jean Tourrilhes9483f032007-08-02 13:16:30 -0400285 dwrq->length = 0;
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400286 }
287
288 lbs_deb_leave(LBS_DEB_WEXT);
289 return 0;
290}
Holger Schurig04799fa2007-10-09 15:04:14 +0200291
Holger Schurig10078322007-11-15 18:05:47 -0500292static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200293 struct iw_param *vwrq, char *extra)
294{
295 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100296 struct lbs_private *priv = dev->priv;
David Woodhouse981f1872007-05-25 23:36:54 -0400297 u32 rthr = vwrq->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200298
Holger Schurig9012b282007-05-25 11:27:16 -0400299 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200300
301 if (vwrq->disabled) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000302 priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200303 } else {
304 if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
305 return -EINVAL;
David Woodhouseaa21c002007-12-08 20:04:36 +0000306 priv->rtsthsd = rthr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200307 }
308
Holger Schurig10078322007-11-15 18:05:47 -0500309 ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
Dan Williams0aef64d2007-08-02 11:31:18 -0400310 CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200311 OID_802_11_RTS_THRESHOLD, &rthr);
312
Holger Schurig9012b282007-05-25 11:27:16 -0400313 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200314 return ret;
315}
316
Holger Schurig10078322007-11-15 18:05:47 -0500317static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200318 struct iw_param *vwrq, char *extra)
319{
320 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100321 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200322
Holger Schurig9012b282007-05-25 11:27:16 -0400323 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200324
David Woodhouseaa21c002007-12-08 20:04:36 +0000325 priv->rtsthsd = 0;
Holger Schurig10078322007-11-15 18:05:47 -0500326 ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
Dan Williams0aef64d2007-08-02 11:31:18 -0400327 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200328 OID_802_11_RTS_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400329 if (ret)
330 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200331
David Woodhouseaa21c002007-12-08 20:04:36 +0000332 vwrq->value = priv->rtsthsd;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200333 vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
334 || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
335 vwrq->fixed = 1;
336
Holger Schurig9012b282007-05-25 11:27:16 -0400337out:
338 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
339 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200340}
341
Holger Schurig10078322007-11-15 18:05:47 -0500342static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200343 struct iw_param *vwrq, char *extra)
344{
345 int ret = 0;
David Woodhouse981f1872007-05-25 23:36:54 -0400346 u32 fthr = vwrq->value;
Holger Schurig69f90322007-11-23 15:43:44 +0100347 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200348
Holger Schurig9012b282007-05-25 11:27:16 -0400349 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200350
351 if (vwrq->disabled) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000352 priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200353 } else {
354 if (fthr < MRVDRV_FRAG_MIN_VALUE
355 || fthr > MRVDRV_FRAG_MAX_VALUE)
356 return -EINVAL;
David Woodhouseaa21c002007-12-08 20:04:36 +0000357 priv->fragthsd = fthr;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200358 }
359
Holger Schurig10078322007-11-15 18:05:47 -0500360 ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
Dan Williams0aef64d2007-08-02 11:31:18 -0400361 CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200362 OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
Holger Schurig9012b282007-05-25 11:27:16 -0400363
364 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200365 return ret;
366}
367
Holger Schurig10078322007-11-15 18:05:47 -0500368static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200369 struct iw_param *vwrq, char *extra)
370{
371 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100372 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200373
Holger Schurig9012b282007-05-25 11:27:16 -0400374 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200375
David Woodhouseaa21c002007-12-08 20:04:36 +0000376 priv->fragthsd = 0;
Holger Schurig10078322007-11-15 18:05:47 -0500377 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400378 CMD_802_11_SNMP_MIB,
379 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200380 OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400381 if (ret)
382 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200383
David Woodhouseaa21c002007-12-08 20:04:36 +0000384 vwrq->value = priv->fragthsd;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200385 vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
386 || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
387 vwrq->fixed = 1;
388
Holger Schurig9012b282007-05-25 11:27:16 -0400389out:
390 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200391 return ret;
392}
393
Holger Schurig10078322007-11-15 18:05:47 -0500394static int lbs_get_mode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200395 struct iw_request_info *info, u32 * uwrq, char *extra)
396{
Holger Schurig69f90322007-11-23 15:43:44 +0100397 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200398
Holger Schurig9012b282007-05-25 11:27:16 -0400399 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200400
David Woodhouseaa21c002007-12-08 20:04:36 +0000401 *uwrq = priv->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200402
Holger Schurig9012b282007-05-25 11:27:16 -0400403 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200404 return 0;
405}
406
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -0400407static int mesh_wlan_get_mode(struct net_device *dev,
408 struct iw_request_info *info, u32 * uwrq,
409 char *extra)
410{
411 lbs_deb_enter(LBS_DEB_WEXT);
412
413 *uwrq = IW_MODE_REPEAT ;
414
415 lbs_deb_leave(LBS_DEB_WEXT);
416 return 0;
417}
418
Holger Schurig10078322007-11-15 18:05:47 -0500419static int lbs_get_txpow(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200420 struct iw_request_info *info,
421 struct iw_param *vwrq, char *extra)
422{
423 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100424 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200425
Holger Schurig9012b282007-05-25 11:27:16 -0400426 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200427
Holger Schurig10078322007-11-15 18:05:47 -0500428 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400429 CMD_802_11_RF_TX_POWER,
430 CMD_ACT_TX_POWER_OPT_GET,
431 CMD_OPTION_WAITFORRSP, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432
Holger Schurig9012b282007-05-25 11:27:16 -0400433 if (ret)
434 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200435
David Woodhouseaa21c002007-12-08 20:04:36 +0000436 lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel);
437 vwrq->value = priv->txpowerlevel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200438 vwrq->fixed = 1;
David Woodhouseaa21c002007-12-08 20:04:36 +0000439 if (priv->radioon) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200440 vwrq->disabled = 0;
441 vwrq->flags = IW_TXPOW_DBM;
442 } else {
443 vwrq->disabled = 1;
444 }
445
Holger Schurig9012b282007-05-25 11:27:16 -0400446out:
447 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
448 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200449}
450
Holger Schurig10078322007-11-15 18:05:47 -0500451static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200452 struct iw_param *vwrq, char *extra)
453{
454 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100455 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200456
Holger Schurig9012b282007-05-25 11:27:16 -0400457 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200458
459 if (vwrq->flags == IW_RETRY_LIMIT) {
460 /* The MAC has a 4-bit Total_Tx_Count register
461 Total_Tx_Count = 1 + Tx_Retry_Count */
462#define TX_RETRY_MIN 0
463#define TX_RETRY_MAX 14
464 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
465 return -EINVAL;
466
467 /* Adding 1 to convert retry count to try count */
David Woodhouseaa21c002007-12-08 20:04:36 +0000468 priv->txretrycount = vwrq->value + 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200469
Holger Schurig10078322007-11-15 18:05:47 -0500470 ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
Dan Williams0aef64d2007-08-02 11:31:18 -0400471 CMD_ACT_SET,
472 CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200473 OID_802_11_TX_RETRYCOUNT, NULL);
474
Holger Schurig9012b282007-05-25 11:27:16 -0400475 if (ret)
476 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200477 } else {
478 return -EOPNOTSUPP;
479 }
480
Holger Schurig9012b282007-05-25 11:27:16 -0400481out:
482 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
483 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200484}
485
Holger Schurig10078322007-11-15 18:05:47 -0500486static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200487 struct iw_param *vwrq, char *extra)
488{
Holger Schurig69f90322007-11-23 15:43:44 +0100489 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200490 int ret = 0;
491
Holger Schurig9012b282007-05-25 11:27:16 -0400492 lbs_deb_enter(LBS_DEB_WEXT);
493
David Woodhouseaa21c002007-12-08 20:04:36 +0000494 priv->txretrycount = 0;
Holger Schurig10078322007-11-15 18:05:47 -0500495 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400496 CMD_802_11_SNMP_MIB,
497 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200498 OID_802_11_TX_RETRYCOUNT, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400499 if (ret)
500 goto out;
501
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200502 vwrq->disabled = 0;
503 if (!vwrq->flags) {
504 vwrq->flags = IW_RETRY_LIMIT;
505 /* Subtract 1 to convert try count to retry count */
David Woodhouseaa21c002007-12-08 20:04:36 +0000506 vwrq->value = priv->txretrycount - 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200507 }
508
Holger Schurig9012b282007-05-25 11:27:16 -0400509out:
510 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
511 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200512}
513
514static inline void sort_channels(struct iw_freq *freq, int num)
515{
516 int i, j;
517 struct iw_freq temp;
518
519 for (i = 0; i < num; i++)
520 for (j = i + 1; j < num; j++)
521 if (freq[i].i > freq[j].i) {
522 temp.i = freq[i].i;
523 temp.m = freq[i].m;
524
525 freq[i].i = freq[j].i;
526 freq[i].m = freq[j].m;
527
528 freq[j].i = temp.i;
529 freq[j].m = temp.m;
530 }
531}
532
533/* data rate listing
534 MULTI_BANDS:
535 abg a b b/g
536 Infra G(12) A(8) B(4) G(12)
537 Adhoc A+B(12) A(8) B(4) B(4)
538
539 non-MULTI_BANDS:
540 b b/g
541 Infra B(4) G(12)
542 Adhoc B(4) B(4)
543 */
544/**
545 * @brief Get Range Info
546 *
547 * @param dev A pointer to net_device structure
548 * @param info A pointer to iw_request_info structure
549 * @param vwrq A pointer to iw_param structure
550 * @param extra A pointer to extra data buf
551 * @return 0 --success, otherwise fail
552 */
Holger Schurig10078322007-11-15 18:05:47 -0500553static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200554 struct iw_point *dwrq, char *extra)
555{
556 int i, j;
Holger Schurig69f90322007-11-23 15:43:44 +0100557 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200558 struct iw_range *range = (struct iw_range *)extra;
559 struct chan_freq_power *cfp;
Dan Williams8c512762007-08-02 11:40:45 -0400560 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200561
562 u8 flag = 0;
563
Holger Schurig9012b282007-05-25 11:27:16 -0400564 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200565
566 dwrq->length = sizeof(struct iw_range);
567 memset(range, 0, sizeof(struct iw_range));
568
569 range->min_nwid = 0;
570 range->max_nwid = 0;
571
572 memset(rates, 0, sizeof(rates));
David Woodhouseaa21c002007-12-08 20:04:36 +0000573 copy_active_data_rates(priv, rates);
Dan Williams8c512762007-08-02 11:40:45 -0400574 range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
575 for (i = 0; i < range->num_bitrates; i++)
576 range->bitrate[i] = rates[i] * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200577 range->num_bitrates = i;
Holger Schurig9012b282007-05-25 11:27:16 -0400578 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200579 range->num_bitrates);
580
581 range->num_frequency = 0;
Holger Schurig52933d82008-03-05 07:05:32 +0100582
583 range->scan_capa = IW_SCAN_CAPA_ESSID;
584
David Woodhouseaa21c002007-12-08 20:04:36 +0000585 if (priv->enable11d &&
586 (priv->connect_status == LBS_CONNECTED ||
587 priv->mesh_connect_status == LBS_CONNECTED)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200588 u8 chan_no;
589 u8 band;
590
591 struct parsed_region_chan_11d *parsed_region_chan =
David Woodhouseaa21c002007-12-08 20:04:36 +0000592 &priv->parsed_region_chan;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200593
594 if (parsed_region_chan == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -0400595 lbs_deb_wext("11d: parsed_region_chan is NULL\n");
596 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200597 }
598 band = parsed_region_chan->band;
Holger Schurig9012b282007-05-25 11:27:16 -0400599 lbs_deb_wext("band %d, nr_char %d\n", band,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200600 parsed_region_chan->nr_chan);
601
602 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
603 && (i < parsed_region_chan->nr_chan); i++) {
604 chan_no = parsed_region_chan->chanpwr[i].chan;
Holger Schurig9012b282007-05-25 11:27:16 -0400605 lbs_deb_wext("chan_no %d\n", chan_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200606 range->freq[range->num_frequency].i = (long)chan_no;
607 range->freq[range->num_frequency].m =
Holger Schurig10078322007-11-15 18:05:47 -0500608 (long)lbs_chan_2_freq(chan_no, band) * 100000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200609 range->freq[range->num_frequency].e = 1;
610 range->num_frequency++;
611 }
612 flag = 1;
613 }
614 if (!flag) {
615 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
David Woodhouseaa21c002007-12-08 20:04:36 +0000616 && (j < ARRAY_SIZE(priv->region_channel)); j++) {
617 cfp = priv->region_channel[j].CFP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200618 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
David Woodhouseaa21c002007-12-08 20:04:36 +0000619 && priv->region_channel[j].valid
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200620 && cfp
David Woodhouseaa21c002007-12-08 20:04:36 +0000621 && (i < priv->region_channel[j].nrcfp); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200622 range->freq[range->num_frequency].i =
623 (long)cfp->channel;
624 range->freq[range->num_frequency].m =
625 (long)cfp->freq * 100000;
626 range->freq[range->num_frequency].e = 1;
627 cfp++;
628 range->num_frequency++;
629 }
630 }
631 }
632
Holger Schurig9012b282007-05-25 11:27:16 -0400633 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200634 IW_MAX_FREQUENCIES, range->num_frequency);
635
636 range->num_channels = range->num_frequency;
637
638 sort_channels(&range->freq[0], range->num_frequency);
639
640 /*
641 * Set an indication of the max TCP throughput in bit/s that we can
642 * expect using this interface
643 */
644 if (i > 2)
645 range->throughput = 5000 * 1000;
646 else
647 range->throughput = 1500 * 1000;
648
649 range->min_rts = MRVDRV_RTS_MIN_VALUE;
650 range->max_rts = MRVDRV_RTS_MAX_VALUE;
651 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
652 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
653
654 range->encoding_size[0] = 5;
655 range->encoding_size[1] = 13;
656 range->num_encoding_sizes = 2;
657 range->max_encoding_tokens = 4;
658
659 range->min_pmp = 1000000;
660 range->max_pmp = 120000000;
661 range->min_pmt = 1000;
662 range->max_pmt = 1000000;
663 range->pmp_flags = IW_POWER_PERIOD;
664 range->pmt_flags = IW_POWER_TIMEOUT;
665 range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
666
667 /*
668 * Minimum version we recommend
669 */
670 range->we_version_source = 15;
671
672 /*
673 * Version we are compiled with
674 */
675 range->we_version_compiled = WIRELESS_EXT;
676
677 range->retry_capa = IW_RETRY_LIMIT;
678 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
679
680 range->min_retry = TX_RETRY_MIN;
681 range->max_retry = TX_RETRY_MAX;
682
683 /*
684 * Set the qual, level and noise range values
685 */
686 range->max_qual.qual = 100;
687 range->max_qual.level = 0;
688 range->max_qual.noise = 0;
689 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
690
691 range->avg_qual.qual = 70;
692 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
693 range->avg_qual.level = 0;
694 range->avg_qual.noise = 0;
695 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
696
697 range->sensitivity = 0;
698
699 /*
700 * Setup the supported power level ranges
701 */
702 memset(range->txpower, 0, sizeof(range->txpower));
703 range->txpower[0] = 5;
704 range->txpower[1] = 7;
705 range->txpower[2] = 9;
706 range->txpower[3] = 11;
707 range->txpower[4] = 13;
708 range->txpower[5] = 15;
709 range->txpower[6] = 17;
710 range->txpower[7] = 19;
711
712 range->num_txpower = 8;
713 range->txpower_capa = IW_TXPOW_DBM;
714 range->txpower_capa |= IW_TXPOW_RANGE;
715
716 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
717 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
718 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
719 range->event_capa[1] = IW_EVENT_CAPA_K_1;
720
David Woodhouseaa21c002007-12-08 20:04:36 +0000721 if (priv->fwcapinfo & FW_CAPINFO_WPA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200722 range->enc_capa = IW_ENC_CAPA_WPA
723 | IW_ENC_CAPA_WPA2
724 | IW_ENC_CAPA_CIPHER_TKIP
725 | IW_ENC_CAPA_CIPHER_CCMP;
726 }
727
Holger Schurig9012b282007-05-25 11:27:16 -0400728out:
729 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200730 return 0;
731}
732
Holger Schurig10078322007-11-15 18:05:47 -0500733static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200734 struct iw_param *vwrq, char *extra)
735{
Holger Schurig69f90322007-11-23 15:43:44 +0100736 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200737
Holger Schurig9012b282007-05-25 11:27:16 -0400738 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200739
David Woodhouseb2c57ee2007-12-17 14:41:13 -0500740 if (!priv->ps_supported) {
741 if (vwrq->disabled)
742 return 0;
743 else
744 return -EINVAL;
745 }
746
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200747 /* PS is currently supported only in Infrastructure mode
748 * Remove this check if it is to be supported in IBSS mode also
749 */
750
751 if (vwrq->disabled) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000752 priv->psmode = LBS802_11POWERMODECAM;
753 if (priv->psstate != PS_STATE_FULL_POWER) {
Holger Schurig10078322007-11-15 18:05:47 -0500754 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200755 }
756
757 return 0;
758 }
759
760 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
Holger Schurig9012b282007-05-25 11:27:16 -0400761 lbs_deb_wext(
762 "setting power timeout is not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200763 return -EINVAL;
764 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
Holger Schurig9012b282007-05-25 11:27:16 -0400765 lbs_deb_wext("setting power period not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200766 return -EINVAL;
767 }
768
David Woodhouseaa21c002007-12-08 20:04:36 +0000769 if (priv->psmode != LBS802_11POWERMODECAM) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200770 return 0;
771 }
772
David Woodhouseaa21c002007-12-08 20:04:36 +0000773 priv->psmode = LBS802_11POWERMODEMAX_PSP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200774
David Woodhouseaa21c002007-12-08 20:04:36 +0000775 if (priv->connect_status == LBS_CONNECTED) {
Holger Schurig10078322007-11-15 18:05:47 -0500776 lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200777 }
778
Holger Schurig9012b282007-05-25 11:27:16 -0400779 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200780 return 0;
781}
782
Holger Schurig10078322007-11-15 18:05:47 -0500783static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200784 struct iw_param *vwrq, char *extra)
785{
Holger Schurig69f90322007-11-23 15:43:44 +0100786 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200787 int mode;
788
Holger Schurig9012b282007-05-25 11:27:16 -0400789 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200790
David Woodhouseaa21c002007-12-08 20:04:36 +0000791 mode = priv->psmode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200792
Holger Schurig10078322007-11-15 18:05:47 -0500793 if ((vwrq->disabled = (mode == LBS802_11POWERMODECAM))
David Woodhouseaa21c002007-12-08 20:04:36 +0000794 || priv->connect_status == LBS_DISCONNECTED)
Holger Schurig9012b282007-05-25 11:27:16 -0400795 {
796 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200797 }
798
799 vwrq->value = 0;
800
Holger Schurig9012b282007-05-25 11:27:16 -0400801out:
802 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200803 return 0;
804}
805
Holger Schurig10078322007-11-15 18:05:47 -0500806static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200807{
808 enum {
809 POOR = 30,
810 FAIR = 60,
811 GOOD = 80,
812 VERY_GOOD = 90,
813 EXCELLENT = 95,
814 PERFECT = 100
815 };
Holger Schurig69f90322007-11-23 15:43:44 +0100816 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200817 u32 rssi_qual;
818 u32 tx_qual;
819 u32 quality = 0;
820 int stats_valid = 0;
821 u8 rssi;
822 u32 tx_retries;
Holger Schurigc49c3b72008-03-17 12:45:58 +0100823 struct cmd_ds_802_11_get_log log;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200824
Holger Schurig9012b282007-05-25 11:27:16 -0400825 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200826
David Woodhouseaa21c002007-12-08 20:04:36 +0000827 priv->wstats.status = priv->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200828
829 /* If we're not associated, all quality values are meaningless */
David Woodhouseaa21c002007-12-08 20:04:36 +0000830 if ((priv->connect_status != LBS_CONNECTED) &&
831 (priv->mesh_connect_status != LBS_CONNECTED))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200832 goto out;
833
834 /* Quality by RSSI */
835 priv->wstats.qual.level =
David Woodhouseaa21c002007-12-08 20:04:36 +0000836 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
837 priv->NF[TYPE_BEACON][TYPE_NOAVG]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200838
David Woodhouseaa21c002007-12-08 20:04:36 +0000839 if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200840 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
841 } else {
842 priv->wstats.qual.noise =
David Woodhouseaa21c002007-12-08 20:04:36 +0000843 CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200844 }
845
Holger Schurig9012b282007-05-25 11:27:16 -0400846 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
847 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200848
849 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
850 if (rssi < 15)
851 rssi_qual = rssi * POOR / 10;
852 else if (rssi < 20)
853 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
854 else if (rssi < 30)
855 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
856 else if (rssi < 40)
857 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
858 10 + GOOD;
859 else
860 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
861 10 + VERY_GOOD;
862 quality = rssi_qual;
863
864 /* Quality by TX errors */
865 priv->wstats.discard.retries = priv->stats.tx_errors;
866
Holger Schurigc49c3b72008-03-17 12:45:58 +0100867 memset(&log, 0, sizeof(log));
868 log.hdr.size = cpu_to_le16(sizeof(log));
869 lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
870
871 tx_retries = le32_to_cpu(log.retry);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200872
873 if (tx_retries > 75)
874 tx_qual = (90 - tx_retries) * POOR / 15;
875 else if (tx_retries > 70)
876 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
877 else if (tx_retries > 65)
878 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
879 else if (tx_retries > 50)
880 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
881 15 + GOOD;
882 else
883 tx_qual = (50 - tx_retries) *
884 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
885 quality = min(quality, tx_qual);
886
Holger Schurigc49c3b72008-03-17 12:45:58 +0100887 priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200888 priv->wstats.discard.retries = tx_retries;
Holger Schurigc49c3b72008-03-17 12:45:58 +0100889 priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200890
891 /* Calculate quality */
Holger Schurigcad9d9b2007-08-02 13:07:15 -0400892 priv->wstats.qual.qual = min_t(u8, quality, 100);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200893 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
894 stats_valid = 1;
895
896 /* update stats asynchronously for future calls */
Holger Schurig10078322007-11-15 18:05:47 -0500897 lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200898 0, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200899out:
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
Holger Schurig10078322007-11-15 18:05:47 -0500917static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200918 struct iw_freq *fwrq, char *extra)
919{
Dan Williamsef9a2642007-05-25 16:46:33 -0400920 int ret = -EINVAL;
Holger Schurig69f90322007-11-23 15:43:44 +0100921 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200922 struct chan_freq_power *cfp;
Dan Williamsef9a2642007-05-25 16:46:33 -0400923 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200924
Holger Schurig9012b282007-05-25 11:27:16 -0400925 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200926
David Woodhouseaa21c002007-12-08 20:04:36 +0000927 mutex_lock(&priv->lock);
928 assoc_req = lbs_get_association_request(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400929 if (!assoc_req) {
930 ret = -ENOMEM;
931 goto out;
932 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200933
Dan Williamsef9a2642007-05-25 16:46:33 -0400934 /* If setting by frequency, convert to a channel */
935 if (fwrq->e == 1) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200936 long f = fwrq->m / 100000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200937
David Woodhouseaa21c002007-12-08 20:04:36 +0000938 cfp = find_cfp_by_band_and_freq(priv, 0, f);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200939 if (!cfp) {
Holger Schurig9012b282007-05-25 11:27:16 -0400940 lbs_deb_wext("invalid freq %ld\n", f);
Dan Williamsef9a2642007-05-25 16:46:33 -0400941 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200942 }
943
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200944 fwrq->e = 0;
Dan Williamsef9a2642007-05-25 16:46:33 -0400945 fwrq->m = (int) cfp->channel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200946 }
947
Dan Williamsef9a2642007-05-25 16:46:33 -0400948 /* Setting by channel number */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200949 if (fwrq->m > 1000 || fwrq->e > 0) {
Dan Williamsef9a2642007-05-25 16:46:33 -0400950 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200951 }
952
David Woodhouseaa21c002007-12-08 20:04:36 +0000953 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
Dan Williamsef9a2642007-05-25 16:46:33 -0400954 if (!cfp) {
955 goto out;
956 }
957
958 assoc_req->channel = fwrq->m;
959 ret = 0;
960
Holger Schurig9012b282007-05-25 11:27:16 -0400961out:
Dan Williamsef9a2642007-05-25 16:46:33 -0400962 if (ret == 0) {
963 set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -0500964 lbs_postpone_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400965 } else {
Holger Schurig10078322007-11-15 18:05:47 -0500966 lbs_cancel_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400967 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000968 mutex_unlock(&priv->lock);
Dan Williamsef9a2642007-05-25 16:46:33 -0400969
970 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
971 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200972}
973
David Woodhouse823eaa22007-12-11 19:56:28 -0500974static int lbs_mesh_set_freq(struct net_device *dev,
975 struct iw_request_info *info,
976 struct iw_freq *fwrq, char *extra)
977{
978 struct lbs_private *priv = dev->priv;
979 struct chan_freq_power *cfp;
980 int ret = -EINVAL;
981
982 lbs_deb_enter(LBS_DEB_WEXT);
983
984 /* If setting by frequency, convert to a channel */
985 if (fwrq->e == 1) {
986 long f = fwrq->m / 100000;
987
988 cfp = find_cfp_by_band_and_freq(priv, 0, f);
989 if (!cfp) {
990 lbs_deb_wext("invalid freq %ld\n", f);
991 goto out;
992 }
993
994 fwrq->e = 0;
995 fwrq->m = (int) cfp->channel;
996 }
997
998 /* Setting by channel number */
999 if (fwrq->m > 1000 || fwrq->e > 0) {
1000 goto out;
1001 }
1002
1003 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
1004 if (!cfp) {
1005 goto out;
1006 }
1007
1008 if (fwrq->m != priv->curbssparams.channel) {
1009 lbs_deb_wext("mesh channel change forces eth disconnect\n");
1010 if (priv->mode == IW_MODE_INFRA)
1011 lbs_send_deauthentication(priv);
1012 else if (priv->mode == IW_MODE_ADHOC)
1013 lbs_stop_adhoc_network(priv);
1014 }
David Woodhouse86062132007-12-13 00:32:36 -05001015 lbs_mesh_config(priv, 1, fwrq->m);
1016 lbs_update_channel(priv);
David Woodhouse823eaa22007-12-11 19:56:28 -05001017 ret = 0;
1018
1019out:
1020 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1021 return ret;
1022}
1023
Holger Schurig10078322007-11-15 18:05:47 -05001024static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001025 struct iw_param *vwrq, char *extra)
1026{
Holger Schurig69f90322007-11-23 15:43:44 +01001027 struct lbs_private *priv = dev->priv;
Dan Williams8e3c91b2007-12-11 15:50:59 -05001028 u8 new_rate = 0;
Dan Williams8c512762007-08-02 11:40:45 -04001029 int ret = -EINVAL;
1030 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001031
Holger Schurig9012b282007-05-25 11:27:16 -04001032 lbs_deb_enter(LBS_DEB_WEXT);
Holger Schurig9012b282007-05-25 11:27:16 -04001033 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001034
Dan Williams8c512762007-08-02 11:40:45 -04001035 /* Auto rate? */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001036 if (vwrq->value == -1) {
David Woodhouseaa21c002007-12-08 20:04:36 +00001037 priv->auto_rate = 1;
1038 priv->cur_rate = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001039 } else {
Dan Williams8c512762007-08-02 11:40:45 -04001040 if (vwrq->value % 100000)
1041 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001042
1043 memset(rates, 0, sizeof(rates));
David Woodhouseaa21c002007-12-08 20:04:36 +00001044 copy_active_data_rates(priv, rates);
Dan Williams8c512762007-08-02 11:40:45 -04001045 new_rate = vwrq->value / 500000;
1046 if (!memchr(rates, new_rate, sizeof(rates))) {
1047 lbs_pr_alert("fixed data rate 0x%X out of range\n",
1048 new_rate);
1049 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001050 }
1051
David Woodhouseaa21c002007-12-08 20:04:36 +00001052 priv->cur_rate = new_rate;
David Woodhouseaa21c002007-12-08 20:04:36 +00001053 priv->auto_rate = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001054 }
1055
Dan Williams8e3c91b2007-12-11 15:50:59 -05001056 ret = lbs_set_data_rate(priv, new_rate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001057
Dan Williams8c512762007-08-02 11:40:45 -04001058out:
Holger Schurig9012b282007-05-25 11:27:16 -04001059 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001060 return ret;
1061}
1062
Holger Schurig10078322007-11-15 18:05:47 -05001063static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001064 struct iw_param *vwrq, char *extra)
1065{
Holger Schurig69f90322007-11-23 15:43:44 +01001066 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001067
Holger Schurig9012b282007-05-25 11:27:16 -04001068 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001069
David Woodhouseaa21c002007-12-08 20:04:36 +00001070 if (priv->connect_status == LBS_CONNECTED) {
1071 vwrq->value = priv->cur_rate * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001072
David Woodhouseaa21c002007-12-08 20:04:36 +00001073 if (priv->auto_rate)
Dan Williams8c512762007-08-02 11:40:45 -04001074 vwrq->fixed = 0;
1075 else
1076 vwrq->fixed = 1;
1077
1078 } else {
1079 vwrq->fixed = 0;
1080 vwrq->value = 0;
1081 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001082
Holger Schurig9012b282007-05-25 11:27:16 -04001083 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001084 return 0;
1085}
1086
Holger Schurig10078322007-11-15 18:05:47 -05001087static int lbs_set_mode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001088 struct iw_request_info *info, u32 * uwrq, char *extra)
1089{
1090 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001091 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001092 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001093
Holger Schurig9012b282007-05-25 11:27:16 -04001094 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001095
Dan Williams0dc5a292007-05-10 22:58:02 -04001096 if ( (*uwrq != IW_MODE_ADHOC)
1097 && (*uwrq != IW_MODE_INFRA)
1098 && (*uwrq != IW_MODE_AUTO)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001099 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
Dan Williams0dc5a292007-05-10 22:58:02 -04001100 ret = -EINVAL;
1101 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001102 }
1103
David Woodhouseaa21c002007-12-08 20:04:36 +00001104 mutex_lock(&priv->lock);
1105 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001106 if (!assoc_req) {
1107 ret = -ENOMEM;
Holger Schurig10078322007-11-15 18:05:47 -05001108 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001109 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001110 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001111 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001112 lbs_postpone_association_work(priv);
Holger Schurig9012b282007-05-25 11:27:16 -04001113 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001114 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001115 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001116
Dan Williams0dc5a292007-05-10 22:58:02 -04001117out:
Holger Schurig9012b282007-05-25 11:27:16 -04001118 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001119 return ret;
1120}
1121
1122
1123/**
1124 * @brief Get Encryption key
1125 *
1126 * @param dev A pointer to net_device structure
1127 * @param info A pointer to iw_request_info structure
1128 * @param vwrq A pointer to iw_param structure
1129 * @param extra A pointer to extra data buf
1130 * @return 0 --success, otherwise fail
1131 */
Holger Schurig10078322007-11-15 18:05:47 -05001132static int lbs_get_encode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001133 struct iw_request_info *info,
1134 struct iw_point *dwrq, u8 * extra)
1135{
Holger Schurig69f90322007-11-23 15:43:44 +01001136 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001137 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1138
Holger Schurig9012b282007-05-25 11:27:16 -04001139 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001140
Holger Schurig9012b282007-05-25 11:27:16 -04001141 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001142 dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001143
1144 dwrq->flags = 0;
1145
1146 /* Authentication method */
David Woodhouseaa21c002007-12-08 20:04:36 +00001147 switch (priv->secinfo.auth_mode) {
Dan Williams6affe782007-05-10 22:56:42 -04001148 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001149 dwrq->flags = IW_ENCODE_OPEN;
1150 break;
1151
Dan Williams6affe782007-05-10 22:56:42 -04001152 case IW_AUTH_ALG_SHARED_KEY:
1153 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001154 dwrq->flags = IW_ENCODE_RESTRICTED;
1155 break;
1156 default:
1157 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1158 break;
1159 }
1160
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001161 memset(extra, 0, 16);
1162
David Woodhouseaa21c002007-12-08 20:04:36 +00001163 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001164
1165 /* Default to returning current transmit key */
1166 if (index < 0)
David Woodhouseaa21c002007-12-08 20:04:36 +00001167 index = priv->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001168
David Woodhouseaa21c002007-12-08 20:04:36 +00001169 if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
1170 memcpy(extra, priv->wep_keys[index].key,
1171 priv->wep_keys[index].len);
1172 dwrq->length = priv->wep_keys[index].len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001173
1174 dwrq->flags |= (index + 1);
1175 /* Return WEP enabled */
1176 dwrq->flags &= ~IW_ENCODE_DISABLED;
David Woodhouseaa21c002007-12-08 20:04:36 +00001177 } else if ((priv->secinfo.WPAenabled)
1178 || (priv->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001179 /* return WPA enabled */
1180 dwrq->flags &= ~IW_ENCODE_DISABLED;
David Woodhousec12bdc42007-12-07 19:32:12 +00001181 dwrq->flags |= IW_ENCODE_NOKEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001182 } else {
1183 dwrq->flags |= IW_ENCODE_DISABLED;
1184 }
1185
David Woodhouseaa21c002007-12-08 20:04:36 +00001186 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001187
Joe Perches0795af52007-10-03 17:59:30 -07001188 lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001189 extra[0], extra[1], extra[2],
1190 extra[3], extra[4], extra[5], dwrq->length);
1191
Holger Schurig9012b282007-05-25 11:27:16 -04001192 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001193
Holger Schurig9012b282007-05-25 11:27:16 -04001194 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001195 return 0;
1196}
1197
1198/**
1199 * @brief Set Encryption key (internal)
1200 *
1201 * @param priv A pointer to private card structure
1202 * @param key_material A pointer to key material
1203 * @param key_length length of key material
1204 * @param index key index to set
1205 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1206 * @return 0 --success, otherwise fail
1207 */
Holger Schurig10078322007-11-15 18:05:47 -05001208static int lbs_set_wep_key(struct assoc_request *assoc_req,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001209 const char *key_material,
1210 u16 key_length,
1211 u16 index,
1212 int set_tx_key)
1213{
Holger Schurig9012b282007-05-25 11:27:16 -04001214 int ret = 0;
Dan Williams1443b652007-08-02 10:45:55 -04001215 struct enc_key *pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001216
Holger Schurig9012b282007-05-25 11:27:16 -04001217 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001218
1219 /* Paranoid validation of key index */
1220 if (index > 3) {
Holger Schurig9012b282007-05-25 11:27:16 -04001221 ret = -EINVAL;
1222 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001223 }
1224
1225 /* validate max key length */
1226 if (key_length > KEY_LEN_WEP_104) {
Holger Schurig9012b282007-05-25 11:27:16 -04001227 ret = -EINVAL;
1228 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001229 }
1230
1231 pkey = &assoc_req->wep_keys[index];
1232
1233 if (key_length > 0) {
Dan Williams1443b652007-08-02 10:45:55 -04001234 memset(pkey, 0, sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001235 pkey->type = KEY_TYPE_ID_WEP;
1236
1237 /* Standardize the key length */
1238 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1239 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1240 memcpy(pkey->key, key_material, key_length);
1241 }
1242
1243 if (set_tx_key) {
1244 /* Ensure the chosen key is valid */
1245 if (!pkey->len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001246 lbs_deb_wext("key not set, so cannot enable it\n");
1247 ret = -EINVAL;
1248 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001249 }
1250 assoc_req->wep_tx_keyidx = index;
1251 }
1252
Dan Williams889c05b2007-05-10 22:57:23 -04001253 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001254
Holger Schurig9012b282007-05-25 11:27:16 -04001255out:
1256 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1257 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001258}
1259
1260static int validate_key_index(u16 def_index, u16 raw_index,
1261 u16 *out_index, u16 *is_default)
1262{
1263 if (!out_index || !is_default)
1264 return -EINVAL;
1265
1266 /* Verify index if present, otherwise use default TX key index */
1267 if (raw_index > 0) {
1268 if (raw_index > 4)
1269 return -EINVAL;
1270 *out_index = raw_index - 1;
1271 } else {
1272 *out_index = def_index;
1273 *is_default = 1;
1274 }
1275 return 0;
1276}
1277
1278static void disable_wep(struct assoc_request *assoc_req)
1279{
1280 int i;
1281
Dan Williams90a42212007-05-25 23:01:24 -04001282 lbs_deb_enter(LBS_DEB_WEXT);
1283
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001284 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001285 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001286
1287 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001288 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001289 for (i = 0; i < 4; i++)
1290 assoc_req->wep_keys[i].len = 0;
1291
1292 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1293 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
Dan Williams90a42212007-05-25 23:01:24 -04001294
1295 lbs_deb_leave(LBS_DEB_WEXT);
1296}
1297
1298static void disable_wpa(struct assoc_request *assoc_req)
1299{
1300 lbs_deb_enter(LBS_DEB_WEXT);
1301
Dan Williams1443b652007-08-02 10:45:55 -04001302 memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001303 assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1304 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1305
Dan Williams1443b652007-08-02 10:45:55 -04001306 memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001307 assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1308 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1309
1310 assoc_req->secinfo.WPAenabled = 0;
1311 assoc_req->secinfo.WPA2enabled = 0;
1312 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1313
1314 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001315}
1316
1317/**
1318 * @brief Set Encryption key
1319 *
1320 * @param dev A pointer to net_device structure
1321 * @param info A pointer to iw_request_info structure
1322 * @param vwrq A pointer to iw_param structure
1323 * @param extra A pointer to extra data buf
1324 * @return 0 --success, otherwise fail
1325 */
Holger Schurig10078322007-11-15 18:05:47 -05001326static int lbs_set_encode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001327 struct iw_request_info *info,
1328 struct iw_point *dwrq, char *extra)
1329{
1330 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001331 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001332 struct assoc_request * assoc_req;
1333 u16 is_default = 0, index = 0, set_tx_key = 0;
1334
Holger Schurig9012b282007-05-25 11:27:16 -04001335 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001336
David Woodhouseaa21c002007-12-08 20:04:36 +00001337 mutex_lock(&priv->lock);
1338 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001339 if (!assoc_req) {
1340 ret = -ENOMEM;
1341 goto out;
1342 }
1343
1344 if (dwrq->flags & IW_ENCODE_DISABLED) {
1345 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001346 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001347 goto out;
1348 }
1349
1350 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1351 (dwrq->flags & IW_ENCODE_INDEX),
1352 &index, &is_default);
1353 if (ret) {
1354 ret = -EINVAL;
1355 goto out;
1356 }
1357
1358 /* If WEP isn't enabled, or if there is no key data but a valid
1359 * index, set the TX key.
1360 */
Dan Williams889c05b2007-05-10 22:57:23 -04001361 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001362 set_tx_key = 1;
1363
Holger Schurig10078322007-11-15 18:05:47 -05001364 ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001365 if (ret)
1366 goto out;
1367
1368 if (dwrq->length)
1369 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1370 if (set_tx_key)
1371 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1372
1373 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001374 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001375 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001376 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001377 }
1378
1379out:
1380 if (ret == 0) {
1381 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001382 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001383 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001384 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001385 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001386 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001387
Holger Schurig9012b282007-05-25 11:27:16 -04001388 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001389 return ret;
1390}
1391
1392/**
1393 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1394 *
1395 * @param dev A pointer to net_device structure
1396 * @param info A pointer to iw_request_info structure
1397 * @param vwrq A pointer to iw_param structure
1398 * @param extra A pointer to extra data buf
1399 * @return 0 on success, otherwise failure
1400 */
Holger Schurig10078322007-11-15 18:05:47 -05001401static int lbs_get_encodeext(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001402 struct iw_request_info *info,
1403 struct iw_point *dwrq,
1404 char *extra)
1405{
1406 int ret = -EINVAL;
Holger Schurig69f90322007-11-23 15:43:44 +01001407 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001408 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1409 int index, max_key_len;
1410
Holger Schurig9012b282007-05-25 11:27:16 -04001411 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001412
1413 max_key_len = dwrq->length - sizeof(*ext);
1414 if (max_key_len < 0)
1415 goto out;
1416
1417 index = dwrq->flags & IW_ENCODE_INDEX;
1418 if (index) {
1419 if (index < 1 || index > 4)
1420 goto out;
1421 index--;
1422 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001423 index = priv->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001424 }
1425
Roel Kluinf59d9782007-10-26 21:51:26 +02001426 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001427 ext->alg != IW_ENCODE_ALG_WEP) {
David Woodhouseaa21c002007-12-08 20:04:36 +00001428 if (index != 0 || priv->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001429 goto out;
1430 }
1431
1432 dwrq->flags = index + 1;
1433 memset(ext, 0, sizeof(*ext));
1434
David Woodhouseaa21c002007-12-08 20:04:36 +00001435 if ( !priv->secinfo.wep_enabled
1436 && !priv->secinfo.WPAenabled
1437 && !priv->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001438 ext->alg = IW_ENCODE_ALG_NONE;
1439 ext->key_len = 0;
1440 dwrq->flags |= IW_ENCODE_DISABLED;
1441 } else {
1442 u8 *key = NULL;
1443
David Woodhouseaa21c002007-12-08 20:04:36 +00001444 if ( priv->secinfo.wep_enabled
1445 && !priv->secinfo.WPAenabled
1446 && !priv->secinfo.WPA2enabled) {
Dan Williams90a42212007-05-25 23:01:24 -04001447 /* WEP */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001448 ext->alg = IW_ENCODE_ALG_WEP;
David Woodhouseaa21c002007-12-08 20:04:36 +00001449 ext->key_len = priv->wep_keys[index].len;
1450 key = &priv->wep_keys[index].key[0];
1451 } else if ( !priv->secinfo.wep_enabled
1452 && (priv->secinfo.WPAenabled ||
1453 priv->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001454 /* WPA */
Dan Williams1443b652007-08-02 10:45:55 -04001455 struct enc_key * pkey = NULL;
Dan Williams90a42212007-05-25 23:01:24 -04001456
David Woodhouseaa21c002007-12-08 20:04:36 +00001457 if ( priv->wpa_mcast_key.len
1458 && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1459 pkey = &priv->wpa_mcast_key;
1460 else if ( priv->wpa_unicast_key.len
1461 && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1462 pkey = &priv->wpa_unicast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001463
1464 if (pkey) {
1465 if (pkey->type == KEY_TYPE_ID_AES) {
1466 ext->alg = IW_ENCODE_ALG_CCMP;
1467 } else {
1468 ext->alg = IW_ENCODE_ALG_TKIP;
1469 }
1470 ext->key_len = pkey->len;
1471 key = &pkey->key[0];
1472 } else {
1473 ext->alg = IW_ENCODE_ALG_TKIP;
1474 ext->key_len = 0;
1475 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001476 } else {
1477 goto out;
1478 }
1479
1480 if (ext->key_len > max_key_len) {
1481 ret = -E2BIG;
1482 goto out;
1483 }
1484
1485 if (ext->key_len)
1486 memcpy(ext->key, key, ext->key_len);
1487 else
1488 dwrq->flags |= IW_ENCODE_NOKEY;
1489 dwrq->flags |= IW_ENCODE_ENABLED;
1490 }
1491 ret = 0;
1492
1493out:
Holger Schurig9012b282007-05-25 11:27:16 -04001494 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001495 return ret;
1496}
1497
1498/**
1499 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1500 *
1501 * @param dev A pointer to net_device structure
1502 * @param info A pointer to iw_request_info structure
1503 * @param vwrq A pointer to iw_param structure
1504 * @param extra A pointer to extra data buf
1505 * @return 0 --success, otherwise fail
1506 */
Holger Schurig10078322007-11-15 18:05:47 -05001507static int lbs_set_encodeext(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001508 struct iw_request_info *info,
1509 struct iw_point *dwrq,
1510 char *extra)
1511{
1512 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001513 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001514 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1515 int alg = ext->alg;
1516 struct assoc_request * assoc_req;
1517
Holger Schurig9012b282007-05-25 11:27:16 -04001518 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001519
David Woodhouseaa21c002007-12-08 20:04:36 +00001520 mutex_lock(&priv->lock);
1521 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001522 if (!assoc_req) {
1523 ret = -ENOMEM;
1524 goto out;
1525 }
1526
1527 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1528 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001529 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001530 } else if (alg == IW_ENCODE_ALG_WEP) {
1531 u16 is_default = 0, index, set_tx_key = 0;
1532
1533 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1534 (dwrq->flags & IW_ENCODE_INDEX),
1535 &index, &is_default);
1536 if (ret)
1537 goto out;
1538
1539 /* If WEP isn't enabled, or if there is no key data but a valid
1540 * index, or if the set-TX-key flag was passed, set the TX key.
1541 */
Dan Williams889c05b2007-05-10 22:57:23 -04001542 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001543 || (dwrq->length == 0 && !is_default)
1544 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1545 set_tx_key = 1;
1546
1547 /* Copy key to driver */
Holger Schurig10078322007-11-15 18:05:47 -05001548 ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001549 set_tx_key);
1550 if (ret)
1551 goto out;
1552
1553 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001554 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001555 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001556 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001557 }
1558
1559 /* Mark the various WEP bits as modified */
1560 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1561 if (dwrq->length)
1562 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1563 if (set_tx_key)
1564 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001565 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
Dan Williams1443b652007-08-02 10:45:55 -04001566 struct enc_key * pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001567
1568 /* validate key length */
1569 if (((alg == IW_ENCODE_ALG_TKIP)
1570 && (ext->key_len != KEY_LEN_WPA_TKIP))
1571 || ((alg == IW_ENCODE_ALG_CCMP)
1572 && (ext->key_len != KEY_LEN_WPA_AES))) {
Joe Perches8376e7a2007-11-19 17:48:27 -08001573 lbs_deb_wext("invalid size %d for key of alg "
Holger Schurig9012b282007-05-25 11:27:16 -04001574 "type %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001575 ext->key_len,
1576 alg);
1577 ret = -EINVAL;
1578 goto out;
1579 }
1580
Dan Williams90a42212007-05-25 23:01:24 -04001581 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001582 pkey = &assoc_req->wpa_mcast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001583 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1584 } else {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001585 pkey = &assoc_req->wpa_unicast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001586 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1587 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001588
Dan Williams1443b652007-08-02 10:45:55 -04001589 memset(pkey, 0, sizeof (struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001590 memcpy(pkey->key, ext->key, ext->key_len);
1591 pkey->len = ext->key_len;
Dan Williams90a42212007-05-25 23:01:24 -04001592 if (pkey->len)
1593 pkey->flags |= KEY_INFO_WPA_ENABLED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001594
Dan Williams90a42212007-05-25 23:01:24 -04001595 /* Do this after zeroing key structure */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001596 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1597 pkey->flags |= KEY_INFO_WPA_MCAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001598 } else {
1599 pkey->flags |= KEY_INFO_WPA_UNICAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001600 }
1601
Dan Williams90a42212007-05-25 23:01:24 -04001602 if (alg == IW_ENCODE_ALG_TKIP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001603 pkey->type = KEY_TYPE_ID_TKIP;
Dan Williams90a42212007-05-25 23:01:24 -04001604 } else if (alg == IW_ENCODE_ALG_CCMP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001605 pkey->type = KEY_TYPE_ID_AES;
Dan Williams90a42212007-05-25 23:01:24 -04001606 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001607
1608 /* If WPA isn't enabled yet, do that now */
1609 if ( assoc_req->secinfo.WPAenabled == 0
1610 && assoc_req->secinfo.WPA2enabled == 0) {
1611 assoc_req->secinfo.WPAenabled = 1;
1612 assoc_req->secinfo.WPA2enabled = 1;
1613 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1614 }
1615
1616 disable_wep (assoc_req);
1617 }
1618
1619out:
1620 if (ret == 0) {
Holger Schurig10078322007-11-15 18:05:47 -05001621 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001622 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001623 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001624 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001625 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001626
Holger Schurig9012b282007-05-25 11:27:16 -04001627 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001628 return ret;
1629}
1630
1631
Holger Schurig10078322007-11-15 18:05:47 -05001632static int lbs_set_genie(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001633 struct iw_request_info *info,
1634 struct iw_point *dwrq,
1635 char *extra)
1636{
Holger Schurig69f90322007-11-23 15:43:44 +01001637 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001638 int ret = 0;
1639 struct assoc_request * assoc_req;
1640
Holger Schurig9012b282007-05-25 11:27:16 -04001641 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001642
David Woodhouseaa21c002007-12-08 20:04:36 +00001643 mutex_lock(&priv->lock);
1644 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001645 if (!assoc_req) {
1646 ret = -ENOMEM;
1647 goto out;
1648 }
1649
1650 if (dwrq->length > MAX_WPA_IE_LEN ||
1651 (dwrq->length && extra == NULL)) {
1652 ret = -EINVAL;
1653 goto out;
1654 }
1655
1656 if (dwrq->length) {
1657 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1658 assoc_req->wpa_ie_len = dwrq->length;
1659 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001660 memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001661 assoc_req->wpa_ie_len = 0;
1662 }
1663
1664out:
1665 if (ret == 0) {
1666 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001667 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001668 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001669 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001670 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001671 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001672
Holger Schurig9012b282007-05-25 11:27:16 -04001673 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001674 return ret;
1675}
1676
Holger Schurig10078322007-11-15 18:05:47 -05001677static int lbs_get_genie(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001678 struct iw_request_info *info,
1679 struct iw_point *dwrq,
1680 char *extra)
1681{
Holger Schurig9012b282007-05-25 11:27:16 -04001682 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001683 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001684
Holger Schurig9012b282007-05-25 11:27:16 -04001685 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001686
David Woodhouseaa21c002007-12-08 20:04:36 +00001687 if (priv->wpa_ie_len == 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001688 dwrq->length = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001689 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001690 }
1691
David Woodhouseaa21c002007-12-08 20:04:36 +00001692 if (dwrq->length < priv->wpa_ie_len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001693 ret = -E2BIG;
1694 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001695 }
1696
David Woodhouseaa21c002007-12-08 20:04:36 +00001697 dwrq->length = priv->wpa_ie_len;
1698 memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001699
Holger Schurig9012b282007-05-25 11:27:16 -04001700out:
1701 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1702 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001703}
1704
1705
Holger Schurig10078322007-11-15 18:05:47 -05001706static int lbs_set_auth(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001707 struct iw_request_info *info,
1708 struct iw_param *dwrq,
1709 char *extra)
1710{
Holger Schurig69f90322007-11-23 15:43:44 +01001711 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001712 struct assoc_request * assoc_req;
1713 int ret = 0;
1714 int updated = 0;
1715
Holger Schurig9012b282007-05-25 11:27:16 -04001716 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001717
David Woodhouseaa21c002007-12-08 20:04:36 +00001718 mutex_lock(&priv->lock);
1719 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001720 if (!assoc_req) {
1721 ret = -ENOMEM;
1722 goto out;
1723 }
1724
1725 switch (dwrq->flags & IW_AUTH_INDEX) {
1726 case IW_AUTH_TKIP_COUNTERMEASURES:
1727 case IW_AUTH_CIPHER_PAIRWISE:
1728 case IW_AUTH_CIPHER_GROUP:
1729 case IW_AUTH_KEY_MGMT:
Dan Williams90a42212007-05-25 23:01:24 -04001730 case IW_AUTH_DROP_UNENCRYPTED:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001731 /*
1732 * libertas does not use these parameters
1733 */
1734 break;
1735
1736 case IW_AUTH_WPA_VERSION:
1737 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1738 assoc_req->secinfo.WPAenabled = 0;
1739 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001740 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001741 }
1742 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1743 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001744 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001745 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001746 }
1747 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1748 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001749 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001750 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001751 }
1752 updated = 1;
1753 break;
1754
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001755 case IW_AUTH_80211_AUTH_ALG:
1756 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04001757 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001758 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04001759 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001760 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04001761 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001762 } else {
1763 ret = -EINVAL;
1764 }
1765 updated = 1;
1766 break;
1767
1768 case IW_AUTH_WPA_ENABLED:
1769 if (dwrq->value) {
1770 if (!assoc_req->secinfo.WPAenabled &&
1771 !assoc_req->secinfo.WPA2enabled) {
1772 assoc_req->secinfo.WPAenabled = 1;
1773 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001774 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001775 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001776 }
1777 } else {
1778 assoc_req->secinfo.WPAenabled = 0;
1779 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001780 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001781 }
1782 updated = 1;
1783 break;
1784
1785 default:
1786 ret = -EOPNOTSUPP;
1787 break;
1788 }
1789
1790out:
1791 if (ret == 0) {
1792 if (updated)
1793 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001794 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001795 } else if (ret != -EOPNOTSUPP) {
Holger Schurig10078322007-11-15 18:05:47 -05001796 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001797 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001798 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001799
Holger Schurig9012b282007-05-25 11:27:16 -04001800 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001801 return ret;
1802}
1803
Holger Schurig10078322007-11-15 18:05:47 -05001804static int lbs_get_auth(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001805 struct iw_request_info *info,
1806 struct iw_param *dwrq,
1807 char *extra)
1808{
Holger Schurig9012b282007-05-25 11:27:16 -04001809 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001810 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001811
Holger Schurig9012b282007-05-25 11:27:16 -04001812 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001813
1814 switch (dwrq->flags & IW_AUTH_INDEX) {
1815 case IW_AUTH_WPA_VERSION:
1816 dwrq->value = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00001817 if (priv->secinfo.WPAenabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001818 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
David Woodhouseaa21c002007-12-08 20:04:36 +00001819 if (priv->secinfo.WPA2enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001820 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1821 if (!dwrq->value)
1822 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1823 break;
1824
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001825 case IW_AUTH_80211_AUTH_ALG:
David Woodhouseaa21c002007-12-08 20:04:36 +00001826 dwrq->value = priv->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001827 break;
1828
1829 case IW_AUTH_WPA_ENABLED:
David Woodhouseaa21c002007-12-08 20:04:36 +00001830 if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001831 dwrq->value = 1;
1832 break;
1833
1834 default:
Holger Schurig9012b282007-05-25 11:27:16 -04001835 ret = -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001836 }
1837
Holger Schurig9012b282007-05-25 11:27:16 -04001838 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1839 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001840}
1841
1842
Holger Schurig10078322007-11-15 18:05:47 -05001843static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001844 struct iw_param *vwrq, char *extra)
1845{
1846 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001847 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001848
1849 u16 dbm;
1850
Holger Schurig9012b282007-05-25 11:27:16 -04001851 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001852
1853 if (vwrq->disabled) {
Holger Schurig10078322007-11-15 18:05:47 -05001854 lbs_radio_ioctl(priv, RADIO_OFF);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001855 return 0;
1856 }
1857
David Woodhouseaa21c002007-12-08 20:04:36 +00001858 priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001859
Holger Schurig10078322007-11-15 18:05:47 -05001860 lbs_radio_ioctl(priv, RADIO_ON);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001861
Jean Tourrilhes9483f032007-08-02 13:16:30 -04001862 /* Userspace check in iwrange if it should use dBm or mW,
1863 * therefore this should never happen... Jean II */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001864 if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
Jean Tourrilhes9483f032007-08-02 13:16:30 -04001865 return -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001866 } else
1867 dbm = (u16) vwrq->value;
1868
1869 /* auto tx power control */
1870
1871 if (vwrq->fixed == 0)
1872 dbm = 0xffff;
1873
Holger Schurig9012b282007-05-25 11:27:16 -04001874 lbs_deb_wext("txpower set %d dbm\n", dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001875
Holger Schurig10078322007-11-15 18:05:47 -05001876 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -04001877 CMD_802_11_RF_TX_POWER,
1878 CMD_ACT_TX_POWER_OPT_SET_LOW,
1879 CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001880
Holger Schurig9012b282007-05-25 11:27:16 -04001881 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001882 return ret;
1883}
1884
Holger Schurig10078322007-11-15 18:05:47 -05001885static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001886 struct iw_point *dwrq, char *extra)
1887{
Holger Schurig69f90322007-11-23 15:43:44 +01001888 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001889
Holger Schurig9012b282007-05-25 11:27:16 -04001890 lbs_deb_enter(LBS_DEB_WEXT);
1891
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001892 /*
1893 * Note : if dwrq->flags != 0, we should get the relevant SSID from
1894 * the SSID list...
1895 */
1896
1897 /*
1898 * Get the current SSID
1899 */
David Woodhouseaa21c002007-12-08 20:04:36 +00001900 if (priv->connect_status == LBS_CONNECTED) {
1901 memcpy(extra, priv->curbssparams.ssid,
1902 priv->curbssparams.ssid_len);
1903 extra[priv->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001904 } else {
1905 memset(extra, 0, 32);
David Woodhouseaa21c002007-12-08 20:04:36 +00001906 extra[priv->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001907 }
1908 /*
1909 * If none, we may want to get the one that was set
1910 */
1911
David Woodhouseaa21c002007-12-08 20:04:36 +00001912 dwrq->length = priv->curbssparams.ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001913
1914 dwrq->flags = 1; /* active */
1915
Holger Schurig9012b282007-05-25 11:27:16 -04001916 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001917 return 0;
1918}
1919
Holger Schurig10078322007-11-15 18:05:47 -05001920static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001921 struct iw_point *dwrq, char *extra)
1922{
Holger Schurig69f90322007-11-23 15:43:44 +01001923 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001924 int ret = 0;
Dan Williamsd8efea22007-05-28 23:54:55 -04001925 u8 ssid[IW_ESSID_MAX_SIZE];
1926 u8 ssid_len = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001927 struct assoc_request * assoc_req;
Dan Williamsd8efea22007-05-28 23:54:55 -04001928 int in_ssid_len = dwrq->length;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001929
Holger Schurig9012b282007-05-25 11:27:16 -04001930 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001931
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001932 /* Check the size of the string */
Dan Williamsd8efea22007-05-28 23:54:55 -04001933 if (in_ssid_len > IW_ESSID_MAX_SIZE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001934 ret = -E2BIG;
1935 goto out;
1936 }
1937
Dan Williamsd8efea22007-05-28 23:54:55 -04001938 memset(&ssid, 0, sizeof(ssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001939
Dan Williamsd8efea22007-05-28 23:54:55 -04001940 if (!dwrq->flags || !in_ssid_len) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001941 /* "any" SSID requested; leave SSID blank */
1942 } else {
1943 /* Specific SSID requested */
Dan Williamsd8efea22007-05-28 23:54:55 -04001944 memcpy(&ssid, extra, in_ssid_len);
1945 ssid_len = in_ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001946 }
1947
Dan Williamsd8efea22007-05-28 23:54:55 -04001948 if (!ssid_len) {
1949 lbs_deb_wext("requested any SSID\n");
1950 } else {
1951 lbs_deb_wext("requested SSID '%s'\n",
1952 escape_essid(ssid, ssid_len));
1953 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001954
1955out:
David Woodhouseaa21c002007-12-08 20:04:36 +00001956 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001957 if (ret == 0) {
1958 /* Get or create the current association request */
David Woodhouseaa21c002007-12-08 20:04:36 +00001959 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001960 if (!assoc_req) {
1961 ret = -ENOMEM;
1962 } else {
1963 /* Copy the SSID to the association request */
Dan Williamsd8efea22007-05-28 23:54:55 -04001964 memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
1965 assoc_req->ssid_len = ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001966 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001967 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001968 }
1969 }
1970
1971 /* Cancel the association request if there was an error */
1972 if (ret != 0) {
Holger Schurig10078322007-11-15 18:05:47 -05001973 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001974 }
1975
David Woodhouseaa21c002007-12-08 20:04:36 +00001976 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001977
Holger Schurig9012b282007-05-25 11:27:16 -04001978 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001979 return ret;
1980}
1981
David Woodhousef5956bf2007-12-11 19:30:57 -05001982static int lbs_mesh_get_essid(struct net_device *dev,
1983 struct iw_request_info *info,
1984 struct iw_point *dwrq, char *extra)
1985{
1986 struct lbs_private *priv = dev->priv;
1987
1988 lbs_deb_enter(LBS_DEB_WEXT);
1989
1990 memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
1991
1992 dwrq->length = priv->mesh_ssid_len;
1993
1994 dwrq->flags = 1; /* active */
1995
1996 lbs_deb_leave(LBS_DEB_WEXT);
1997 return 0;
1998}
1999
2000static int lbs_mesh_set_essid(struct net_device *dev,
2001 struct iw_request_info *info,
2002 struct iw_point *dwrq, char *extra)
2003{
2004 struct lbs_private *priv = dev->priv;
2005 int ret = 0;
2006
2007 lbs_deb_enter(LBS_DEB_WEXT);
2008
2009 /* Check the size of the string */
2010 if (dwrq->length > IW_ESSID_MAX_SIZE) {
2011 ret = -E2BIG;
2012 goto out;
2013 }
2014
2015 if (!dwrq->flags || !dwrq->length) {
2016 ret = -EINVAL;
2017 goto out;
2018 } else {
2019 /* Specific SSID requested */
2020 memcpy(priv->mesh_ssid, extra, dwrq->length);
2021 priv->mesh_ssid_len = dwrq->length;
2022 }
2023
David Woodhouse86062132007-12-13 00:32:36 -05002024 lbs_mesh_config(priv, 1, priv->curbssparams.channel);
David Woodhousef5956bf2007-12-11 19:30:57 -05002025 out:
2026 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2027 return ret;
2028}
2029
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002030/**
2031 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2032 *
2033 * @param dev A pointer to net_device structure
2034 * @param info A pointer to iw_request_info structure
2035 * @param awrq A pointer to iw_param structure
2036 * @param extra A pointer to extra data buf
2037 * @return 0 --success, otherwise fail
2038 */
Holger Schurig10078322007-11-15 18:05:47 -05002039static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002040 struct sockaddr *awrq, char *extra)
2041{
Holger Schurig69f90322007-11-23 15:43:44 +01002042 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002043 struct assoc_request * assoc_req;
2044 int ret = 0;
Joe Perches0795af52007-10-03 17:59:30 -07002045 DECLARE_MAC_BUF(mac);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002046
Holger Schurig9012b282007-05-25 11:27:16 -04002047 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002048
2049 if (awrq->sa_family != ARPHRD_ETHER)
2050 return -EINVAL;
2051
Joe Perches0795af52007-10-03 17:59:30 -07002052 lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002053
David Woodhouseaa21c002007-12-08 20:04:36 +00002054 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002055
2056 /* Get or create the current association request */
David Woodhouseaa21c002007-12-08 20:04:36 +00002057 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002058 if (!assoc_req) {
Holger Schurig10078322007-11-15 18:05:47 -05002059 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002060 ret = -ENOMEM;
2061 } else {
2062 /* Copy the BSSID to the association request */
2063 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2064 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05002065 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002066 }
2067
David Woodhouseaa21c002007-12-08 20:04:36 +00002068 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002069
2070 return ret;
2071}
2072
David Woodhouseaa21c002007-12-08 20:04:36 +00002073void lbs_get_fwversion(struct lbs_private *priv, char *fwversion, int maxlen)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002074{
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002075 char fwver[32];
2076
David Woodhouseaa21c002007-12-08 20:04:36 +00002077 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002078
Holger Schurigdac10a92008-01-16 15:55:22 +01002079 sprintf(fwver, "%u.%u.%u.p%u",
2080 priv->fwrelease >> 24 & 0xff,
2081 priv->fwrelease >> 16 & 0xff,
2082 priv->fwrelease >> 8 & 0xff,
2083 priv->fwrelease & 0xff);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002084
David Woodhouseaa21c002007-12-08 20:04:36 +00002085 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002086 snprintf(fwversion, maxlen, fwver);
2087}
2088
2089
2090/*
2091 * iwconfig settable callbacks
2092 */
Holger Schurig10078322007-11-15 18:05:47 -05002093static const iw_handler lbs_handler[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002094 (iw_handler) NULL, /* SIOCSIWCOMMIT */
Holger Schurig10078322007-11-15 18:05:47 -05002095 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002096 (iw_handler) NULL, /* SIOCSIWNWID */
2097 (iw_handler) NULL, /* SIOCGIWNWID */
Holger Schurig10078322007-11-15 18:05:47 -05002098 (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */
2099 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
2100 (iw_handler) lbs_set_mode, /* SIOCSIWMODE */
2101 (iw_handler) lbs_get_mode, /* SIOCGIWMODE */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002102 (iw_handler) NULL, /* SIOCSIWSENS */
2103 (iw_handler) NULL, /* SIOCGIWSENS */
2104 (iw_handler) NULL, /* SIOCSIWRANGE */
Holger Schurig10078322007-11-15 18:05:47 -05002105 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002106 (iw_handler) NULL, /* SIOCSIWPRIV */
2107 (iw_handler) NULL, /* SIOCGIWPRIV */
2108 (iw_handler) NULL, /* SIOCSIWSTATS */
2109 (iw_handler) NULL, /* SIOCGIWSTATS */
2110 iw_handler_set_spy, /* SIOCSIWSPY */
2111 iw_handler_get_spy, /* SIOCGIWSPY */
2112 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2113 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
Holger Schurig10078322007-11-15 18:05:47 -05002114 (iw_handler) lbs_set_wap, /* SIOCSIWAP */
2115 (iw_handler) lbs_get_wap, /* SIOCGIWAP */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002116 (iw_handler) NULL, /* SIOCSIWMLME */
2117 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
Holger Schurig10078322007-11-15 18:05:47 -05002118 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2119 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
2120 (iw_handler) lbs_set_essid, /* SIOCSIWESSID */
2121 (iw_handler) lbs_get_essid, /* SIOCGIWESSID */
2122 (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */
2123 (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002124 (iw_handler) NULL, /* -- hole -- */
2125 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002126 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2127 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2128 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2129 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2130 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2131 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2132 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2133 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2134 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2135 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2136 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2137 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2138 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2139 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002140 (iw_handler) NULL, /* -- hole -- */
2141 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002142 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2143 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2144 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2145 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2146 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2147 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002148 (iw_handler) NULL, /* SIOCSIWPMKSA */
2149};
2150
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002151static const iw_handler mesh_wlan_handler[] = {
2152 (iw_handler) NULL, /* SIOCSIWCOMMIT */
Holger Schurig10078322007-11-15 18:05:47 -05002153 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002154 (iw_handler) NULL, /* SIOCSIWNWID */
2155 (iw_handler) NULL, /* SIOCGIWNWID */
David Woodhouse823eaa22007-12-11 19:56:28 -05002156 (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
Holger Schurig10078322007-11-15 18:05:47 -05002157 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002158 (iw_handler) NULL, /* SIOCSIWMODE */
2159 (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
2160 (iw_handler) NULL, /* SIOCSIWSENS */
2161 (iw_handler) NULL, /* SIOCGIWSENS */
2162 (iw_handler) NULL, /* SIOCSIWRANGE */
Holger Schurig10078322007-11-15 18:05:47 -05002163 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002164 (iw_handler) NULL, /* SIOCSIWPRIV */
2165 (iw_handler) NULL, /* SIOCGIWPRIV */
2166 (iw_handler) NULL, /* SIOCSIWSTATS */
2167 (iw_handler) NULL, /* SIOCGIWSTATS */
2168 iw_handler_set_spy, /* SIOCSIWSPY */
2169 iw_handler_get_spy, /* SIOCGIWSPY */
2170 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2171 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2172 (iw_handler) NULL, /* SIOCSIWAP */
2173 (iw_handler) NULL, /* SIOCGIWAP */
2174 (iw_handler) NULL, /* SIOCSIWMLME */
2175 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
Holger Schurig10078322007-11-15 18:05:47 -05002176 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2177 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
David Woodhousef5956bf2007-12-11 19:30:57 -05002178 (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
2179 (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002180 (iw_handler) NULL, /* SIOCSIWNICKN */
2181 (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
2182 (iw_handler) NULL, /* -- hole -- */
2183 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002184 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2185 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2186 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2187 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2188 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2189 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2190 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2191 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2192 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2193 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2194 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2195 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2196 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2197 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002198 (iw_handler) NULL, /* -- hole -- */
2199 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002200 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2201 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2202 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2203 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2204 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2205 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002206 (iw_handler) NULL, /* SIOCSIWPMKSA */
2207};
Holger Schurig10078322007-11-15 18:05:47 -05002208struct iw_handler_def lbs_handler_def = {
2209 .num_standard = ARRAY_SIZE(lbs_handler),
2210 .standard = (iw_handler *) lbs_handler,
2211 .get_wireless_stats = lbs_get_wireless_stats,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002212};
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002213
2214struct iw_handler_def mesh_handler_def = {
Denis Chengff8ac602007-09-02 18:30:18 +08002215 .num_standard = ARRAY_SIZE(mesh_wlan_handler),
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002216 .standard = (iw_handler *) mesh_wlan_handler,
Holger Schurig10078322007-11-15 18:05:47 -05002217 .get_wireless_stats = lbs_get_wireless_stats,
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002218};