blob: 38295ee1a05f04f2a18ac6d756374c6c16cc4c4e [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"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020019#include "wext.h"
Holger Schurig245bf202008-04-02 16:27:42 +020020#include "scan.h"
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020021#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;
Dan Williams87c8c722008-08-19 15:15:35 -0400425 s16 curlevel = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426
Holger Schurig9012b282007-05-25 11:27:16 -0400427 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200428
Dan Williams87c8c722008-08-19 15:15:35 -0400429 ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400430 if (ret)
431 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200432
Dan Williams87c8c722008-08-19 15:15:35 -0400433 lbs_deb_wext("tx power level %d dbm\n", curlevel);
434
435 priv->txpower_cur = curlevel;
436 vwrq->value = curlevel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200437 vwrq->fixed = 1;
David Woodhouseaa21c002007-12-08 20:04:36 +0000438 if (priv->radioon) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439 vwrq->disabled = 0;
440 vwrq->flags = IW_TXPOW_DBM;
Dan Williams87c8c722008-08-19 15:15:35 -0400441 } else
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200442 vwrq->disabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200443
Holger Schurig9012b282007-05-25 11:27:16 -0400444out:
445 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
446 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200447}
448
Holger Schurig10078322007-11-15 18:05:47 -0500449static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200450 struct iw_param *vwrq, char *extra)
451{
452 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +0100453 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200454
Holger Schurig9012b282007-05-25 11:27:16 -0400455 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200456
457 if (vwrq->flags == IW_RETRY_LIMIT) {
458 /* The MAC has a 4-bit Total_Tx_Count register
459 Total_Tx_Count = 1 + Tx_Retry_Count */
460#define TX_RETRY_MIN 0
461#define TX_RETRY_MAX 14
462 if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
463 return -EINVAL;
464
465 /* Adding 1 to convert retry count to try count */
David Woodhouseaa21c002007-12-08 20:04:36 +0000466 priv->txretrycount = vwrq->value + 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200467
Holger Schurig10078322007-11-15 18:05:47 -0500468 ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
Dan Williams0aef64d2007-08-02 11:31:18 -0400469 CMD_ACT_SET,
470 CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200471 OID_802_11_TX_RETRYCOUNT, NULL);
472
Holger Schurig9012b282007-05-25 11:27:16 -0400473 if (ret)
474 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200475 } else {
476 return -EOPNOTSUPP;
477 }
478
Holger Schurig9012b282007-05-25 11:27:16 -0400479out:
480 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
481 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482}
483
Holger Schurig10078322007-11-15 18:05:47 -0500484static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200485 struct iw_param *vwrq, char *extra)
486{
Holger Schurig69f90322007-11-23 15:43:44 +0100487 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200488 int ret = 0;
489
Holger Schurig9012b282007-05-25 11:27:16 -0400490 lbs_deb_enter(LBS_DEB_WEXT);
491
David Woodhouseaa21c002007-12-08 20:04:36 +0000492 priv->txretrycount = 0;
Holger Schurig10078322007-11-15 18:05:47 -0500493 ret = lbs_prepare_and_send_command(priv,
Dan Williams0aef64d2007-08-02 11:31:18 -0400494 CMD_802_11_SNMP_MIB,
495 CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200496 OID_802_11_TX_RETRYCOUNT, NULL);
Holger Schurig9012b282007-05-25 11:27:16 -0400497 if (ret)
498 goto out;
499
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200500 vwrq->disabled = 0;
501 if (!vwrq->flags) {
502 vwrq->flags = IW_RETRY_LIMIT;
503 /* Subtract 1 to convert try count to retry count */
David Woodhouseaa21c002007-12-08 20:04:36 +0000504 vwrq->value = priv->txretrycount - 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200505 }
506
Holger Schurig9012b282007-05-25 11:27:16 -0400507out:
508 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
509 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200510}
511
512static inline void sort_channels(struct iw_freq *freq, int num)
513{
514 int i, j;
515 struct iw_freq temp;
516
517 for (i = 0; i < num; i++)
518 for (j = i + 1; j < num; j++)
519 if (freq[i].i > freq[j].i) {
520 temp.i = freq[i].i;
521 temp.m = freq[i].m;
522
523 freq[i].i = freq[j].i;
524 freq[i].m = freq[j].m;
525
526 freq[j].i = temp.i;
527 freq[j].m = temp.m;
528 }
529}
530
531/* data rate listing
532 MULTI_BANDS:
533 abg a b b/g
534 Infra G(12) A(8) B(4) G(12)
535 Adhoc A+B(12) A(8) B(4) B(4)
536
537 non-MULTI_BANDS:
538 b b/g
539 Infra B(4) G(12)
540 Adhoc B(4) B(4)
541 */
542/**
543 * @brief Get Range Info
544 *
545 * @param dev A pointer to net_device structure
546 * @param info A pointer to iw_request_info structure
547 * @param vwrq A pointer to iw_param structure
548 * @param extra A pointer to extra data buf
549 * @return 0 --success, otherwise fail
550 */
Holger Schurig10078322007-11-15 18:05:47 -0500551static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200552 struct iw_point *dwrq, char *extra)
553{
554 int i, j;
Holger Schurig69f90322007-11-23 15:43:44 +0100555 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200556 struct iw_range *range = (struct iw_range *)extra;
557 struct chan_freq_power *cfp;
Dan Williams8c512762007-08-02 11:40:45 -0400558 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200559
560 u8 flag = 0;
561
Holger Schurig9012b282007-05-25 11:27:16 -0400562 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200563
564 dwrq->length = sizeof(struct iw_range);
565 memset(range, 0, sizeof(struct iw_range));
566
567 range->min_nwid = 0;
568 range->max_nwid = 0;
569
570 memset(rates, 0, sizeof(rates));
David Woodhouseaa21c002007-12-08 20:04:36 +0000571 copy_active_data_rates(priv, rates);
Dan Williams8c512762007-08-02 11:40:45 -0400572 range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
573 for (i = 0; i < range->num_bitrates; i++)
574 range->bitrate[i] = rates[i] * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200575 range->num_bitrates = i;
Holger Schurig9012b282007-05-25 11:27:16 -0400576 lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200577 range->num_bitrates);
578
579 range->num_frequency = 0;
Holger Schurig52933d82008-03-05 07:05:32 +0100580
581 range->scan_capa = IW_SCAN_CAPA_ESSID;
582
David Woodhouseaa21c002007-12-08 20:04:36 +0000583 if (priv->enable11d &&
584 (priv->connect_status == LBS_CONNECTED ||
585 priv->mesh_connect_status == LBS_CONNECTED)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200586 u8 chan_no;
587 u8 band;
588
589 struct parsed_region_chan_11d *parsed_region_chan =
David Woodhouseaa21c002007-12-08 20:04:36 +0000590 &priv->parsed_region_chan;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200591
592 if (parsed_region_chan == NULL) {
Holger Schurig9012b282007-05-25 11:27:16 -0400593 lbs_deb_wext("11d: parsed_region_chan is NULL\n");
594 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200595 }
596 band = parsed_region_chan->band;
Holger Schurig9012b282007-05-25 11:27:16 -0400597 lbs_deb_wext("band %d, nr_char %d\n", band,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200598 parsed_region_chan->nr_chan);
599
600 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
601 && (i < parsed_region_chan->nr_chan); i++) {
602 chan_no = parsed_region_chan->chanpwr[i].chan;
Holger Schurig9012b282007-05-25 11:27:16 -0400603 lbs_deb_wext("chan_no %d\n", chan_no);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200604 range->freq[range->num_frequency].i = (long)chan_no;
605 range->freq[range->num_frequency].m =
Holger Schurige98a88d2008-03-19 14:25:58 +0100606 (long)lbs_chan_2_freq(chan_no) * 100000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200607 range->freq[range->num_frequency].e = 1;
608 range->num_frequency++;
609 }
610 flag = 1;
611 }
612 if (!flag) {
613 for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
David Woodhouseaa21c002007-12-08 20:04:36 +0000614 && (j < ARRAY_SIZE(priv->region_channel)); j++) {
615 cfp = priv->region_channel[j].CFP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200616 for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
David Woodhouseaa21c002007-12-08 20:04:36 +0000617 && priv->region_channel[j].valid
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200618 && cfp
David Woodhouseaa21c002007-12-08 20:04:36 +0000619 && (i < priv->region_channel[j].nrcfp); i++) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200620 range->freq[range->num_frequency].i =
621 (long)cfp->channel;
622 range->freq[range->num_frequency].m =
623 (long)cfp->freq * 100000;
624 range->freq[range->num_frequency].e = 1;
625 cfp++;
626 range->num_frequency++;
627 }
628 }
629 }
630
Holger Schurig9012b282007-05-25 11:27:16 -0400631 lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200632 IW_MAX_FREQUENCIES, range->num_frequency);
633
634 range->num_channels = range->num_frequency;
635
636 sort_channels(&range->freq[0], range->num_frequency);
637
638 /*
639 * Set an indication of the max TCP throughput in bit/s that we can
640 * expect using this interface
641 */
642 if (i > 2)
643 range->throughput = 5000 * 1000;
644 else
645 range->throughput = 1500 * 1000;
646
647 range->min_rts = MRVDRV_RTS_MIN_VALUE;
648 range->max_rts = MRVDRV_RTS_MAX_VALUE;
649 range->min_frag = MRVDRV_FRAG_MIN_VALUE;
650 range->max_frag = MRVDRV_FRAG_MAX_VALUE;
651
652 range->encoding_size[0] = 5;
653 range->encoding_size[1] = 13;
654 range->num_encoding_sizes = 2;
655 range->max_encoding_tokens = 4;
656
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100657 /*
658 * Right now we support only "iwconfig ethX power on|off"
659 */
660 range->pm_capa = IW_POWER_ON;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200661
662 /*
663 * Minimum version we recommend
664 */
665 range->we_version_source = 15;
666
667 /*
668 * Version we are compiled with
669 */
670 range->we_version_compiled = WIRELESS_EXT;
671
672 range->retry_capa = IW_RETRY_LIMIT;
673 range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
674
675 range->min_retry = TX_RETRY_MIN;
676 range->max_retry = TX_RETRY_MAX;
677
678 /*
679 * Set the qual, level and noise range values
680 */
681 range->max_qual.qual = 100;
682 range->max_qual.level = 0;
683 range->max_qual.noise = 0;
684 range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
685
686 range->avg_qual.qual = 70;
687 /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
688 range->avg_qual.level = 0;
689 range->avg_qual.noise = 0;
690 range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
691
692 range->sensitivity = 0;
693
Dan Williams87c8c722008-08-19 15:15:35 -0400694 /* Setup the supported power level ranges */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200695 memset(range->txpower, 0, sizeof(range->txpower));
Dan Williams87c8c722008-08-19 15:15:35 -0400696 range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;
697 range->txpower[0] = priv->txpower_min;
698 range->txpower[1] = priv->txpower_max;
699 range->num_txpower = 2;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200700
701 range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
702 IW_EVENT_CAPA_MASK(SIOCGIWAP) |
703 IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
704 range->event_capa[1] = IW_EVENT_CAPA_K_1;
705
David Woodhouseaa21c002007-12-08 20:04:36 +0000706 if (priv->fwcapinfo & FW_CAPINFO_WPA) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200707 range->enc_capa = IW_ENC_CAPA_WPA
708 | IW_ENC_CAPA_WPA2
709 | IW_ENC_CAPA_CIPHER_TKIP
710 | IW_ENC_CAPA_CIPHER_CCMP;
711 }
712
Holger Schurig9012b282007-05-25 11:27:16 -0400713out:
714 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200715 return 0;
716}
717
Holger Schurig10078322007-11-15 18:05:47 -0500718static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200719 struct iw_param *vwrq, char *extra)
720{
Holger Schurig69f90322007-11-23 15:43:44 +0100721 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200722
Holger Schurig9012b282007-05-25 11:27:16 -0400723 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200724
David Woodhouseb2c57ee2007-12-17 14:41:13 -0500725 if (!priv->ps_supported) {
726 if (vwrq->disabled)
727 return 0;
728 else
729 return -EINVAL;
730 }
731
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200732 /* PS is currently supported only in Infrastructure mode
733 * Remove this check if it is to be supported in IBSS mode also
734 */
735
736 if (vwrq->disabled) {
David Woodhouseaa21c002007-12-08 20:04:36 +0000737 priv->psmode = LBS802_11POWERMODECAM;
738 if (priv->psstate != PS_STATE_FULL_POWER) {
Holger Schurig10078322007-11-15 18:05:47 -0500739 lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200740 }
741
742 return 0;
743 }
744
745 if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
Holger Schurig9012b282007-05-25 11:27:16 -0400746 lbs_deb_wext(
747 "setting power timeout is not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200748 return -EINVAL;
749 } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
Holger Schurig9012b282007-05-25 11:27:16 -0400750 lbs_deb_wext("setting power period not supported\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200751 return -EINVAL;
752 }
753
David Woodhouseaa21c002007-12-08 20:04:36 +0000754 if (priv->psmode != LBS802_11POWERMODECAM) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200755 return 0;
756 }
757
David Woodhouseaa21c002007-12-08 20:04:36 +0000758 priv->psmode = LBS802_11POWERMODEMAX_PSP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200759
David Woodhouseaa21c002007-12-08 20:04:36 +0000760 if (priv->connect_status == LBS_CONNECTED) {
Holger Schurig10078322007-11-15 18:05:47 -0500761 lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200762 }
763
Holger Schurig9012b282007-05-25 11:27:16 -0400764 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200765 return 0;
766}
767
Holger Schurig10078322007-11-15 18:05:47 -0500768static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200769 struct iw_param *vwrq, char *extra)
770{
Holger Schurig69f90322007-11-23 15:43:44 +0100771 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200772
Holger Schurig9012b282007-05-25 11:27:16 -0400773 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200774
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200775 vwrq->value = 0;
Holger Schurigd4ff0ef2008-03-19 14:25:18 +0100776 vwrq->flags = 0;
777 vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM
778 || priv->connect_status == LBS_DISCONNECTED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200779
Holger Schurig9012b282007-05-25 11:27:16 -0400780 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200781 return 0;
782}
783
Holger Schurig10078322007-11-15 18:05:47 -0500784static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200785{
786 enum {
787 POOR = 30,
788 FAIR = 60,
789 GOOD = 80,
790 VERY_GOOD = 90,
791 EXCELLENT = 95,
792 PERFECT = 100
793 };
Holger Schurig69f90322007-11-23 15:43:44 +0100794 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200795 u32 rssi_qual;
796 u32 tx_qual;
797 u32 quality = 0;
798 int stats_valid = 0;
799 u8 rssi;
800 u32 tx_retries;
Holger Schurigc49c3b72008-03-17 12:45:58 +0100801 struct cmd_ds_802_11_get_log log;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200802
Holger Schurig9012b282007-05-25 11:27:16 -0400803 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200804
David Woodhouseaa21c002007-12-08 20:04:36 +0000805 priv->wstats.status = priv->mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200806
807 /* If we're not associated, all quality values are meaningless */
David Woodhouseaa21c002007-12-08 20:04:36 +0000808 if ((priv->connect_status != LBS_CONNECTED) &&
809 (priv->mesh_connect_status != LBS_CONNECTED))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200810 goto out;
811
812 /* Quality by RSSI */
813 priv->wstats.qual.level =
David Woodhouseaa21c002007-12-08 20:04:36 +0000814 CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
815 priv->NF[TYPE_BEACON][TYPE_NOAVG]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200816
David Woodhouseaa21c002007-12-08 20:04:36 +0000817 if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200818 priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
819 } else {
820 priv->wstats.qual.noise =
David Woodhouseaa21c002007-12-08 20:04:36 +0000821 CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200822 }
823
Holger Schurig9012b282007-05-25 11:27:16 -0400824 lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);
825 lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200826
827 rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
828 if (rssi < 15)
829 rssi_qual = rssi * POOR / 10;
830 else if (rssi < 20)
831 rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
832 else if (rssi < 30)
833 rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
834 else if (rssi < 40)
835 rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
836 10 + GOOD;
837 else
838 rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
839 10 + VERY_GOOD;
840 quality = rssi_qual;
841
842 /* Quality by TX errors */
843 priv->wstats.discard.retries = priv->stats.tx_errors;
844
Holger Schurigc49c3b72008-03-17 12:45:58 +0100845 memset(&log, 0, sizeof(log));
846 log.hdr.size = cpu_to_le16(sizeof(log));
847 lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);
848
849 tx_retries = le32_to_cpu(log.retry);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200850
851 if (tx_retries > 75)
852 tx_qual = (90 - tx_retries) * POOR / 15;
853 else if (tx_retries > 70)
854 tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
855 else if (tx_retries > 65)
856 tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
857 else if (tx_retries > 50)
858 tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
859 15 + GOOD;
860 else
861 tx_qual = (50 - tx_retries) *
862 (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
863 quality = min(quality, tx_qual);
864
Holger Schurigc49c3b72008-03-17 12:45:58 +0100865 priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200866 priv->wstats.discard.retries = tx_retries;
Holger Schurigc49c3b72008-03-17 12:45:58 +0100867 priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200868
869 /* Calculate quality */
Holger Schurigcad9d9b2007-08-02 13:07:15 -0400870 priv->wstats.qual.qual = min_t(u8, quality, 100);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200871 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
872 stats_valid = 1;
873
874 /* update stats asynchronously for future calls */
Holger Schurig10078322007-11-15 18:05:47 -0500875 lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200876 0, 0, NULL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200877out:
878 if (!stats_valid) {
879 priv->wstats.miss.beacon = 0;
880 priv->wstats.discard.retries = 0;
881 priv->wstats.qual.qual = 0;
882 priv->wstats.qual.level = 0;
883 priv->wstats.qual.noise = 0;
884 priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
885 priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
886 IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
887 }
888
Holger Schurig9012b282007-05-25 11:27:16 -0400889 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200890 return &priv->wstats;
891
892
893}
894
Holger Schurig10078322007-11-15 18:05:47 -0500895static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200896 struct iw_freq *fwrq, char *extra)
897{
Dan Williamsef9a2642007-05-25 16:46:33 -0400898 int ret = -EINVAL;
Holger Schurig69f90322007-11-23 15:43:44 +0100899 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200900 struct chan_freq_power *cfp;
Dan Williamsef9a2642007-05-25 16:46:33 -0400901 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200902
Holger Schurig9012b282007-05-25 11:27:16 -0400903 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200904
David Woodhouseaa21c002007-12-08 20:04:36 +0000905 mutex_lock(&priv->lock);
906 assoc_req = lbs_get_association_request(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400907 if (!assoc_req) {
908 ret = -ENOMEM;
909 goto out;
910 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200911
Dan Williamsef9a2642007-05-25 16:46:33 -0400912 /* If setting by frequency, convert to a channel */
913 if (fwrq->e == 1) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200914 long f = fwrq->m / 100000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200915
David Woodhouseaa21c002007-12-08 20:04:36 +0000916 cfp = find_cfp_by_band_and_freq(priv, 0, f);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200917 if (!cfp) {
Holger Schurig9012b282007-05-25 11:27:16 -0400918 lbs_deb_wext("invalid freq %ld\n", f);
Dan Williamsef9a2642007-05-25 16:46:33 -0400919 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200920 }
921
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200922 fwrq->e = 0;
Dan Williamsef9a2642007-05-25 16:46:33 -0400923 fwrq->m = (int) cfp->channel;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200924 }
925
Dan Williamsef9a2642007-05-25 16:46:33 -0400926 /* Setting by channel number */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200927 if (fwrq->m > 1000 || fwrq->e > 0) {
Dan Williamsef9a2642007-05-25 16:46:33 -0400928 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200929 }
930
David Woodhouseaa21c002007-12-08 20:04:36 +0000931 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
Dan Williamsef9a2642007-05-25 16:46:33 -0400932 if (!cfp) {
933 goto out;
934 }
935
936 assoc_req->channel = fwrq->m;
937 ret = 0;
938
Holger Schurig9012b282007-05-25 11:27:16 -0400939out:
Dan Williamsef9a2642007-05-25 16:46:33 -0400940 if (ret == 0) {
941 set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -0500942 lbs_postpone_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400943 } else {
Holger Schurig10078322007-11-15 18:05:47 -0500944 lbs_cancel_association_work(priv);
Dan Williamsef9a2642007-05-25 16:46:33 -0400945 }
David Woodhouseaa21c002007-12-08 20:04:36 +0000946 mutex_unlock(&priv->lock);
Dan Williamsef9a2642007-05-25 16:46:33 -0400947
948 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
949 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200950}
951
David Woodhouse823eaa22007-12-11 19:56:28 -0500952static int lbs_mesh_set_freq(struct net_device *dev,
953 struct iw_request_info *info,
954 struct iw_freq *fwrq, char *extra)
955{
956 struct lbs_private *priv = dev->priv;
957 struct chan_freq_power *cfp;
958 int ret = -EINVAL;
959
960 lbs_deb_enter(LBS_DEB_WEXT);
961
962 /* If setting by frequency, convert to a channel */
963 if (fwrq->e == 1) {
964 long f = fwrq->m / 100000;
965
966 cfp = find_cfp_by_band_and_freq(priv, 0, f);
967 if (!cfp) {
968 lbs_deb_wext("invalid freq %ld\n", f);
969 goto out;
970 }
971
972 fwrq->e = 0;
973 fwrq->m = (int) cfp->channel;
974 }
975
976 /* Setting by channel number */
977 if (fwrq->m > 1000 || fwrq->e > 0) {
978 goto out;
979 }
980
981 cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);
982 if (!cfp) {
983 goto out;
984 }
985
986 if (fwrq->m != priv->curbssparams.channel) {
987 lbs_deb_wext("mesh channel change forces eth disconnect\n");
988 if (priv->mode == IW_MODE_INFRA)
Dan Williams191bb402008-08-21 17:46:18 -0400989 lbs_cmd_80211_deauthenticate(priv,
990 priv->curbssparams.bssid,
991 WLAN_REASON_DEAUTH_LEAVING);
David Woodhouse823eaa22007-12-11 19:56:28 -0500992 else if (priv->mode == IW_MODE_ADHOC)
993 lbs_stop_adhoc_network(priv);
994 }
Javier Cardonaedaea5c2008-05-17 00:55:10 -0700995 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);
David Woodhouse86062132007-12-13 00:32:36 -0500996 lbs_update_channel(priv);
David Woodhouse823eaa22007-12-11 19:56:28 -0500997 ret = 0;
998
999out:
1000 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1001 return ret;
1002}
1003
Holger Schurig10078322007-11-15 18:05:47 -05001004static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001005 struct iw_param *vwrq, char *extra)
1006{
Holger Schurig69f90322007-11-23 15:43:44 +01001007 struct lbs_private *priv = dev->priv;
Dan Williams8e3c91b2007-12-11 15:50:59 -05001008 u8 new_rate = 0;
Dan Williams8c512762007-08-02 11:40:45 -04001009 int ret = -EINVAL;
1010 u8 rates[MAX_RATES + 1];
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001011
Holger Schurig9012b282007-05-25 11:27:16 -04001012 lbs_deb_enter(LBS_DEB_WEXT);
Holger Schurig9012b282007-05-25 11:27:16 -04001013 lbs_deb_wext("vwrq->value %d\n", vwrq->value);
Javier Cardona85319f92008-05-24 10:59:49 +01001014 lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);
1015
1016 if (vwrq->fixed && vwrq->value == -1)
1017 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001018
Dan Williams8c512762007-08-02 11:40:45 -04001019 /* Auto rate? */
Javier Cardona85319f92008-05-24 10:59:49 +01001020 priv->enablehwauto = !vwrq->fixed;
1021
1022 if (vwrq->value == -1)
David Woodhouseaa21c002007-12-08 20:04:36 +00001023 priv->cur_rate = 0;
Javier Cardona85319f92008-05-24 10:59:49 +01001024 else {
Dan Williams8c512762007-08-02 11:40:45 -04001025 if (vwrq->value % 100000)
1026 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001027
Javier Cardona85319f92008-05-24 10:59:49 +01001028 new_rate = vwrq->value / 500000;
1029 priv->cur_rate = new_rate;
1030 /* the rest is only needed for lbs_set_data_rate() */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001031 memset(rates, 0, sizeof(rates));
David Woodhouseaa21c002007-12-08 20:04:36 +00001032 copy_active_data_rates(priv, rates);
Dan Williams8c512762007-08-02 11:40:45 -04001033 if (!memchr(rates, new_rate, sizeof(rates))) {
1034 lbs_pr_alert("fixed data rate 0x%X out of range\n",
1035 new_rate);
1036 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001037 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001038 }
1039
Javier Cardona85319f92008-05-24 10:59:49 +01001040 /* Try the newer command first (Firmware Spec 5.1 and above) */
1041 ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);
1042
1043 /* Fallback to older version */
1044 if (ret)
1045 ret = lbs_set_data_rate(priv, new_rate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001046
Dan Williams8c512762007-08-02 11:40:45 -04001047out:
Holger Schurig9012b282007-05-25 11:27:16 -04001048 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001049 return ret;
1050}
1051
Holger Schurig10078322007-11-15 18:05:47 -05001052static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001053 struct iw_param *vwrq, char *extra)
1054{
Holger Schurig69f90322007-11-23 15:43:44 +01001055 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001056
Holger Schurig9012b282007-05-25 11:27:16 -04001057 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001058
David Woodhouseaa21c002007-12-08 20:04:36 +00001059 if (priv->connect_status == LBS_CONNECTED) {
1060 vwrq->value = priv->cur_rate * 500000;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001061
Javier Cardona85319f92008-05-24 10:59:49 +01001062 if (priv->enablehwauto)
Dan Williams8c512762007-08-02 11:40:45 -04001063 vwrq->fixed = 0;
1064 else
1065 vwrq->fixed = 1;
1066
1067 } else {
1068 vwrq->fixed = 0;
1069 vwrq->value = 0;
1070 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001071
Holger Schurig9012b282007-05-25 11:27:16 -04001072 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001073 return 0;
1074}
1075
Holger Schurig10078322007-11-15 18:05:47 -05001076static int lbs_set_mode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001077 struct iw_request_info *info, u32 * uwrq, char *extra)
1078{
1079 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001080 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001081 struct assoc_request * assoc_req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001082
Holger Schurig9012b282007-05-25 11:27:16 -04001083 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001084
Dan Williams0dc5a292007-05-10 22:58:02 -04001085 if ( (*uwrq != IW_MODE_ADHOC)
1086 && (*uwrq != IW_MODE_INFRA)
1087 && (*uwrq != IW_MODE_AUTO)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001088 lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);
Dan Williams0dc5a292007-05-10 22:58:02 -04001089 ret = -EINVAL;
1090 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001091 }
1092
David Woodhouseaa21c002007-12-08 20:04:36 +00001093 mutex_lock(&priv->lock);
1094 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001095 if (!assoc_req) {
1096 ret = -ENOMEM;
Holger Schurig10078322007-11-15 18:05:47 -05001097 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001098 } else {
Dan Williams0dc5a292007-05-10 22:58:02 -04001099 assoc_req->mode = *uwrq;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001100 set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001101 lbs_postpone_association_work(priv);
Holger Schurig9012b282007-05-25 11:27:16 -04001102 lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001103 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001104 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001105
Dan Williams0dc5a292007-05-10 22:58:02 -04001106out:
Holger Schurig9012b282007-05-25 11:27:16 -04001107 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001108 return ret;
1109}
1110
1111
1112/**
1113 * @brief Get Encryption key
1114 *
1115 * @param dev A pointer to net_device structure
1116 * @param info A pointer to iw_request_info structure
1117 * @param vwrq A pointer to iw_param structure
1118 * @param extra A pointer to extra data buf
1119 * @return 0 --success, otherwise fail
1120 */
Holger Schurig10078322007-11-15 18:05:47 -05001121static int lbs_get_encode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001122 struct iw_request_info *info,
1123 struct iw_point *dwrq, u8 * extra)
1124{
Holger Schurig69f90322007-11-23 15:43:44 +01001125 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001126 int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1127
Holger Schurig9012b282007-05-25 11:27:16 -04001128 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001129
Holger Schurig9012b282007-05-25 11:27:16 -04001130 lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",
David Woodhouseaa21c002007-12-08 20:04:36 +00001131 dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001132
1133 dwrq->flags = 0;
1134
1135 /* Authentication method */
David Woodhouseaa21c002007-12-08 20:04:36 +00001136 switch (priv->secinfo.auth_mode) {
Dan Williams6affe782007-05-10 22:56:42 -04001137 case IW_AUTH_ALG_OPEN_SYSTEM:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001138 dwrq->flags = IW_ENCODE_OPEN;
1139 break;
1140
Dan Williams6affe782007-05-10 22:56:42 -04001141 case IW_AUTH_ALG_SHARED_KEY:
1142 case IW_AUTH_ALG_LEAP:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001143 dwrq->flags = IW_ENCODE_RESTRICTED;
1144 break;
1145 default:
1146 dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
1147 break;
1148 }
1149
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001150 memset(extra, 0, 16);
1151
David Woodhouseaa21c002007-12-08 20:04:36 +00001152 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001153
1154 /* Default to returning current transmit key */
1155 if (index < 0)
David Woodhouseaa21c002007-12-08 20:04:36 +00001156 index = priv->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001157
David Woodhouseaa21c002007-12-08 20:04:36 +00001158 if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {
1159 memcpy(extra, priv->wep_keys[index].key,
1160 priv->wep_keys[index].len);
1161 dwrq->length = priv->wep_keys[index].len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001162
1163 dwrq->flags |= (index + 1);
1164 /* Return WEP enabled */
1165 dwrq->flags &= ~IW_ENCODE_DISABLED;
David Woodhouseaa21c002007-12-08 20:04:36 +00001166 } else if ((priv->secinfo.WPAenabled)
1167 || (priv->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001168 /* return WPA enabled */
1169 dwrq->flags &= ~IW_ENCODE_DISABLED;
David Woodhousec12bdc42007-12-07 19:32:12 +00001170 dwrq->flags |= IW_ENCODE_NOKEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001171 } else {
1172 dwrq->flags |= IW_ENCODE_DISABLED;
1173 }
1174
David Woodhouseaa21c002007-12-08 20:04:36 +00001175 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001176
Joe Perches0795af52007-10-03 17:59:30 -07001177 lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001178 extra[0], extra[1], extra[2],
1179 extra[3], extra[4], extra[5], dwrq->length);
1180
Holger Schurig9012b282007-05-25 11:27:16 -04001181 lbs_deb_wext("return flags 0x%x\n", dwrq->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001182
Holger Schurig9012b282007-05-25 11:27:16 -04001183 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001184 return 0;
1185}
1186
1187/**
1188 * @brief Set Encryption key (internal)
1189 *
1190 * @param priv A pointer to private card structure
1191 * @param key_material A pointer to key material
1192 * @param key_length length of key material
1193 * @param index key index to set
1194 * @param set_tx_key Force set TX key (1 = yes, 0 = no)
1195 * @return 0 --success, otherwise fail
1196 */
Holger Schurig10078322007-11-15 18:05:47 -05001197static int lbs_set_wep_key(struct assoc_request *assoc_req,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001198 const char *key_material,
1199 u16 key_length,
1200 u16 index,
1201 int set_tx_key)
1202{
Holger Schurig9012b282007-05-25 11:27:16 -04001203 int ret = 0;
Dan Williams1443b652007-08-02 10:45:55 -04001204 struct enc_key *pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001205
Holger Schurig9012b282007-05-25 11:27:16 -04001206 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001207
1208 /* Paranoid validation of key index */
1209 if (index > 3) {
Holger Schurig9012b282007-05-25 11:27:16 -04001210 ret = -EINVAL;
1211 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001212 }
1213
1214 /* validate max key length */
1215 if (key_length > KEY_LEN_WEP_104) {
Holger Schurig9012b282007-05-25 11:27:16 -04001216 ret = -EINVAL;
1217 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001218 }
1219
1220 pkey = &assoc_req->wep_keys[index];
1221
1222 if (key_length > 0) {
Dan Williams1443b652007-08-02 10:45:55 -04001223 memset(pkey, 0, sizeof(struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001224 pkey->type = KEY_TYPE_ID_WEP;
1225
1226 /* Standardize the key length */
1227 pkey->len = (key_length > KEY_LEN_WEP_40) ?
1228 KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
1229 memcpy(pkey->key, key_material, key_length);
1230 }
1231
1232 if (set_tx_key) {
1233 /* Ensure the chosen key is valid */
1234 if (!pkey->len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001235 lbs_deb_wext("key not set, so cannot enable it\n");
1236 ret = -EINVAL;
1237 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001238 }
1239 assoc_req->wep_tx_keyidx = index;
1240 }
1241
Dan Williams889c05b2007-05-10 22:57:23 -04001242 assoc_req->secinfo.wep_enabled = 1;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001243
Holger Schurig9012b282007-05-25 11:27:16 -04001244out:
1245 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1246 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001247}
1248
1249static int validate_key_index(u16 def_index, u16 raw_index,
1250 u16 *out_index, u16 *is_default)
1251{
1252 if (!out_index || !is_default)
1253 return -EINVAL;
1254
1255 /* Verify index if present, otherwise use default TX key index */
1256 if (raw_index > 0) {
1257 if (raw_index > 4)
1258 return -EINVAL;
1259 *out_index = raw_index - 1;
1260 } else {
1261 *out_index = def_index;
1262 *is_default = 1;
1263 }
1264 return 0;
1265}
1266
1267static void disable_wep(struct assoc_request *assoc_req)
1268{
1269 int i;
1270
Dan Williams90a42212007-05-25 23:01:24 -04001271 lbs_deb_enter(LBS_DEB_WEXT);
1272
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001273 /* Set Open System auth mode */
Dan Williams6affe782007-05-10 22:56:42 -04001274 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001275
1276 /* Clear WEP keys and mark WEP as disabled */
Dan Williams889c05b2007-05-10 22:57:23 -04001277 assoc_req->secinfo.wep_enabled = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001278 for (i = 0; i < 4; i++)
1279 assoc_req->wep_keys[i].len = 0;
1280
1281 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1282 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
Dan Williams90a42212007-05-25 23:01:24 -04001283
1284 lbs_deb_leave(LBS_DEB_WEXT);
1285}
1286
1287static void disable_wpa(struct assoc_request *assoc_req)
1288{
1289 lbs_deb_enter(LBS_DEB_WEXT);
1290
Dan Williams1443b652007-08-02 10:45:55 -04001291 memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001292 assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
1293 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1294
Dan Williams1443b652007-08-02 10:45:55 -04001295 memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
Dan Williams90a42212007-05-25 23:01:24 -04001296 assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
1297 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1298
1299 assoc_req->secinfo.WPAenabled = 0;
1300 assoc_req->secinfo.WPA2enabled = 0;
1301 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1302
1303 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001304}
1305
1306/**
1307 * @brief Set Encryption key
1308 *
1309 * @param dev A pointer to net_device structure
1310 * @param info A pointer to iw_request_info structure
1311 * @param vwrq A pointer to iw_param structure
1312 * @param extra A pointer to extra data buf
1313 * @return 0 --success, otherwise fail
1314 */
Holger Schurig10078322007-11-15 18:05:47 -05001315static int lbs_set_encode(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001316 struct iw_request_info *info,
1317 struct iw_point *dwrq, char *extra)
1318{
1319 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001320 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001321 struct assoc_request * assoc_req;
1322 u16 is_default = 0, index = 0, set_tx_key = 0;
1323
Holger Schurig9012b282007-05-25 11:27:16 -04001324 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001325
David Woodhouseaa21c002007-12-08 20:04:36 +00001326 mutex_lock(&priv->lock);
1327 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001328 if (!assoc_req) {
1329 ret = -ENOMEM;
1330 goto out;
1331 }
1332
1333 if (dwrq->flags & IW_ENCODE_DISABLED) {
1334 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001335 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001336 goto out;
1337 }
1338
1339 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1340 (dwrq->flags & IW_ENCODE_INDEX),
1341 &index, &is_default);
1342 if (ret) {
1343 ret = -EINVAL;
1344 goto out;
1345 }
1346
1347 /* If WEP isn't enabled, or if there is no key data but a valid
1348 * index, set the TX key.
1349 */
Dan Williams889c05b2007-05-10 22:57:23 -04001350 if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001351 set_tx_key = 1;
1352
Holger Schurig10078322007-11-15 18:05:47 -05001353 ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001354 if (ret)
1355 goto out;
1356
1357 if (dwrq->length)
1358 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1359 if (set_tx_key)
1360 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
1361
1362 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001363 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001364 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001365 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001366 }
1367
1368out:
1369 if (ret == 0) {
1370 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001371 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001372 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001373 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001374 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001375 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001376
Holger Schurig9012b282007-05-25 11:27:16 -04001377 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001378 return ret;
1379}
1380
1381/**
1382 * @brief Get Extended Encryption key (WPA/802.1x and WEP)
1383 *
1384 * @param dev A pointer to net_device structure
1385 * @param info A pointer to iw_request_info structure
1386 * @param vwrq A pointer to iw_param structure
1387 * @param extra A pointer to extra data buf
1388 * @return 0 on success, otherwise failure
1389 */
Holger Schurig10078322007-11-15 18:05:47 -05001390static int lbs_get_encodeext(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001391 struct iw_request_info *info,
1392 struct iw_point *dwrq,
1393 char *extra)
1394{
1395 int ret = -EINVAL;
Holger Schurig69f90322007-11-23 15:43:44 +01001396 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001397 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1398 int index, max_key_len;
1399
Holger Schurig9012b282007-05-25 11:27:16 -04001400 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001401
1402 max_key_len = dwrq->length - sizeof(*ext);
1403 if (max_key_len < 0)
1404 goto out;
1405
1406 index = dwrq->flags & IW_ENCODE_INDEX;
1407 if (index) {
1408 if (index < 1 || index > 4)
1409 goto out;
1410 index--;
1411 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001412 index = priv->wep_tx_keyidx;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001413 }
1414
Roel Kluinf59d9782007-10-26 21:51:26 +02001415 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001416 ext->alg != IW_ENCODE_ALG_WEP) {
David Woodhouseaa21c002007-12-08 20:04:36 +00001417 if (index != 0 || priv->mode != IW_MODE_INFRA)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001418 goto out;
1419 }
1420
1421 dwrq->flags = index + 1;
1422 memset(ext, 0, sizeof(*ext));
1423
David Woodhouseaa21c002007-12-08 20:04:36 +00001424 if ( !priv->secinfo.wep_enabled
1425 && !priv->secinfo.WPAenabled
1426 && !priv->secinfo.WPA2enabled) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001427 ext->alg = IW_ENCODE_ALG_NONE;
1428 ext->key_len = 0;
1429 dwrq->flags |= IW_ENCODE_DISABLED;
1430 } else {
1431 u8 *key = NULL;
1432
David Woodhouseaa21c002007-12-08 20:04:36 +00001433 if ( priv->secinfo.wep_enabled
1434 && !priv->secinfo.WPAenabled
1435 && !priv->secinfo.WPA2enabled) {
Dan Williams90a42212007-05-25 23:01:24 -04001436 /* WEP */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001437 ext->alg = IW_ENCODE_ALG_WEP;
David Woodhouseaa21c002007-12-08 20:04:36 +00001438 ext->key_len = priv->wep_keys[index].len;
1439 key = &priv->wep_keys[index].key[0];
1440 } else if ( !priv->secinfo.wep_enabled
1441 && (priv->secinfo.WPAenabled ||
1442 priv->secinfo.WPA2enabled)) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001443 /* WPA */
Dan Williams1443b652007-08-02 10:45:55 -04001444 struct enc_key * pkey = NULL;
Dan Williams90a42212007-05-25 23:01:24 -04001445
David Woodhouseaa21c002007-12-08 20:04:36 +00001446 if ( priv->wpa_mcast_key.len
1447 && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
1448 pkey = &priv->wpa_mcast_key;
1449 else if ( priv->wpa_unicast_key.len
1450 && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))
1451 pkey = &priv->wpa_unicast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001452
1453 if (pkey) {
1454 if (pkey->type == KEY_TYPE_ID_AES) {
1455 ext->alg = IW_ENCODE_ALG_CCMP;
1456 } else {
1457 ext->alg = IW_ENCODE_ALG_TKIP;
1458 }
1459 ext->key_len = pkey->len;
1460 key = &pkey->key[0];
1461 } else {
1462 ext->alg = IW_ENCODE_ALG_TKIP;
1463 ext->key_len = 0;
1464 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001465 } else {
1466 goto out;
1467 }
1468
1469 if (ext->key_len > max_key_len) {
1470 ret = -E2BIG;
1471 goto out;
1472 }
1473
1474 if (ext->key_len)
1475 memcpy(ext->key, key, ext->key_len);
1476 else
1477 dwrq->flags |= IW_ENCODE_NOKEY;
1478 dwrq->flags |= IW_ENCODE_ENABLED;
1479 }
1480 ret = 0;
1481
1482out:
Holger Schurig9012b282007-05-25 11:27:16 -04001483 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001484 return ret;
1485}
1486
1487/**
1488 * @brief Set Encryption key Extended (WPA/802.1x and WEP)
1489 *
1490 * @param dev A pointer to net_device structure
1491 * @param info A pointer to iw_request_info structure
1492 * @param vwrq A pointer to iw_param structure
1493 * @param extra A pointer to extra data buf
1494 * @return 0 --success, otherwise fail
1495 */
Holger Schurig10078322007-11-15 18:05:47 -05001496static int lbs_set_encodeext(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001497 struct iw_request_info *info,
1498 struct iw_point *dwrq,
1499 char *extra)
1500{
1501 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001502 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001503 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1504 int alg = ext->alg;
1505 struct assoc_request * assoc_req;
1506
Holger Schurig9012b282007-05-25 11:27:16 -04001507 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001508
David Woodhouseaa21c002007-12-08 20:04:36 +00001509 mutex_lock(&priv->lock);
1510 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001511 if (!assoc_req) {
1512 ret = -ENOMEM;
1513 goto out;
1514 }
1515
1516 if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
1517 disable_wep (assoc_req);
Dan Williams90a42212007-05-25 23:01:24 -04001518 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001519 } else if (alg == IW_ENCODE_ALG_WEP) {
1520 u16 is_default = 0, index, set_tx_key = 0;
1521
1522 ret = validate_key_index(assoc_req->wep_tx_keyidx,
1523 (dwrq->flags & IW_ENCODE_INDEX),
1524 &index, &is_default);
1525 if (ret)
1526 goto out;
1527
1528 /* If WEP isn't enabled, or if there is no key data but a valid
1529 * index, or if the set-TX-key flag was passed, set the TX key.
1530 */
Dan Williams889c05b2007-05-10 22:57:23 -04001531 if ( !assoc_req->secinfo.wep_enabled
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001532 || (dwrq->length == 0 && !is_default)
1533 || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
1534 set_tx_key = 1;
1535
1536 /* Copy key to driver */
Holger Schurig10078322007-11-15 18:05:47 -05001537 ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001538 set_tx_key);
1539 if (ret)
1540 goto out;
1541
1542 if (dwrq->flags & IW_ENCODE_RESTRICTED) {
Dan Williams6affe782007-05-10 22:56:42 -04001543 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001544 } else if (dwrq->flags & IW_ENCODE_OPEN) {
Dan Williams6affe782007-05-10 22:56:42 -04001545 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001546 }
1547
1548 /* Mark the various WEP bits as modified */
1549 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1550 if (dwrq->length)
1551 set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
1552 if (set_tx_key)
1553 set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001554 } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
Dan Williams1443b652007-08-02 10:45:55 -04001555 struct enc_key * pkey;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001556
1557 /* validate key length */
1558 if (((alg == IW_ENCODE_ALG_TKIP)
1559 && (ext->key_len != KEY_LEN_WPA_TKIP))
1560 || ((alg == IW_ENCODE_ALG_CCMP)
1561 && (ext->key_len != KEY_LEN_WPA_AES))) {
Joe Perches8376e7a2007-11-19 17:48:27 -08001562 lbs_deb_wext("invalid size %d for key of alg "
Holger Schurig9012b282007-05-25 11:27:16 -04001563 "type %d\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001564 ext->key_len,
1565 alg);
1566 ret = -EINVAL;
1567 goto out;
1568 }
1569
Dan Williams90a42212007-05-25 23:01:24 -04001570 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001571 pkey = &assoc_req->wpa_mcast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001572 set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
1573 } else {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001574 pkey = &assoc_req->wpa_unicast_key;
Dan Williams90a42212007-05-25 23:01:24 -04001575 set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
1576 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001577
Dan Williams1443b652007-08-02 10:45:55 -04001578 memset(pkey, 0, sizeof (struct enc_key));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001579 memcpy(pkey->key, ext->key, ext->key_len);
1580 pkey->len = ext->key_len;
Dan Williams90a42212007-05-25 23:01:24 -04001581 if (pkey->len)
1582 pkey->flags |= KEY_INFO_WPA_ENABLED;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001583
Dan Williams90a42212007-05-25 23:01:24 -04001584 /* Do this after zeroing key structure */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001585 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
1586 pkey->flags |= KEY_INFO_WPA_MCAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001587 } else {
1588 pkey->flags |= KEY_INFO_WPA_UNICAST;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001589 }
1590
Dan Williams90a42212007-05-25 23:01:24 -04001591 if (alg == IW_ENCODE_ALG_TKIP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001592 pkey->type = KEY_TYPE_ID_TKIP;
Dan Williams90a42212007-05-25 23:01:24 -04001593 } else if (alg == IW_ENCODE_ALG_CCMP) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001594 pkey->type = KEY_TYPE_ID_AES;
Dan Williams90a42212007-05-25 23:01:24 -04001595 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001596
1597 /* If WPA isn't enabled yet, do that now */
1598 if ( assoc_req->secinfo.WPAenabled == 0
1599 && assoc_req->secinfo.WPA2enabled == 0) {
1600 assoc_req->secinfo.WPAenabled = 1;
1601 assoc_req->secinfo.WPA2enabled = 1;
1602 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
1603 }
1604
1605 disable_wep (assoc_req);
1606 }
1607
1608out:
1609 if (ret == 0) {
Holger Schurig10078322007-11-15 18:05:47 -05001610 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001611 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001612 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001613 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001614 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001615
Holger Schurig9012b282007-05-25 11:27:16 -04001616 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001617 return ret;
1618}
1619
1620
Holger Schurig10078322007-11-15 18:05:47 -05001621static int lbs_set_genie(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001622 struct iw_request_info *info,
1623 struct iw_point *dwrq,
1624 char *extra)
1625{
Holger Schurig69f90322007-11-23 15:43:44 +01001626 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001627 int ret = 0;
1628 struct assoc_request * assoc_req;
1629
Holger Schurig9012b282007-05-25 11:27:16 -04001630 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001631
David Woodhouseaa21c002007-12-08 20:04:36 +00001632 mutex_lock(&priv->lock);
1633 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001634 if (!assoc_req) {
1635 ret = -ENOMEM;
1636 goto out;
1637 }
1638
1639 if (dwrq->length > MAX_WPA_IE_LEN ||
1640 (dwrq->length && extra == NULL)) {
1641 ret = -EINVAL;
1642 goto out;
1643 }
1644
1645 if (dwrq->length) {
1646 memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
1647 assoc_req->wpa_ie_len = dwrq->length;
1648 } else {
David Woodhouseaa21c002007-12-08 20:04:36 +00001649 memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001650 assoc_req->wpa_ie_len = 0;
1651 }
1652
1653out:
1654 if (ret == 0) {
1655 set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001656 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001657 } else {
Holger Schurig10078322007-11-15 18:05:47 -05001658 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001659 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001660 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001661
Holger Schurig9012b282007-05-25 11:27:16 -04001662 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001663 return ret;
1664}
1665
Holger Schurig10078322007-11-15 18:05:47 -05001666static int lbs_get_genie(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001667 struct iw_request_info *info,
1668 struct iw_point *dwrq,
1669 char *extra)
1670{
Holger Schurig9012b282007-05-25 11:27:16 -04001671 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001672 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001673
Holger Schurig9012b282007-05-25 11:27:16 -04001674 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001675
David Woodhouseaa21c002007-12-08 20:04:36 +00001676 if (priv->wpa_ie_len == 0) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001677 dwrq->length = 0;
Holger Schurig9012b282007-05-25 11:27:16 -04001678 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001679 }
1680
David Woodhouseaa21c002007-12-08 20:04:36 +00001681 if (dwrq->length < priv->wpa_ie_len) {
Holger Schurig9012b282007-05-25 11:27:16 -04001682 ret = -E2BIG;
1683 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001684 }
1685
David Woodhouseaa21c002007-12-08 20:04:36 +00001686 dwrq->length = priv->wpa_ie_len;
1687 memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001688
Holger Schurig9012b282007-05-25 11:27:16 -04001689out:
1690 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1691 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001692}
1693
1694
Holger Schurig10078322007-11-15 18:05:47 -05001695static int lbs_set_auth(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001696 struct iw_request_info *info,
1697 struct iw_param *dwrq,
1698 char *extra)
1699{
Holger Schurig69f90322007-11-23 15:43:44 +01001700 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001701 struct assoc_request * assoc_req;
1702 int ret = 0;
1703 int updated = 0;
1704
Holger Schurig9012b282007-05-25 11:27:16 -04001705 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001706
David Woodhouseaa21c002007-12-08 20:04:36 +00001707 mutex_lock(&priv->lock);
1708 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001709 if (!assoc_req) {
1710 ret = -ENOMEM;
1711 goto out;
1712 }
1713
1714 switch (dwrq->flags & IW_AUTH_INDEX) {
1715 case IW_AUTH_TKIP_COUNTERMEASURES:
1716 case IW_AUTH_CIPHER_PAIRWISE:
1717 case IW_AUTH_CIPHER_GROUP:
1718 case IW_AUTH_KEY_MGMT:
Dan Williams90a42212007-05-25 23:01:24 -04001719 case IW_AUTH_DROP_UNENCRYPTED:
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001720 /*
1721 * libertas does not use these parameters
1722 */
1723 break;
1724
1725 case IW_AUTH_WPA_VERSION:
1726 if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
1727 assoc_req->secinfo.WPAenabled = 0;
1728 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001729 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001730 }
1731 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
1732 assoc_req->secinfo.WPAenabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001733 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001734 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001735 }
1736 if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
1737 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001738 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001739 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001740 }
1741 updated = 1;
1742 break;
1743
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001744 case IW_AUTH_80211_AUTH_ALG:
1745 if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
Dan Williams6affe782007-05-10 22:56:42 -04001746 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001747 } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
Dan Williams6affe782007-05-10 22:56:42 -04001748 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001749 } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
Dan Williams6affe782007-05-10 22:56:42 -04001750 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001751 } else {
1752 ret = -EINVAL;
1753 }
1754 updated = 1;
1755 break;
1756
1757 case IW_AUTH_WPA_ENABLED:
1758 if (dwrq->value) {
1759 if (!assoc_req->secinfo.WPAenabled &&
1760 !assoc_req->secinfo.WPA2enabled) {
1761 assoc_req->secinfo.WPAenabled = 1;
1762 assoc_req->secinfo.WPA2enabled = 1;
Dan Williams889c05b2007-05-10 22:57:23 -04001763 assoc_req->secinfo.wep_enabled = 0;
Dan Williams6affe782007-05-10 22:56:42 -04001764 assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001765 }
1766 } else {
1767 assoc_req->secinfo.WPAenabled = 0;
1768 assoc_req->secinfo.WPA2enabled = 0;
Dan Williams90a42212007-05-25 23:01:24 -04001769 disable_wpa (assoc_req);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001770 }
1771 updated = 1;
1772 break;
1773
1774 default:
1775 ret = -EOPNOTSUPP;
1776 break;
1777 }
1778
1779out:
1780 if (ret == 0) {
1781 if (updated)
1782 set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001783 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001784 } else if (ret != -EOPNOTSUPP) {
Holger Schurig10078322007-11-15 18:05:47 -05001785 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001786 }
David Woodhouseaa21c002007-12-08 20:04:36 +00001787 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001788
Holger Schurig9012b282007-05-25 11:27:16 -04001789 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001790 return ret;
1791}
1792
Holger Schurig10078322007-11-15 18:05:47 -05001793static int lbs_get_auth(struct net_device *dev,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001794 struct iw_request_info *info,
1795 struct iw_param *dwrq,
1796 char *extra)
1797{
Holger Schurig9012b282007-05-25 11:27:16 -04001798 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001799 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001800
Holger Schurig9012b282007-05-25 11:27:16 -04001801 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001802
1803 switch (dwrq->flags & IW_AUTH_INDEX) {
1804 case IW_AUTH_WPA_VERSION:
1805 dwrq->value = 0;
David Woodhouseaa21c002007-12-08 20:04:36 +00001806 if (priv->secinfo.WPAenabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001807 dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
David Woodhouseaa21c002007-12-08 20:04:36 +00001808 if (priv->secinfo.WPA2enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001809 dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
1810 if (!dwrq->value)
1811 dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
1812 break;
1813
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001814 case IW_AUTH_80211_AUTH_ALG:
David Woodhouseaa21c002007-12-08 20:04:36 +00001815 dwrq->value = priv->secinfo.auth_mode;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001816 break;
1817
1818 case IW_AUTH_WPA_ENABLED:
David Woodhouseaa21c002007-12-08 20:04:36 +00001819 if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001820 dwrq->value = 1;
1821 break;
1822
1823 default:
Holger Schurig9012b282007-05-25 11:27:16 -04001824 ret = -EOPNOTSUPP;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001825 }
1826
Holger Schurig9012b282007-05-25 11:27:16 -04001827 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
1828 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001829}
1830
1831
Holger Schurig10078322007-11-15 18:05:47 -05001832static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001833 struct iw_param *vwrq, char *extra)
1834{
1835 int ret = 0;
Holger Schurig69f90322007-11-23 15:43:44 +01001836 struct lbs_private *priv = dev->priv;
Dan Williams87c8c722008-08-19 15:15:35 -04001837 s16 dbm = (s16) vwrq->value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001838
Holger Schurig9012b282007-05-25 11:27:16 -04001839 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001840
1841 if (vwrq->disabled) {
Holger Schurig10078322007-11-15 18:05:47 -05001842 lbs_radio_ioctl(priv, RADIO_OFF);
Dan Williams87c8c722008-08-19 15:15:35 -04001843 goto out;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001844 }
1845
Dan Williams87c8c722008-08-19 15:15:35 -04001846 if (vwrq->fixed == 0) {
1847 /* Auto power control */
1848 priv->preamble = CMD_TYPE_AUTO_PREAMBLE;
1849 dbm = priv->txpower_max;
1850 } else {
1851 /* Userspace check in iwrange if it should use dBm or mW,
1852 * therefore this should never happen... Jean II */
1853 if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
1854 ret = -EOPNOTSUPP;
1855 goto out;
1856 }
1857
1858 /* Validate requested power level against firmware allowed levels */
1859 if (priv->txpower_min && (dbm < priv->txpower_min)) {
1860 ret = -EINVAL;
1861 goto out;
1862 }
1863
1864 if (priv->txpower_max && (dbm > priv->txpower_max)) {
1865 ret = -EINVAL;
1866 goto out;
1867 }
1868 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001869
Holger Schurig10078322007-11-15 18:05:47 -05001870 lbs_radio_ioctl(priv, RADIO_ON);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001871
Dan Williams87c8c722008-08-19 15:15:35 -04001872 lbs_deb_wext("txpower set %d dBm\n", dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001873
Dan Williams87c8c722008-08-19 15:15:35 -04001874 ret = lbs_set_tx_power(priv, dbm);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001875
Dan Williams87c8c722008-08-19 15:15:35 -04001876out:
Holger Schurig9012b282007-05-25 11:27:16 -04001877 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001878 return ret;
1879}
1880
Holger Schurig10078322007-11-15 18:05:47 -05001881static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001882 struct iw_point *dwrq, char *extra)
1883{
Holger Schurig69f90322007-11-23 15:43:44 +01001884 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001885
Holger Schurig9012b282007-05-25 11:27:16 -04001886 lbs_deb_enter(LBS_DEB_WEXT);
1887
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001888 /*
1889 * Note : if dwrq->flags != 0, we should get the relevant SSID from
1890 * the SSID list...
1891 */
1892
1893 /*
1894 * Get the current SSID
1895 */
David Woodhouseaa21c002007-12-08 20:04:36 +00001896 if (priv->connect_status == LBS_CONNECTED) {
1897 memcpy(extra, priv->curbssparams.ssid,
1898 priv->curbssparams.ssid_len);
1899 extra[priv->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001900 } else {
1901 memset(extra, 0, 32);
David Woodhouseaa21c002007-12-08 20:04:36 +00001902 extra[priv->curbssparams.ssid_len] = '\0';
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001903 }
1904 /*
1905 * If none, we may want to get the one that was set
1906 */
1907
David Woodhouseaa21c002007-12-08 20:04:36 +00001908 dwrq->length = priv->curbssparams.ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001909
1910 dwrq->flags = 1; /* active */
1911
Holger Schurig9012b282007-05-25 11:27:16 -04001912 lbs_deb_leave(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001913 return 0;
1914}
1915
Holger Schurig10078322007-11-15 18:05:47 -05001916static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001917 struct iw_point *dwrq, char *extra)
1918{
Holger Schurig69f90322007-11-23 15:43:44 +01001919 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001920 int ret = 0;
Dan Williamsd8efea22007-05-28 23:54:55 -04001921 u8 ssid[IW_ESSID_MAX_SIZE];
1922 u8 ssid_len = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001923 struct assoc_request * assoc_req;
Dan Williamsd8efea22007-05-28 23:54:55 -04001924 int in_ssid_len = dwrq->length;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001925
Holger Schurig9012b282007-05-25 11:27:16 -04001926 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001927
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001928 /* Check the size of the string */
Dan Williamsd8efea22007-05-28 23:54:55 -04001929 if (in_ssid_len > IW_ESSID_MAX_SIZE) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001930 ret = -E2BIG;
1931 goto out;
1932 }
1933
Dan Williamsd8efea22007-05-28 23:54:55 -04001934 memset(&ssid, 0, sizeof(ssid));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001935
Dan Williamsd8efea22007-05-28 23:54:55 -04001936 if (!dwrq->flags || !in_ssid_len) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001937 /* "any" SSID requested; leave SSID blank */
1938 } else {
1939 /* Specific SSID requested */
Dan Williamsd8efea22007-05-28 23:54:55 -04001940 memcpy(&ssid, extra, in_ssid_len);
1941 ssid_len = in_ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001942 }
1943
Dan Williamsd8efea22007-05-28 23:54:55 -04001944 if (!ssid_len) {
1945 lbs_deb_wext("requested any SSID\n");
1946 } else {
1947 lbs_deb_wext("requested SSID '%s'\n",
1948 escape_essid(ssid, ssid_len));
1949 }
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001950
1951out:
David Woodhouseaa21c002007-12-08 20:04:36 +00001952 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001953 if (ret == 0) {
1954 /* Get or create the current association request */
David Woodhouseaa21c002007-12-08 20:04:36 +00001955 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001956 if (!assoc_req) {
1957 ret = -ENOMEM;
1958 } else {
1959 /* Copy the SSID to the association request */
Dan Williamsd8efea22007-05-28 23:54:55 -04001960 memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
1961 assoc_req->ssid_len = ssid_len;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001962 set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05001963 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001964 }
1965 }
1966
1967 /* Cancel the association request if there was an error */
1968 if (ret != 0) {
Holger Schurig10078322007-11-15 18:05:47 -05001969 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001970 }
1971
David Woodhouseaa21c002007-12-08 20:04:36 +00001972 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001973
Holger Schurig9012b282007-05-25 11:27:16 -04001974 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001975 return ret;
1976}
1977
David Woodhousef5956bf2007-12-11 19:30:57 -05001978static int lbs_mesh_get_essid(struct net_device *dev,
1979 struct iw_request_info *info,
1980 struct iw_point *dwrq, char *extra)
1981{
1982 struct lbs_private *priv = dev->priv;
1983
1984 lbs_deb_enter(LBS_DEB_WEXT);
1985
1986 memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);
1987
1988 dwrq->length = priv->mesh_ssid_len;
1989
1990 dwrq->flags = 1; /* active */
1991
1992 lbs_deb_leave(LBS_DEB_WEXT);
1993 return 0;
1994}
1995
1996static int lbs_mesh_set_essid(struct net_device *dev,
1997 struct iw_request_info *info,
1998 struct iw_point *dwrq, char *extra)
1999{
2000 struct lbs_private *priv = dev->priv;
2001 int ret = 0;
2002
2003 lbs_deb_enter(LBS_DEB_WEXT);
2004
2005 /* Check the size of the string */
2006 if (dwrq->length > IW_ESSID_MAX_SIZE) {
2007 ret = -E2BIG;
2008 goto out;
2009 }
2010
2011 if (!dwrq->flags || !dwrq->length) {
2012 ret = -EINVAL;
2013 goto out;
2014 } else {
2015 /* Specific SSID requested */
2016 memcpy(priv->mesh_ssid, extra, dwrq->length);
2017 priv->mesh_ssid_len = dwrq->length;
2018 }
2019
Javier Cardonaedaea5c2008-05-17 00:55:10 -07002020 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
2021 priv->curbssparams.channel);
David Woodhousef5956bf2007-12-11 19:30:57 -05002022 out:
2023 lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
2024 return ret;
2025}
2026
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002027/**
2028 * @brief Connect to the AP or Ad-hoc Network with specific bssid
2029 *
2030 * @param dev A pointer to net_device structure
2031 * @param info A pointer to iw_request_info structure
2032 * @param awrq A pointer to iw_param structure
2033 * @param extra A pointer to extra data buf
2034 * @return 0 --success, otherwise fail
2035 */
Holger Schurig10078322007-11-15 18:05:47 -05002036static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002037 struct sockaddr *awrq, char *extra)
2038{
Holger Schurig69f90322007-11-23 15:43:44 +01002039 struct lbs_private *priv = dev->priv;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002040 struct assoc_request * assoc_req;
2041 int ret = 0;
Joe Perches0795af52007-10-03 17:59:30 -07002042 DECLARE_MAC_BUF(mac);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002043
Holger Schurig9012b282007-05-25 11:27:16 -04002044 lbs_deb_enter(LBS_DEB_WEXT);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002045
2046 if (awrq->sa_family != ARPHRD_ETHER)
2047 return -EINVAL;
2048
Joe Perches0795af52007-10-03 17:59:30 -07002049 lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002050
David Woodhouseaa21c002007-12-08 20:04:36 +00002051 mutex_lock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002052
2053 /* Get or create the current association request */
David Woodhouseaa21c002007-12-08 20:04:36 +00002054 assoc_req = lbs_get_association_request(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002055 if (!assoc_req) {
Holger Schurig10078322007-11-15 18:05:47 -05002056 lbs_cancel_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002057 ret = -ENOMEM;
2058 } else {
2059 /* Copy the BSSID to the association request */
2060 memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
2061 set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
Holger Schurig10078322007-11-15 18:05:47 -05002062 lbs_postpone_association_work(priv);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002063 }
2064
David Woodhouseaa21c002007-12-08 20:04:36 +00002065 mutex_unlock(&priv->lock);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002066
2067 return ret;
2068}
2069
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002070/*
2071 * iwconfig settable callbacks
2072 */
Holger Schurig10078322007-11-15 18:05:47 -05002073static const iw_handler lbs_handler[] = {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002074 (iw_handler) NULL, /* SIOCSIWCOMMIT */
Holger Schurig10078322007-11-15 18:05:47 -05002075 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002076 (iw_handler) NULL, /* SIOCSIWNWID */
2077 (iw_handler) NULL, /* SIOCGIWNWID */
Holger Schurig10078322007-11-15 18:05:47 -05002078 (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */
2079 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
2080 (iw_handler) lbs_set_mode, /* SIOCSIWMODE */
2081 (iw_handler) lbs_get_mode, /* SIOCGIWMODE */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002082 (iw_handler) NULL, /* SIOCSIWSENS */
2083 (iw_handler) NULL, /* SIOCGIWSENS */
2084 (iw_handler) NULL, /* SIOCSIWRANGE */
Holger Schurig10078322007-11-15 18:05:47 -05002085 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002086 (iw_handler) NULL, /* SIOCSIWPRIV */
2087 (iw_handler) NULL, /* SIOCGIWPRIV */
2088 (iw_handler) NULL, /* SIOCSIWSTATS */
2089 (iw_handler) NULL, /* SIOCGIWSTATS */
2090 iw_handler_set_spy, /* SIOCSIWSPY */
2091 iw_handler_get_spy, /* SIOCGIWSPY */
2092 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2093 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
Holger Schurig10078322007-11-15 18:05:47 -05002094 (iw_handler) lbs_set_wap, /* SIOCSIWAP */
2095 (iw_handler) lbs_get_wap, /* SIOCGIWAP */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002096 (iw_handler) NULL, /* SIOCSIWMLME */
2097 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
Holger Schurig10078322007-11-15 18:05:47 -05002098 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2099 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
2100 (iw_handler) lbs_set_essid, /* SIOCSIWESSID */
2101 (iw_handler) lbs_get_essid, /* SIOCGIWESSID */
2102 (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */
2103 (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002104 (iw_handler) NULL, /* -- hole -- */
2105 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002106 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2107 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2108 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2109 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2110 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2111 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2112 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2113 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2114 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2115 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2116 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2117 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2118 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2119 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002120 (iw_handler) NULL, /* -- hole -- */
2121 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002122 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2123 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2124 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2125 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2126 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2127 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002128 (iw_handler) NULL, /* SIOCSIWPMKSA */
2129};
2130
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002131static const iw_handler mesh_wlan_handler[] = {
2132 (iw_handler) NULL, /* SIOCSIWCOMMIT */
Holger Schurig10078322007-11-15 18:05:47 -05002133 (iw_handler) lbs_get_name, /* SIOCGIWNAME */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002134 (iw_handler) NULL, /* SIOCSIWNWID */
2135 (iw_handler) NULL, /* SIOCGIWNWID */
David Woodhouse823eaa22007-12-11 19:56:28 -05002136 (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */
Holger Schurig10078322007-11-15 18:05:47 -05002137 (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002138 (iw_handler) NULL, /* SIOCSIWMODE */
2139 (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */
2140 (iw_handler) NULL, /* SIOCSIWSENS */
2141 (iw_handler) NULL, /* SIOCGIWSENS */
2142 (iw_handler) NULL, /* SIOCSIWRANGE */
Holger Schurig10078322007-11-15 18:05:47 -05002143 (iw_handler) lbs_get_range, /* SIOCGIWRANGE */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002144 (iw_handler) NULL, /* SIOCSIWPRIV */
2145 (iw_handler) NULL, /* SIOCGIWPRIV */
2146 (iw_handler) NULL, /* SIOCSIWSTATS */
2147 (iw_handler) NULL, /* SIOCGIWSTATS */
2148 iw_handler_set_spy, /* SIOCSIWSPY */
2149 iw_handler_get_spy, /* SIOCGIWSPY */
2150 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2151 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2152 (iw_handler) NULL, /* SIOCSIWAP */
2153 (iw_handler) NULL, /* SIOCGIWAP */
2154 (iw_handler) NULL, /* SIOCSIWMLME */
2155 (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
Holger Schurig10078322007-11-15 18:05:47 -05002156 (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */
2157 (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */
David Woodhousef5956bf2007-12-11 19:30:57 -05002158 (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */
2159 (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002160 (iw_handler) NULL, /* SIOCSIWNICKN */
2161 (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */
2162 (iw_handler) NULL, /* -- hole -- */
2163 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002164 (iw_handler) lbs_set_rate, /* SIOCSIWRATE */
2165 (iw_handler) lbs_get_rate, /* SIOCGIWRATE */
2166 (iw_handler) lbs_set_rts, /* SIOCSIWRTS */
2167 (iw_handler) lbs_get_rts, /* SIOCGIWRTS */
2168 (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */
2169 (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */
2170 (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */
2171 (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */
2172 (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */
2173 (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */
2174 (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */
2175 (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */
2176 (iw_handler) lbs_set_power, /* SIOCSIWPOWER */
2177 (iw_handler) lbs_get_power, /* SIOCGIWPOWER */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002178 (iw_handler) NULL, /* -- hole -- */
2179 (iw_handler) NULL, /* -- hole -- */
Holger Schurig10078322007-11-15 18:05:47 -05002180 (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */
2181 (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */
2182 (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */
2183 (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */
2184 (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */
2185 (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002186 (iw_handler) NULL, /* SIOCSIWPMKSA */
2187};
Holger Schurig10078322007-11-15 18:05:47 -05002188struct iw_handler_def lbs_handler_def = {
2189 .num_standard = ARRAY_SIZE(lbs_handler),
2190 .standard = (iw_handler *) lbs_handler,
2191 .get_wireless_stats = lbs_get_wireless_stats,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02002192};
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002193
2194struct iw_handler_def mesh_handler_def = {
Denis Chengff8ac602007-09-02 18:30:18 +08002195 .num_standard = ARRAY_SIZE(mesh_wlan_handler),
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002196 .standard = (iw_handler *) mesh_wlan_handler,
Holger Schurig10078322007-11-15 18:05:47 -05002197 .get_wireless_stats = lbs_get_wireless_stats,
Luis Carlos Cobo Rusf5e05b62007-05-25 23:08:34 -04002198};