1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2002 Intersil Americas Inc.
3*4882a593Smuzhiyun * (C) 2003,2004 Aurelien Alleaume <slts@free.fr>
4*4882a593Smuzhiyun * (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
5*4882a593Smuzhiyun * (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or modify
8*4882a593Smuzhiyun * it under the terms of the GNU General Public License as published by
9*4882a593Smuzhiyun * the Free Software Foundation; either version 2 of the License
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
12*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*4882a593Smuzhiyun * GNU General Public License for more details.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
17*4882a593Smuzhiyun * along with this program; if not, see <http://www.gnu.org/licenses/>.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/capability.h>
22*4882a593Smuzhiyun #include <linux/module.h>
23*4882a593Smuzhiyun #include <linux/kernel.h>
24*4882a593Smuzhiyun #include <linux/if_arp.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/pci.h>
27*4882a593Smuzhiyun #include <linux/etherdevice.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #include <linux/uaccess.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include "prismcompat.h"
32*4882a593Smuzhiyun #include "isl_ioctl.h"
33*4882a593Smuzhiyun #include "islpci_mgt.h"
34*4882a593Smuzhiyun #include "isl_oid.h" /* additional types and defs for isl38xx fw */
35*4882a593Smuzhiyun #include "oid_mgt.h"
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #include <net/iw_handler.h> /* New driver API */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */
40*4882a593Smuzhiyun #define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */
41*4882a593Smuzhiyun /* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
42*4882a593Smuzhiyun #define KEY_SIZE_TKIP 32 /* TKIP keys */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
45*4882a593Smuzhiyun u8 *wpa_ie, size_t wpa_ie_len);
46*4882a593Smuzhiyun static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
47*4882a593Smuzhiyun static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
48*4882a593Smuzhiyun __u32 *, char *);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* In 500 kbps */
51*4882a593Smuzhiyun static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
52*4882a593Smuzhiyun 12, 18, 24, 36,
53*4882a593Smuzhiyun 48, 72, 96, 108 };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /**
56*4882a593Smuzhiyun * prism54_mib_mode_helper - MIB change mode helper function
57*4882a593Smuzhiyun * @mib: the &struct islpci_mib object to modify
58*4882a593Smuzhiyun * @iw_mode: new mode (%IW_MODE_*)
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * This is a helper function, hence it does not lock. Make sure
61*4882a593Smuzhiyun * caller deals with locking *if* necessary. This function sets the
62*4882a593Smuzhiyun * mode-dependent mib values and does the mapping of the Linux
63*4882a593Smuzhiyun * Wireless API modes to Device firmware modes. It also checks for
64*4882a593Smuzhiyun * correct valid Linux wireless modes.
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun static int
prism54_mib_mode_helper(islpci_private * priv,u32 iw_mode)67*4882a593Smuzhiyun prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun u32 config = INL_CONFIG_MANUALRUN;
70*4882a593Smuzhiyun u32 mode, bsstype;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* For now, just catch early the Repeater and Secondary modes here */
73*4882a593Smuzhiyun if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) {
74*4882a593Smuzhiyun printk(KERN_DEBUG
75*4882a593Smuzhiyun "%s(): Sorry, Repeater mode and Secondary mode "
76*4882a593Smuzhiyun "are not yet supported by this driver.\n", __func__);
77*4882a593Smuzhiyun return -EINVAL;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun priv->iw_mode = iw_mode;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun switch (iw_mode) {
83*4882a593Smuzhiyun case IW_MODE_AUTO:
84*4882a593Smuzhiyun mode = INL_MODE_CLIENT;
85*4882a593Smuzhiyun bsstype = DOT11_BSSTYPE_ANY;
86*4882a593Smuzhiyun break;
87*4882a593Smuzhiyun case IW_MODE_ADHOC:
88*4882a593Smuzhiyun mode = INL_MODE_CLIENT;
89*4882a593Smuzhiyun bsstype = DOT11_BSSTYPE_IBSS;
90*4882a593Smuzhiyun break;
91*4882a593Smuzhiyun case IW_MODE_INFRA:
92*4882a593Smuzhiyun mode = INL_MODE_CLIENT;
93*4882a593Smuzhiyun bsstype = DOT11_BSSTYPE_INFRA;
94*4882a593Smuzhiyun break;
95*4882a593Smuzhiyun case IW_MODE_MASTER:
96*4882a593Smuzhiyun mode = INL_MODE_AP;
97*4882a593Smuzhiyun bsstype = DOT11_BSSTYPE_INFRA;
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun case IW_MODE_MONITOR:
100*4882a593Smuzhiyun mode = INL_MODE_PROMISCUOUS;
101*4882a593Smuzhiyun bsstype = DOT11_BSSTYPE_ANY;
102*4882a593Smuzhiyun config |= INL_CONFIG_RXANNEX;
103*4882a593Smuzhiyun break;
104*4882a593Smuzhiyun default:
105*4882a593Smuzhiyun return -EINVAL;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (init_wds)
109*4882a593Smuzhiyun config |= INL_CONFIG_WDS;
110*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype);
111*4882a593Smuzhiyun mgt_set(priv, OID_INL_CONFIG, &config);
112*4882a593Smuzhiyun mgt_set(priv, OID_INL_MODE, &mode);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun /**
118*4882a593Smuzhiyun * prism54_mib_init - fill MIB cache with defaults
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun * this function initializes the struct given as @mib with defaults,
121*4882a593Smuzhiyun * of which many are retrieved from the global module parameter
122*4882a593Smuzhiyun * variables.
123*4882a593Smuzhiyun */
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun void
prism54_mib_init(islpci_private * priv)126*4882a593Smuzhiyun prism54_mib_init(islpci_private *priv)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
129*4882a593Smuzhiyun struct obj_buffer psm_buffer = {
130*4882a593Smuzhiyun .size = PSM_BUFFER_SIZE,
131*4882a593Smuzhiyun .addr = priv->device_psm_buffer
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun channel = CARD_DEFAULT_CHANNEL;
135*4882a593Smuzhiyun authen = CARD_DEFAULT_AUTHEN;
136*4882a593Smuzhiyun wep = CARD_DEFAULT_WEP;
137*4882a593Smuzhiyun filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
138*4882a593Smuzhiyun dot1x = CARD_DEFAULT_DOT1X;
139*4882a593Smuzhiyun mlme = CARD_DEFAULT_MLME_MODE;
140*4882a593Smuzhiyun conformance = CARD_DEFAULT_CONFORMANCE;
141*4882a593Smuzhiyun power = 127;
142*4882a593Smuzhiyun mode = CARD_DEFAULT_IW_MODE;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_CHANNEL, &channel);
145*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
146*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
147*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
148*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
149*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
150*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
151*4882a593Smuzhiyun mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
152*4882a593Smuzhiyun mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* This sets all of the mode-dependent values */
155*4882a593Smuzhiyun prism54_mib_mode_helper(priv, mode);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* this will be executed outside of atomic context thanks to
159*4882a593Smuzhiyun * schedule_work(), thus we can as well use sleeping semaphore
160*4882a593Smuzhiyun * locking */
161*4882a593Smuzhiyun void
prism54_update_stats(struct work_struct * work)162*4882a593Smuzhiyun prism54_update_stats(struct work_struct *work)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun islpci_private *priv = container_of(work, islpci_private, stats_work);
165*4882a593Smuzhiyun char *data;
166*4882a593Smuzhiyun struct obj_bss bss, *bss2;
167*4882a593Smuzhiyun union oid_res_t r;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun mutex_lock(&priv->stats_lock);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Noise floor.
172*4882a593Smuzhiyun * I'm not sure if the unit is dBm.
173*4882a593Smuzhiyun * Note : If we are not connected, this value seems to be irrelevant. */
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
176*4882a593Smuzhiyun priv->local_iwstatistics.qual.noise = r.u;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Get the rssi of the link. To do this we need to retrieve a bss. */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* First get the MAC address of the AP we are associated with. */
181*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
182*4882a593Smuzhiyun data = r.ptr;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* copy this MAC to the bss */
185*4882a593Smuzhiyun memcpy(bss.address, data, ETH_ALEN);
186*4882a593Smuzhiyun kfree(data);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* now ask for the corresponding bss */
189*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r);
190*4882a593Smuzhiyun bss2 = r.ptr;
191*4882a593Smuzhiyun /* report the rssi and use it to calculate
192*4882a593Smuzhiyun * link quality through a signal-noise
193*4882a593Smuzhiyun * ratio */
194*4882a593Smuzhiyun priv->local_iwstatistics.qual.level = bss2->rssi;
195*4882a593Smuzhiyun priv->local_iwstatistics.qual.qual =
196*4882a593Smuzhiyun bss2->rssi - priv->iwstatistics.qual.noise;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun kfree(bss2);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /* report that the stats are new */
201*4882a593Smuzhiyun priv->local_iwstatistics.qual.updated = 0x7;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun /* Rx : unable to decrypt the MPDU */
204*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r);
205*4882a593Smuzhiyun priv->local_iwstatistics.discard.code = r.u;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* Tx : Max MAC retries num reached */
208*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r);
209*4882a593Smuzhiyun priv->local_iwstatistics.discard.retries = r.u;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun mutex_unlock(&priv->stats_lock);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun struct iw_statistics *
prism54_get_wireless_stats(struct net_device * ndev)215*4882a593Smuzhiyun prism54_get_wireless_stats(struct net_device *ndev)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* If the stats are being updated return old data */
220*4882a593Smuzhiyun if (mutex_trylock(&priv->stats_lock)) {
221*4882a593Smuzhiyun memcpy(&priv->iwstatistics, &priv->local_iwstatistics,
222*4882a593Smuzhiyun sizeof (struct iw_statistics));
223*4882a593Smuzhiyun /* They won't be marked updated for the next time */
224*4882a593Smuzhiyun priv->local_iwstatistics.qual.updated = 0;
225*4882a593Smuzhiyun mutex_unlock(&priv->stats_lock);
226*4882a593Smuzhiyun } else
227*4882a593Smuzhiyun priv->iwstatistics.qual.updated = 0;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* Update our wireless stats, but do not schedule to often
230*4882a593Smuzhiyun * (max 1 HZ) */
231*4882a593Smuzhiyun if ((priv->stats_timestamp == 0) ||
232*4882a593Smuzhiyun time_after(jiffies, priv->stats_timestamp + 1 * HZ)) {
233*4882a593Smuzhiyun schedule_work(&priv->stats_work);
234*4882a593Smuzhiyun priv->stats_timestamp = jiffies;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun return &priv->iwstatistics;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static int
prism54_commit(struct net_device * ndev,struct iw_request_info * info,char * cwrq,char * extra)241*4882a593Smuzhiyun prism54_commit(struct net_device *ndev, struct iw_request_info *info,
242*4882a593Smuzhiyun char *cwrq, char *extra)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* simply re-set the last set SSID, this should commit most stuff */
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* Commit in Monitor mode is not necessary, also setting essid
249*4882a593Smuzhiyun * in Monitor mode does not make sense and isn't allowed for this
250*4882a593Smuzhiyun * device's firmware */
251*4882a593Smuzhiyun if (priv->iw_mode != IW_MODE_MONITOR)
252*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL);
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun static int
prism54_get_name(struct net_device * ndev,struct iw_request_info * info,char * cwrq,char * extra)257*4882a593Smuzhiyun prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
258*4882a593Smuzhiyun char *cwrq, char *extra)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
261*4882a593Smuzhiyun char *capabilities;
262*4882a593Smuzhiyun union oid_res_t r;
263*4882a593Smuzhiyun int rvalue;
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT) {
266*4882a593Smuzhiyun strncpy(cwrq, "NOT READY!", IFNAMSIZ);
267*4882a593Smuzhiyun return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun switch (r.u) {
272*4882a593Smuzhiyun case INL_PHYCAP_5000MHZ:
273*4882a593Smuzhiyun capabilities = "IEEE 802.11a/b/g";
274*4882a593Smuzhiyun break;
275*4882a593Smuzhiyun case INL_PHYCAP_FAA:
276*4882a593Smuzhiyun capabilities = "IEEE 802.11b/g - FAA Support";
277*4882a593Smuzhiyun break;
278*4882a593Smuzhiyun case INL_PHYCAP_2400MHZ:
279*4882a593Smuzhiyun default:
280*4882a593Smuzhiyun capabilities = "IEEE 802.11b/g"; /* Default */
281*4882a593Smuzhiyun break;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun strncpy(cwrq, capabilities, IFNAMSIZ);
284*4882a593Smuzhiyun return rvalue;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun static int
prism54_set_freq(struct net_device * ndev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)288*4882a593Smuzhiyun prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
289*4882a593Smuzhiyun struct iw_freq *fwrq, char *extra)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
292*4882a593Smuzhiyun int rvalue;
293*4882a593Smuzhiyun u32 c;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (fwrq->m < 1000)
296*4882a593Smuzhiyun /* we have a channel number */
297*4882a593Smuzhiyun c = fwrq->m;
298*4882a593Smuzhiyun else
299*4882a593Smuzhiyun c = (fwrq->e == 1) ? channel_of_freq(fwrq->m / 100000) : 0;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun rvalue = c ? mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c) : -EINVAL;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* Call commit handler */
304*4882a593Smuzhiyun return (rvalue ? rvalue : -EINPROGRESS);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun static int
prism54_get_freq(struct net_device * ndev,struct iw_request_info * info,struct iw_freq * fwrq,char * extra)308*4882a593Smuzhiyun prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
309*4882a593Smuzhiyun struct iw_freq *fwrq, char *extra)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
312*4882a593Smuzhiyun union oid_res_t r;
313*4882a593Smuzhiyun int rvalue;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r);
316*4882a593Smuzhiyun fwrq->i = r.u;
317*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_FREQUENCY, 0, NULL, &r);
318*4882a593Smuzhiyun fwrq->m = r.u;
319*4882a593Smuzhiyun fwrq->e = 3;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return rvalue;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun static int
prism54_set_mode(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)325*4882a593Smuzhiyun prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
326*4882a593Smuzhiyun __u32 * uwrq, char *extra)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
329*4882a593Smuzhiyun u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun /* Let's see if the user passed a valid Linux Wireless mode */
332*4882a593Smuzhiyun if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) {
333*4882a593Smuzhiyun printk(KERN_DEBUG
334*4882a593Smuzhiyun "%s: %s() You passed a non-valid init_mode.\n",
335*4882a593Smuzhiyun priv->ndev->name, __func__);
336*4882a593Smuzhiyun return -EINVAL;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun down_write(&priv->mib_sem);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (prism54_mib_mode_helper(priv, *uwrq)) {
342*4882a593Smuzhiyun up_write(&priv->mib_sem);
343*4882a593Smuzhiyun return -EOPNOTSUPP;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an
347*4882a593Smuzhiyun * extended one.
348*4882a593Smuzhiyun */
349*4882a593Smuzhiyun if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN))
350*4882a593Smuzhiyun mlmeautolevel = DOT11_MLME_INTERMEDIATE;
351*4882a593Smuzhiyun if (priv->wpa)
352*4882a593Smuzhiyun mlmeautolevel = DOT11_MLME_EXTENDED;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (mgt_commit(priv)) {
357*4882a593Smuzhiyun up_write(&priv->mib_sem);
358*4882a593Smuzhiyun return -EIO;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR)
361*4882a593Smuzhiyun ? priv->monitor_type : ARPHRD_ETHER;
362*4882a593Smuzhiyun up_write(&priv->mib_sem);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /* Use mib cache */
368*4882a593Smuzhiyun static int
prism54_get_mode(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)369*4882a593Smuzhiyun prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
370*4882a593Smuzhiyun __u32 * uwrq, char *extra)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
375*4882a593Smuzhiyun IW_MODE_MONITOR));
376*4882a593Smuzhiyun *uwrq = priv->iw_mode;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun return 0;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to
382*4882a593Smuzhiyun * emit data if (sensitivity > rssi - noise) (in dBm).
383*4882a593Smuzhiyun * prism54_set_sens does not seem to work.
384*4882a593Smuzhiyun */
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun static int
prism54_set_sens(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)387*4882a593Smuzhiyun prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
388*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
391*4882a593Smuzhiyun u32 sens;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /* by default the card sets this to 20. */
394*4882a593Smuzhiyun sens = vwrq->disabled ? 20 : vwrq->value;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun static int
prism54_get_sens(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)400*4882a593Smuzhiyun prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
401*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
404*4882a593Smuzhiyun union oid_res_t r;
405*4882a593Smuzhiyun int rvalue;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun vwrq->value = r.u;
410*4882a593Smuzhiyun vwrq->disabled = (vwrq->value == 0);
411*4882a593Smuzhiyun vwrq->fixed = 1;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return rvalue;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun static int
prism54_get_range(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)417*4882a593Smuzhiyun prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
418*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun struct iw_range *range = (struct iw_range *) extra;
421*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
422*4882a593Smuzhiyun u8 *data;
423*4882a593Smuzhiyun int i, m, rvalue;
424*4882a593Smuzhiyun struct obj_frequencies *freq;
425*4882a593Smuzhiyun union oid_res_t r;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun memset(range, 0, sizeof (struct iw_range));
428*4882a593Smuzhiyun dwrq->length = sizeof (struct iw_range);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /* set the wireless extension version number */
431*4882a593Smuzhiyun range->we_version_source = SUPPORTED_WIRELESS_EXT;
432*4882a593Smuzhiyun range->we_version_compiled = WIRELESS_EXT;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun /* Now the encoding capabilities */
435*4882a593Smuzhiyun range->num_encoding_sizes = 3;
436*4882a593Smuzhiyun /* 64(40) bits WEP */
437*4882a593Smuzhiyun range->encoding_size[0] = 5;
438*4882a593Smuzhiyun /* 128(104) bits WEP */
439*4882a593Smuzhiyun range->encoding_size[1] = 13;
440*4882a593Smuzhiyun /* 256 bits for WPA-PSK */
441*4882a593Smuzhiyun range->encoding_size[2] = 32;
442*4882a593Smuzhiyun /* 4 keys are allowed */
443*4882a593Smuzhiyun range->max_encoding_tokens = 4;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /* we don't know the quality range... */
446*4882a593Smuzhiyun range->max_qual.level = 0;
447*4882a593Smuzhiyun range->max_qual.noise = 0;
448*4882a593Smuzhiyun range->max_qual.qual = 0;
449*4882a593Smuzhiyun /* these value describe an average quality. Needs more tweaking... */
450*4882a593Smuzhiyun range->avg_qual.level = -80; /* -80 dBm */
451*4882a593Smuzhiyun range->avg_qual.noise = 0; /* don't know what to put here */
452*4882a593Smuzhiyun range->avg_qual.qual = 0;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun range->sensitivity = 200;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* retry limit capabilities */
457*4882a593Smuzhiyun range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
458*4882a593Smuzhiyun range->retry_flags = IW_RETRY_LIMIT;
459*4882a593Smuzhiyun range->r_time_flags = IW_RETRY_LIFETIME;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* I don't know the range. Put stupid things here */
462*4882a593Smuzhiyun range->min_retry = 1;
463*4882a593Smuzhiyun range->max_retry = 65535;
464*4882a593Smuzhiyun range->min_r_time = 1024;
465*4882a593Smuzhiyun range->max_r_time = 65535 * 1024;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* txpower is supported in dBm's */
468*4882a593Smuzhiyun range->txpower_capa = IW_TXPOW_DBM;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun /* Event capability (kernel + driver) */
471*4882a593Smuzhiyun range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
472*4882a593Smuzhiyun IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
473*4882a593Smuzhiyun IW_EVENT_CAPA_MASK(SIOCGIWAP));
474*4882a593Smuzhiyun range->event_capa[1] = IW_EVENT_CAPA_K_1;
475*4882a593Smuzhiyun range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
478*4882a593Smuzhiyun IW_ENC_CAPA_CIPHER_TKIP;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
481*4882a593Smuzhiyun return 0;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun /* Request the device for the supported frequencies
484*4882a593Smuzhiyun * not really relevant since some devices will report the 5 GHz band
485*4882a593Smuzhiyun * frequencies even if they don't support them.
486*4882a593Smuzhiyun */
487*4882a593Smuzhiyun rvalue =
488*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r);
489*4882a593Smuzhiyun freq = r.ptr;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun range->num_channels = freq->nr;
492*4882a593Smuzhiyun range->num_frequency = freq->nr;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun m = min(IW_MAX_FREQUENCIES, (int) freq->nr);
495*4882a593Smuzhiyun for (i = 0; i < m; i++) {
496*4882a593Smuzhiyun range->freq[i].m = freq->mhz[i];
497*4882a593Smuzhiyun range->freq[i].e = 6;
498*4882a593Smuzhiyun range->freq[i].i = channel_of_freq(freq->mhz[i]);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun kfree(freq);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
503*4882a593Smuzhiyun data = r.ptr;
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun /* We got an array of char. It is NULL terminated. */
506*4882a593Smuzhiyun i = 0;
507*4882a593Smuzhiyun while ((i < IW_MAX_BITRATES) && (*data != 0)) {
508*4882a593Smuzhiyun /* the result must be in bps. The card gives us 500Kbps */
509*4882a593Smuzhiyun range->bitrate[i] = *data * 500000;
510*4882a593Smuzhiyun i++;
511*4882a593Smuzhiyun data++;
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun range->num_bitrates = i;
514*4882a593Smuzhiyun kfree(r.ptr);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun return rvalue;
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /* Set AP address*/
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun static int
prism54_set_wap(struct net_device * ndev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)522*4882a593Smuzhiyun prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
523*4882a593Smuzhiyun struct sockaddr *awrq, char *extra)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
526*4882a593Smuzhiyun char bssid[6];
527*4882a593Smuzhiyun int rvalue;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun if (awrq->sa_family != ARPHRD_ETHER)
530*4882a593Smuzhiyun return -EINVAL;
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun /* prepare the structure for the set object */
533*4882a593Smuzhiyun memcpy(&bssid[0], awrq->sa_data, ETH_ALEN);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun /* set the bssid -- does this make sense when in AP mode? */
536*4882a593Smuzhiyun rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* get AP address*/
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun static int
prism54_get_wap(struct net_device * ndev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)544*4882a593Smuzhiyun prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
545*4882a593Smuzhiyun struct sockaddr *awrq, char *extra)
546*4882a593Smuzhiyun {
547*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
548*4882a593Smuzhiyun union oid_res_t r;
549*4882a593Smuzhiyun int rvalue;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r);
552*4882a593Smuzhiyun memcpy(awrq->sa_data, r.ptr, ETH_ALEN);
553*4882a593Smuzhiyun awrq->sa_family = ARPHRD_ETHER;
554*4882a593Smuzhiyun kfree(r.ptr);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun return rvalue;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun static int
prism54_set_scan(struct net_device * dev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)560*4882a593Smuzhiyun prism54_set_scan(struct net_device *dev, struct iw_request_info *info,
561*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun /* hehe the device does this automagicaly */
564*4882a593Smuzhiyun return 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* a little helper that will translate our data into a card independent
568*4882a593Smuzhiyun * format that the Wireless Tools will understand. This was inspired by
569*4882a593Smuzhiyun * the "Aironet driver for 4500 and 4800 series cards" (GPL)
570*4882a593Smuzhiyun */
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun static char *
prism54_translate_bss(struct net_device * ndev,struct iw_request_info * info,char * current_ev,char * end_buf,struct obj_bss * bss,char noise)573*4882a593Smuzhiyun prism54_translate_bss(struct net_device *ndev, struct iw_request_info *info,
574*4882a593Smuzhiyun char *current_ev, char *end_buf, struct obj_bss *bss,
575*4882a593Smuzhiyun char noise)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun struct iw_event iwe; /* Temporary buffer */
578*4882a593Smuzhiyun short cap;
579*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
580*4882a593Smuzhiyun u8 wpa_ie[MAX_WPA_IE_LEN];
581*4882a593Smuzhiyun size_t wpa_ie_len;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun /* The first entry must be the MAC address */
584*4882a593Smuzhiyun memcpy(iwe.u.ap_addr.sa_data, bss->address, ETH_ALEN);
585*4882a593Smuzhiyun iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
586*4882a593Smuzhiyun iwe.cmd = SIOCGIWAP;
587*4882a593Smuzhiyun current_ev = iwe_stream_add_event(info, current_ev, end_buf,
588*4882a593Smuzhiyun &iwe, IW_EV_ADDR_LEN);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* The following entries will be displayed in the same order we give them */
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun /* The ESSID. */
593*4882a593Smuzhiyun iwe.u.data.length = bss->ssid.length;
594*4882a593Smuzhiyun iwe.u.data.flags = 1;
595*4882a593Smuzhiyun iwe.cmd = SIOCGIWESSID;
596*4882a593Smuzhiyun current_ev = iwe_stream_add_point(info, current_ev, end_buf,
597*4882a593Smuzhiyun &iwe, bss->ssid.octets);
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun /* Capabilities */
600*4882a593Smuzhiyun #define CAP_ESS 0x01
601*4882a593Smuzhiyun #define CAP_IBSS 0x02
602*4882a593Smuzhiyun #define CAP_CRYPT 0x10
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* Mode */
605*4882a593Smuzhiyun cap = bss->capinfo;
606*4882a593Smuzhiyun iwe.u.mode = 0;
607*4882a593Smuzhiyun if (cap & CAP_ESS)
608*4882a593Smuzhiyun iwe.u.mode = IW_MODE_MASTER;
609*4882a593Smuzhiyun else if (cap & CAP_IBSS)
610*4882a593Smuzhiyun iwe.u.mode = IW_MODE_ADHOC;
611*4882a593Smuzhiyun iwe.cmd = SIOCGIWMODE;
612*4882a593Smuzhiyun if (iwe.u.mode)
613*4882a593Smuzhiyun current_ev = iwe_stream_add_event(info, current_ev, end_buf,
614*4882a593Smuzhiyun &iwe, IW_EV_UINT_LEN);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /* Encryption capability */
617*4882a593Smuzhiyun if (cap & CAP_CRYPT)
618*4882a593Smuzhiyun iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
619*4882a593Smuzhiyun else
620*4882a593Smuzhiyun iwe.u.data.flags = IW_ENCODE_DISABLED;
621*4882a593Smuzhiyun iwe.u.data.length = 0;
622*4882a593Smuzhiyun iwe.cmd = SIOCGIWENCODE;
623*4882a593Smuzhiyun current_ev = iwe_stream_add_point(info, current_ev, end_buf,
624*4882a593Smuzhiyun &iwe, NULL);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /* Add frequency. (short) bss->channel is the frequency in MHz */
627*4882a593Smuzhiyun iwe.u.freq.m = bss->channel;
628*4882a593Smuzhiyun iwe.u.freq.e = 6;
629*4882a593Smuzhiyun iwe.cmd = SIOCGIWFREQ;
630*4882a593Smuzhiyun current_ev = iwe_stream_add_event(info, current_ev, end_buf,
631*4882a593Smuzhiyun &iwe, IW_EV_FREQ_LEN);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun /* Add quality statistics */
634*4882a593Smuzhiyun iwe.u.qual.level = bss->rssi;
635*4882a593Smuzhiyun iwe.u.qual.noise = noise;
636*4882a593Smuzhiyun /* do a simple SNR for quality */
637*4882a593Smuzhiyun iwe.u.qual.qual = bss->rssi - noise;
638*4882a593Smuzhiyun iwe.cmd = IWEVQUAL;
639*4882a593Smuzhiyun current_ev = iwe_stream_add_event(info, current_ev, end_buf,
640*4882a593Smuzhiyun &iwe, IW_EV_QUAL_LEN);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun /* Add WPA/RSN Information Element, if any */
643*4882a593Smuzhiyun wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
644*4882a593Smuzhiyun if (wpa_ie_len > 0) {
645*4882a593Smuzhiyun iwe.cmd = IWEVGENIE;
646*4882a593Smuzhiyun iwe.u.data.length = min_t(size_t, wpa_ie_len, MAX_WPA_IE_LEN);
647*4882a593Smuzhiyun current_ev = iwe_stream_add_point(info, current_ev, end_buf,
648*4882a593Smuzhiyun &iwe, wpa_ie);
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun /* Do the bitrates */
651*4882a593Smuzhiyun {
652*4882a593Smuzhiyun char *current_val = current_ev + iwe_stream_lcp_len(info);
653*4882a593Smuzhiyun int i;
654*4882a593Smuzhiyun int mask;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun iwe.cmd = SIOCGIWRATE;
657*4882a593Smuzhiyun /* Those two flags are ignored... */
658*4882a593Smuzhiyun iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun /* Parse the bitmask */
661*4882a593Smuzhiyun mask = 0x1;
662*4882a593Smuzhiyun for(i = 0; i < sizeof(scan_rate_list); i++) {
663*4882a593Smuzhiyun if(bss->rates & mask) {
664*4882a593Smuzhiyun iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
665*4882a593Smuzhiyun current_val = iwe_stream_add_value(
666*4882a593Smuzhiyun info, current_ev, current_val,
667*4882a593Smuzhiyun end_buf, &iwe, IW_EV_PARAM_LEN);
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun mask <<= 1;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun /* Check if we added any event */
672*4882a593Smuzhiyun if ((current_val - current_ev) > iwe_stream_lcp_len(info))
673*4882a593Smuzhiyun current_ev = current_val;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun return current_ev;
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun static int
prism54_get_scan(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)680*4882a593Smuzhiyun prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
681*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
684*4882a593Smuzhiyun int i, rvalue;
685*4882a593Smuzhiyun struct obj_bsslist *bsslist;
686*4882a593Smuzhiyun u32 noise = 0;
687*4882a593Smuzhiyun char *current_ev = extra;
688*4882a593Smuzhiyun union oid_res_t r;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT) {
691*4882a593Smuzhiyun /* device is not ready, fail gently */
692*4882a593Smuzhiyun dwrq->length = 0;
693*4882a593Smuzhiyun return 0;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun /* first get the noise value. We will use it to report the link quality */
697*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
698*4882a593Smuzhiyun noise = r.u;
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun /* Ask the device for a list of known bss.
701*4882a593Smuzhiyun * The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
702*4882a593Smuzhiyun * The new API, using SIOCGIWSCAN, is only limited by the buffer size.
703*4882a593Smuzhiyun * WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
704*4882a593Smuzhiyun * Starting with WE-17, the buffer can be as big as needed.
705*4882a593Smuzhiyun * But the device won't repport anything if you change the value
706*4882a593Smuzhiyun * of IWMAX_BSS=24. */
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
709*4882a593Smuzhiyun bsslist = r.ptr;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun /* ok now, scan the list and translate its info */
712*4882a593Smuzhiyun for (i = 0; i < (int) bsslist->nr; i++) {
713*4882a593Smuzhiyun current_ev = prism54_translate_bss(ndev, info, current_ev,
714*4882a593Smuzhiyun extra + dwrq->length,
715*4882a593Smuzhiyun &(bsslist->bsslist[i]),
716*4882a593Smuzhiyun noise);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun /* Check if there is space for one more entry */
719*4882a593Smuzhiyun if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
720*4882a593Smuzhiyun /* Ask user space to try again with a bigger buffer */
721*4882a593Smuzhiyun rvalue = -E2BIG;
722*4882a593Smuzhiyun break;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun }
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun kfree(bsslist);
727*4882a593Smuzhiyun dwrq->length = (current_ev - extra);
728*4882a593Smuzhiyun dwrq->flags = 0; /* todo */
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun return rvalue;
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun static int
prism54_set_essid(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)734*4882a593Smuzhiyun prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
735*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
736*4882a593Smuzhiyun {
737*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
738*4882a593Smuzhiyun struct obj_ssid essid;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun memset(essid.octets, 0, 33);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun /* Check if we were asked for `any' */
743*4882a593Smuzhiyun if (dwrq->flags && dwrq->length) {
744*4882a593Smuzhiyun if (dwrq->length > 32)
745*4882a593Smuzhiyun return -E2BIG;
746*4882a593Smuzhiyun essid.length = dwrq->length;
747*4882a593Smuzhiyun memcpy(essid.octets, extra, dwrq->length);
748*4882a593Smuzhiyun } else
749*4882a593Smuzhiyun essid.length = 0;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun if (priv->iw_mode != IW_MODE_MONITOR)
752*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun /* If in monitor mode, just save to mib */
755*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_SSID, &essid);
756*4882a593Smuzhiyun return 0;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun static int
prism54_get_essid(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)761*4882a593Smuzhiyun prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
762*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
765*4882a593Smuzhiyun struct obj_ssid *essid;
766*4882a593Smuzhiyun union oid_res_t r;
767*4882a593Smuzhiyun int rvalue;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r);
770*4882a593Smuzhiyun essid = r.ptr;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (essid->length) {
773*4882a593Smuzhiyun dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */
774*4882a593Smuzhiyun /* if it is too big, trunk it */
775*4882a593Smuzhiyun dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length);
776*4882a593Smuzhiyun } else {
777*4882a593Smuzhiyun dwrq->flags = 0;
778*4882a593Smuzhiyun dwrq->length = 0;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun essid->octets[dwrq->length] = '\0';
781*4882a593Smuzhiyun memcpy(extra, essid->octets, dwrq->length);
782*4882a593Smuzhiyun kfree(essid);
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun return rvalue;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun /* Provides no functionality, just completes the ioctl. In essence this is a
788*4882a593Smuzhiyun * just a cosmetic ioctl.
789*4882a593Smuzhiyun */
790*4882a593Smuzhiyun static int
prism54_set_nick(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)791*4882a593Smuzhiyun prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
792*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun if (dwrq->length > IW_ESSID_MAX_SIZE)
797*4882a593Smuzhiyun return -E2BIG;
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun down_write(&priv->mib_sem);
800*4882a593Smuzhiyun memset(priv->nickname, 0, sizeof (priv->nickname));
801*4882a593Smuzhiyun memcpy(priv->nickname, extra, dwrq->length);
802*4882a593Smuzhiyun up_write(&priv->mib_sem);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun return 0;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun static int
prism54_get_nick(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)808*4882a593Smuzhiyun prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
809*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun dwrq->length = 0;
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun down_read(&priv->mib_sem);
816*4882a593Smuzhiyun dwrq->length = strlen(priv->nickname);
817*4882a593Smuzhiyun memcpy(extra, priv->nickname, dwrq->length);
818*4882a593Smuzhiyun up_read(&priv->mib_sem);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun return 0;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun /* Set the allowed Bitrates */
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun static int
prism54_set_rate(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)826*4882a593Smuzhiyun prism54_set_rate(struct net_device *ndev,
827*4882a593Smuzhiyun struct iw_request_info *info,
828*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
829*4882a593Smuzhiyun {
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
832*4882a593Smuzhiyun u32 rate, profile;
833*4882a593Smuzhiyun char *data;
834*4882a593Smuzhiyun int ret, i;
835*4882a593Smuzhiyun union oid_res_t r;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun if (vwrq->value == -1) {
838*4882a593Smuzhiyun /* auto mode. No limit. */
839*4882a593Smuzhiyun profile = 1;
840*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r);
844*4882a593Smuzhiyun if (ret) {
845*4882a593Smuzhiyun kfree(r.ptr);
846*4882a593Smuzhiyun return ret;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun rate = (u32) (vwrq->value / 500000);
850*4882a593Smuzhiyun data = r.ptr;
851*4882a593Smuzhiyun i = 0;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun while (data[i]) {
854*4882a593Smuzhiyun if (rate && (data[i] == rate)) {
855*4882a593Smuzhiyun break;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun if (vwrq->value == i) {
858*4882a593Smuzhiyun break;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun data[i] |= 0x80;
861*4882a593Smuzhiyun i++;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun if (!data[i]) {
865*4882a593Smuzhiyun kfree(r.ptr);
866*4882a593Smuzhiyun return -EINVAL;
867*4882a593Smuzhiyun }
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun data[i] |= 0x80;
870*4882a593Smuzhiyun data[i + 1] = 0;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun /* Now, check if we want a fixed or auto value */
873*4882a593Smuzhiyun if (vwrq->fixed) {
874*4882a593Smuzhiyun data[0] = data[i];
875*4882a593Smuzhiyun data[1] = 0;
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /*
879*4882a593Smuzhiyun i = 0;
880*4882a593Smuzhiyun printk("prism54 rate: ");
881*4882a593Smuzhiyun while(data[i]) {
882*4882a593Smuzhiyun printk("%u ", data[i]);
883*4882a593Smuzhiyun i++;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun printk("0\n");
886*4882a593Smuzhiyun */
887*4882a593Smuzhiyun profile = -1;
888*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
889*4882a593Smuzhiyun ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data);
890*4882a593Smuzhiyun ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data);
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun kfree(r.ptr);
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun return ret;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun /* Get the current bit rate */
898*4882a593Smuzhiyun static int
prism54_get_rate(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)899*4882a593Smuzhiyun prism54_get_rate(struct net_device *ndev,
900*4882a593Smuzhiyun struct iw_request_info *info,
901*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
902*4882a593Smuzhiyun {
903*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
904*4882a593Smuzhiyun int rvalue;
905*4882a593Smuzhiyun char *data;
906*4882a593Smuzhiyun union oid_res_t r;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun /* Get the current bit rate */
909*4882a593Smuzhiyun if ((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r)))
910*4882a593Smuzhiyun return rvalue;
911*4882a593Smuzhiyun vwrq->value = r.u * 500000;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun /* request the device for the enabled rates */
914*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r);
915*4882a593Smuzhiyun if (rvalue) {
916*4882a593Smuzhiyun kfree(r.ptr);
917*4882a593Smuzhiyun return rvalue;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun data = r.ptr;
920*4882a593Smuzhiyun vwrq->fixed = (data[0] != 0) && (data[1] == 0);
921*4882a593Smuzhiyun kfree(r.ptr);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun return 0;
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun static int
prism54_set_rts(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)927*4882a593Smuzhiyun prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
928*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
929*4882a593Smuzhiyun {
930*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun static int
prism54_get_rts(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)936*4882a593Smuzhiyun prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
937*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
938*4882a593Smuzhiyun {
939*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
940*4882a593Smuzhiyun union oid_res_t r;
941*4882a593Smuzhiyun int rvalue;
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun /* get the rts threshold */
944*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r);
945*4882a593Smuzhiyun vwrq->value = r.u;
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun return rvalue;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun static int
prism54_set_frag(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)951*4882a593Smuzhiyun prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
952*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
953*4882a593Smuzhiyun {
954*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun static int
prism54_get_frag(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)960*4882a593Smuzhiyun prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
961*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
964*4882a593Smuzhiyun union oid_res_t r;
965*4882a593Smuzhiyun int rvalue;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r);
968*4882a593Smuzhiyun vwrq->value = r.u;
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun return rvalue;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun /* Here we have (min,max) = max retries for (small frames, big frames). Where
974*4882a593Smuzhiyun * big frame <=> bigger than the rts threshold
975*4882a593Smuzhiyun * small frame <=> smaller than the rts threshold
976*4882a593Smuzhiyun * This is not really the behavior expected by the wireless tool but it seems
977*4882a593Smuzhiyun * to be a common behavior in other drivers.
978*4882a593Smuzhiyun */
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun static int
prism54_set_retry(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)981*4882a593Smuzhiyun prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
982*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
983*4882a593Smuzhiyun {
984*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
985*4882a593Smuzhiyun u32 slimit = 0, llimit = 0; /* short and long limit */
986*4882a593Smuzhiyun u32 lifetime = 0;
987*4882a593Smuzhiyun int rvalue = 0;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun if (vwrq->disabled)
990*4882a593Smuzhiyun /* we cannot disable this feature */
991*4882a593Smuzhiyun return -EINVAL;
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun if (vwrq->flags & IW_RETRY_LIMIT) {
994*4882a593Smuzhiyun if (vwrq->flags & IW_RETRY_SHORT)
995*4882a593Smuzhiyun slimit = vwrq->value;
996*4882a593Smuzhiyun else if (vwrq->flags & IW_RETRY_LONG)
997*4882a593Smuzhiyun llimit = vwrq->value;
998*4882a593Smuzhiyun else {
999*4882a593Smuzhiyun /* we are asked to set both */
1000*4882a593Smuzhiyun slimit = vwrq->value;
1001*4882a593Smuzhiyun llimit = vwrq->value;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun }
1004*4882a593Smuzhiyun if (vwrq->flags & IW_RETRY_LIFETIME)
1005*4882a593Smuzhiyun /* Wireless tools use us unit while the device uses 1024 us unit */
1006*4882a593Smuzhiyun lifetime = vwrq->value / 1024;
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun /* now set what is requested */
1009*4882a593Smuzhiyun if (slimit)
1010*4882a593Smuzhiyun rvalue =
1011*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit);
1012*4882a593Smuzhiyun if (llimit)
1013*4882a593Smuzhiyun rvalue |=
1014*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit);
1015*4882a593Smuzhiyun if (lifetime)
1016*4882a593Smuzhiyun rvalue |=
1017*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0,
1018*4882a593Smuzhiyun &lifetime);
1019*4882a593Smuzhiyun return rvalue;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun static int
prism54_get_retry(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1023*4882a593Smuzhiyun prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
1024*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1027*4882a593Smuzhiyun union oid_res_t r;
1028*4882a593Smuzhiyun int rvalue = 0;
1029*4882a593Smuzhiyun vwrq->disabled = 0; /* It cannot be disabled */
1030*4882a593Smuzhiyun
1031*4882a593Smuzhiyun if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
1032*4882a593Smuzhiyun /* we are asked for the life time */
1033*4882a593Smuzhiyun rvalue =
1034*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
1035*4882a593Smuzhiyun vwrq->value = r.u * 1024;
1036*4882a593Smuzhiyun vwrq->flags = IW_RETRY_LIFETIME;
1037*4882a593Smuzhiyun } else if ((vwrq->flags & IW_RETRY_LONG)) {
1038*4882a593Smuzhiyun /* we are asked for the long retry limit */
1039*4882a593Smuzhiyun rvalue |=
1040*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
1041*4882a593Smuzhiyun vwrq->value = r.u;
1042*4882a593Smuzhiyun vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
1043*4882a593Smuzhiyun } else {
1044*4882a593Smuzhiyun /* default. get the short retry limit */
1045*4882a593Smuzhiyun rvalue |=
1046*4882a593Smuzhiyun mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
1047*4882a593Smuzhiyun vwrq->value = r.u;
1048*4882a593Smuzhiyun vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun
1051*4882a593Smuzhiyun return rvalue;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun static int
prism54_set_encode(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1055*4882a593Smuzhiyun prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
1056*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1057*4882a593Smuzhiyun {
1058*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1059*4882a593Smuzhiyun int rvalue = 0, force = 0;
1060*4882a593Smuzhiyun int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
1061*4882a593Smuzhiyun union oid_res_t r;
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun /* with the new API, it's impossible to get a NULL pointer.
1064*4882a593Smuzhiyun * New version of iwconfig set the IW_ENCODE_NOKEY flag
1065*4882a593Smuzhiyun * when no key is given, but older versions don't. */
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun if (dwrq->length > 0) {
1068*4882a593Smuzhiyun /* we have a key to set */
1069*4882a593Smuzhiyun int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1070*4882a593Smuzhiyun int current_index;
1071*4882a593Smuzhiyun struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun /* get the current key index */
1074*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1075*4882a593Smuzhiyun current_index = r.u;
1076*4882a593Smuzhiyun /* Verify that the key is not marked as invalid */
1077*4882a593Smuzhiyun if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
1078*4882a593Smuzhiyun if (dwrq->length > KEY_SIZE_TKIP) {
1079*4882a593Smuzhiyun /* User-provided key data too big */
1080*4882a593Smuzhiyun return -EINVAL;
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun if (dwrq->length > KEY_SIZE_WEP104) {
1083*4882a593Smuzhiyun /* WPA-PSK TKIP */
1084*4882a593Smuzhiyun key.type = DOT11_PRIV_TKIP;
1085*4882a593Smuzhiyun key.length = KEY_SIZE_TKIP;
1086*4882a593Smuzhiyun } else if (dwrq->length > KEY_SIZE_WEP40) {
1087*4882a593Smuzhiyun /* WEP 104/128 */
1088*4882a593Smuzhiyun key.length = KEY_SIZE_WEP104;
1089*4882a593Smuzhiyun } else {
1090*4882a593Smuzhiyun /* WEP 40/64 */
1091*4882a593Smuzhiyun key.length = KEY_SIZE_WEP40;
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun memset(key.key, 0, sizeof (key.key));
1094*4882a593Smuzhiyun memcpy(key.key, extra, dwrq->length);
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun if ((index < 0) || (index > 3))
1097*4882a593Smuzhiyun /* no index provided use the current one */
1098*4882a593Smuzhiyun index = current_index;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun /* now send the key to the card */
1101*4882a593Smuzhiyun rvalue |=
1102*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
1103*4882a593Smuzhiyun &key);
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun /*
1106*4882a593Smuzhiyun * If a valid key is set, encryption should be enabled
1107*4882a593Smuzhiyun * (user may turn it off later).
1108*4882a593Smuzhiyun * This is also how "iwconfig ethX key on" works
1109*4882a593Smuzhiyun */
1110*4882a593Smuzhiyun if ((index == current_index) && (key.length > 0))
1111*4882a593Smuzhiyun force = 1;
1112*4882a593Smuzhiyun } else {
1113*4882a593Smuzhiyun int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1114*4882a593Smuzhiyun if ((index >= 0) && (index <= 3)) {
1115*4882a593Smuzhiyun /* we want to set the key index */
1116*4882a593Smuzhiyun rvalue |=
1117*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
1118*4882a593Smuzhiyun &index);
1119*4882a593Smuzhiyun } else {
1120*4882a593Smuzhiyun if (!(dwrq->flags & IW_ENCODE_MODE)) {
1121*4882a593Smuzhiyun /* we cannot do anything. Complain. */
1122*4882a593Smuzhiyun return -EINVAL;
1123*4882a593Smuzhiyun }
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun /* now read the flags */
1127*4882a593Smuzhiyun if (dwrq->flags & IW_ENCODE_DISABLED) {
1128*4882a593Smuzhiyun /* Encoding disabled,
1129*4882a593Smuzhiyun * authen = DOT11_AUTH_OS;
1130*4882a593Smuzhiyun * invoke = 0;
1131*4882a593Smuzhiyun * exunencrypt = 0; */
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun if (dwrq->flags & IW_ENCODE_OPEN)
1134*4882a593Smuzhiyun /* Encode but accept non-encoded packets. No auth */
1135*4882a593Smuzhiyun invoke = 1;
1136*4882a593Smuzhiyun if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) {
1137*4882a593Smuzhiyun /* Refuse non-encoded packets. Auth */
1138*4882a593Smuzhiyun authen = DOT11_AUTH_BOTH;
1139*4882a593Smuzhiyun invoke = 1;
1140*4882a593Smuzhiyun exunencrypt = 1;
1141*4882a593Smuzhiyun }
1142*4882a593Smuzhiyun /* do the change if requested */
1143*4882a593Smuzhiyun if ((dwrq->flags & IW_ENCODE_MODE) || force) {
1144*4882a593Smuzhiyun rvalue |=
1145*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
1146*4882a593Smuzhiyun rvalue |=
1147*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
1148*4882a593Smuzhiyun rvalue |=
1149*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
1150*4882a593Smuzhiyun &exunencrypt);
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun return rvalue;
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
1155*4882a593Smuzhiyun static int
prism54_get_encode(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1156*4882a593Smuzhiyun prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
1157*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1160*4882a593Smuzhiyun struct obj_key *key;
1161*4882a593Smuzhiyun u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1162*4882a593Smuzhiyun u32 authen = 0, invoke = 0, exunencrypt = 0;
1163*4882a593Smuzhiyun int rvalue;
1164*4882a593Smuzhiyun union oid_res_t r;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun /* first get the flags */
1167*4882a593Smuzhiyun rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1168*4882a593Smuzhiyun authen = r.u;
1169*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1170*4882a593Smuzhiyun invoke = r.u;
1171*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1172*4882a593Smuzhiyun exunencrypt = r.u;
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt)
1175*4882a593Smuzhiyun dwrq->flags = IW_ENCODE_RESTRICTED;
1176*4882a593Smuzhiyun else if ((authen == DOT11_AUTH_OS) && !exunencrypt) {
1177*4882a593Smuzhiyun if (invoke)
1178*4882a593Smuzhiyun dwrq->flags = IW_ENCODE_OPEN;
1179*4882a593Smuzhiyun else
1180*4882a593Smuzhiyun dwrq->flags = IW_ENCODE_DISABLED;
1181*4882a593Smuzhiyun } else
1182*4882a593Smuzhiyun /* The card should not work in this state */
1183*4882a593Smuzhiyun dwrq->flags = 0;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun /* get the current device key index */
1186*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1187*4882a593Smuzhiyun devindex = r.u;
1188*4882a593Smuzhiyun /* Now get the key, return it */
1189*4882a593Smuzhiyun if (index == -1 || index > 3)
1190*4882a593Smuzhiyun /* no index provided, use the current one */
1191*4882a593Smuzhiyun index = devindex;
1192*4882a593Smuzhiyun rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r);
1193*4882a593Smuzhiyun key = r.ptr;
1194*4882a593Smuzhiyun dwrq->length = key->length;
1195*4882a593Smuzhiyun memcpy(extra, key->key, dwrq->length);
1196*4882a593Smuzhiyun kfree(key);
1197*4882a593Smuzhiyun /* return the used key index */
1198*4882a593Smuzhiyun dwrq->flags |= devindex + 1;
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun return rvalue;
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun static int
prism54_get_txpower(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1204*4882a593Smuzhiyun prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
1205*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1208*4882a593Smuzhiyun union oid_res_t r;
1209*4882a593Smuzhiyun int rvalue;
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r);
1212*4882a593Smuzhiyun /* intersil firmware operates in 0.25 dBm (1/4 dBm) */
1213*4882a593Smuzhiyun vwrq->value = (s32) r.u / 4;
1214*4882a593Smuzhiyun vwrq->fixed = 1;
1215*4882a593Smuzhiyun /* radio is not turned of
1216*4882a593Smuzhiyun * btw: how is possible to turn off only the radio
1217*4882a593Smuzhiyun */
1218*4882a593Smuzhiyun vwrq->disabled = 0;
1219*4882a593Smuzhiyun
1220*4882a593Smuzhiyun return rvalue;
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun static int
prism54_set_txpower(struct net_device * ndev,struct iw_request_info * info,struct iw_param * vwrq,char * extra)1224*4882a593Smuzhiyun prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
1225*4882a593Smuzhiyun struct iw_param *vwrq, char *extra)
1226*4882a593Smuzhiyun {
1227*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1228*4882a593Smuzhiyun s32 u = vwrq->value;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun /* intersil firmware operates in 0.25 dBm (1/4) */
1231*4882a593Smuzhiyun u *= 4;
1232*4882a593Smuzhiyun if (vwrq->disabled) {
1233*4882a593Smuzhiyun /* don't know how to disable radio */
1234*4882a593Smuzhiyun printk(KERN_DEBUG
1235*4882a593Smuzhiyun "%s: %s() disabling radio is not yet supported.\n",
1236*4882a593Smuzhiyun priv->ndev->name, __func__);
1237*4882a593Smuzhiyun return -ENOTSUPP;
1238*4882a593Smuzhiyun } else if (vwrq->fixed)
1239*4882a593Smuzhiyun /* currently only fixed value is supported */
1240*4882a593Smuzhiyun return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u);
1241*4882a593Smuzhiyun else {
1242*4882a593Smuzhiyun printk(KERN_DEBUG
1243*4882a593Smuzhiyun "%s: %s() auto power will be implemented later.\n",
1244*4882a593Smuzhiyun priv->ndev->name, __func__);
1245*4882a593Smuzhiyun return -ENOTSUPP;
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun
prism54_set_genie(struct net_device * ndev,struct iw_request_info * info,struct iw_point * data,char * extra)1249*4882a593Smuzhiyun static int prism54_set_genie(struct net_device *ndev,
1250*4882a593Smuzhiyun struct iw_request_info *info,
1251*4882a593Smuzhiyun struct iw_point *data, char *extra)
1252*4882a593Smuzhiyun {
1253*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1254*4882a593Smuzhiyun int alen, ret = 0;
1255*4882a593Smuzhiyun struct obj_attachment *attach;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun if (data->length > MAX_WPA_IE_LEN ||
1258*4882a593Smuzhiyun (data->length && extra == NULL))
1259*4882a593Smuzhiyun return -EINVAL;
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun memcpy(priv->wpa_ie, extra, data->length);
1262*4882a593Smuzhiyun priv->wpa_ie_len = data->length;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun alen = sizeof(*attach) + priv->wpa_ie_len;
1265*4882a593Smuzhiyun attach = kzalloc(alen, GFP_KERNEL);
1266*4882a593Smuzhiyun if (attach == NULL)
1267*4882a593Smuzhiyun return -ENOMEM;
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun #define WLAN_FC_TYPE_MGMT 0
1270*4882a593Smuzhiyun #define WLAN_FC_STYPE_ASSOC_REQ 0
1271*4882a593Smuzhiyun #define WLAN_FC_STYPE_REASSOC_REQ 2
1272*4882a593Smuzhiyun
1273*4882a593Smuzhiyun /* Note: endianness is covered by mgt_set_varlen */
1274*4882a593Smuzhiyun attach->type = (WLAN_FC_TYPE_MGMT << 2) |
1275*4882a593Smuzhiyun (WLAN_FC_STYPE_ASSOC_REQ << 4);
1276*4882a593Smuzhiyun attach->id = -1;
1277*4882a593Smuzhiyun attach->size = priv->wpa_ie_len;
1278*4882a593Smuzhiyun memcpy(attach->data, extra, priv->wpa_ie_len);
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
1281*4882a593Smuzhiyun priv->wpa_ie_len);
1282*4882a593Smuzhiyun if (ret == 0) {
1283*4882a593Smuzhiyun attach->type = (WLAN_FC_TYPE_MGMT << 2) |
1284*4882a593Smuzhiyun (WLAN_FC_STYPE_REASSOC_REQ << 4);
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
1287*4882a593Smuzhiyun priv->wpa_ie_len);
1288*4882a593Smuzhiyun if (ret == 0)
1289*4882a593Smuzhiyun printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
1290*4882a593Smuzhiyun ndev->name);
1291*4882a593Smuzhiyun }
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun kfree(attach);
1294*4882a593Smuzhiyun return ret;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun
prism54_get_genie(struct net_device * ndev,struct iw_request_info * info,struct iw_point * data,char * extra)1298*4882a593Smuzhiyun static int prism54_get_genie(struct net_device *ndev,
1299*4882a593Smuzhiyun struct iw_request_info *info,
1300*4882a593Smuzhiyun struct iw_point *data, char *extra)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1303*4882a593Smuzhiyun int len = priv->wpa_ie_len;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun if (len <= 0) {
1306*4882a593Smuzhiyun data->length = 0;
1307*4882a593Smuzhiyun return 0;
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun if (data->length < len)
1311*4882a593Smuzhiyun return -E2BIG;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun data->length = len;
1314*4882a593Smuzhiyun memcpy(extra, priv->wpa_ie, len);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun return 0;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun
prism54_set_auth(struct net_device * ndev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1319*4882a593Smuzhiyun static int prism54_set_auth(struct net_device *ndev,
1320*4882a593Smuzhiyun struct iw_request_info *info,
1321*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
1322*4882a593Smuzhiyun {
1323*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1324*4882a593Smuzhiyun struct iw_param *param = &wrqu->param;
1325*4882a593Smuzhiyun u32 mlmelevel = 0, authen = 0, dot1x = 0;
1326*4882a593Smuzhiyun u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
1327*4882a593Smuzhiyun u32 old_wpa;
1328*4882a593Smuzhiyun int ret = 0;
1329*4882a593Smuzhiyun union oid_res_t r;
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
1332*4882a593Smuzhiyun return 0;
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun /* first get the flags */
1335*4882a593Smuzhiyun down_write(&priv->mib_sem);
1336*4882a593Smuzhiyun wpa = old_wpa = priv->wpa;
1337*4882a593Smuzhiyun up_write(&priv->mib_sem);
1338*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1339*4882a593Smuzhiyun authen = r.u;
1340*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1341*4882a593Smuzhiyun privinvoked = r.u;
1342*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1343*4882a593Smuzhiyun exunencrypt = r.u;
1344*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
1345*4882a593Smuzhiyun dot1x = r.u;
1346*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
1347*4882a593Smuzhiyun mlmelevel = r.u;
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun if (ret < 0)
1350*4882a593Smuzhiyun goto out;
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun switch (param->flags & IW_AUTH_INDEX) {
1353*4882a593Smuzhiyun case IW_AUTH_CIPHER_PAIRWISE:
1354*4882a593Smuzhiyun case IW_AUTH_CIPHER_GROUP:
1355*4882a593Smuzhiyun case IW_AUTH_KEY_MGMT:
1356*4882a593Smuzhiyun break;
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun case IW_AUTH_WPA_ENABLED:
1359*4882a593Smuzhiyun /* Do the same thing as IW_AUTH_WPA_VERSION */
1360*4882a593Smuzhiyun if (param->value) {
1361*4882a593Smuzhiyun wpa = 1;
1362*4882a593Smuzhiyun privinvoked = 1; /* For privacy invoked */
1363*4882a593Smuzhiyun exunencrypt = 1; /* Filter out all unencrypted frames */
1364*4882a593Smuzhiyun dot1x = 0x01; /* To enable eap filter */
1365*4882a593Smuzhiyun mlmelevel = DOT11_MLME_EXTENDED;
1366*4882a593Smuzhiyun authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
1367*4882a593Smuzhiyun } else {
1368*4882a593Smuzhiyun wpa = 0;
1369*4882a593Smuzhiyun privinvoked = 0;
1370*4882a593Smuzhiyun exunencrypt = 0; /* Do not filter un-encrypted data */
1371*4882a593Smuzhiyun dot1x = 0;
1372*4882a593Smuzhiyun mlmelevel = DOT11_MLME_AUTO;
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun break;
1375*4882a593Smuzhiyun
1376*4882a593Smuzhiyun case IW_AUTH_WPA_VERSION:
1377*4882a593Smuzhiyun if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
1378*4882a593Smuzhiyun wpa = 0;
1379*4882a593Smuzhiyun privinvoked = 0;
1380*4882a593Smuzhiyun exunencrypt = 0; /* Do not filter un-encrypted data */
1381*4882a593Smuzhiyun dot1x = 0;
1382*4882a593Smuzhiyun mlmelevel = DOT11_MLME_AUTO;
1383*4882a593Smuzhiyun } else {
1384*4882a593Smuzhiyun if (param->value & IW_AUTH_WPA_VERSION_WPA)
1385*4882a593Smuzhiyun wpa = 1;
1386*4882a593Smuzhiyun else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
1387*4882a593Smuzhiyun wpa = 2;
1388*4882a593Smuzhiyun privinvoked = 1; /* For privacy invoked */
1389*4882a593Smuzhiyun exunencrypt = 1; /* Filter out all unencrypted frames */
1390*4882a593Smuzhiyun dot1x = 0x01; /* To enable eap filter */
1391*4882a593Smuzhiyun mlmelevel = DOT11_MLME_EXTENDED;
1392*4882a593Smuzhiyun authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun break;
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1397*4882a593Smuzhiyun /* dot1x should be the opposite of RX_UNENCRYPTED_EAPOL;
1398*4882a593Smuzhiyun * turn off dot1x when allowing receipt of unencrypted EAPOL
1399*4882a593Smuzhiyun * frames, turn on dot1x when receipt should be disallowed
1400*4882a593Smuzhiyun */
1401*4882a593Smuzhiyun dot1x = param->value ? 0 : 0x01;
1402*4882a593Smuzhiyun break;
1403*4882a593Smuzhiyun
1404*4882a593Smuzhiyun case IW_AUTH_PRIVACY_INVOKED:
1405*4882a593Smuzhiyun privinvoked = param->value ? 1 : 0;
1406*4882a593Smuzhiyun break;
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun case IW_AUTH_DROP_UNENCRYPTED:
1409*4882a593Smuzhiyun exunencrypt = param->value ? 1 : 0;
1410*4882a593Smuzhiyun break;
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun case IW_AUTH_80211_AUTH_ALG:
1413*4882a593Smuzhiyun if (param->value & IW_AUTH_ALG_SHARED_KEY) {
1414*4882a593Smuzhiyun /* Only WEP uses _SK and _BOTH */
1415*4882a593Smuzhiyun if (wpa > 0) {
1416*4882a593Smuzhiyun ret = -EINVAL;
1417*4882a593Smuzhiyun goto out;
1418*4882a593Smuzhiyun }
1419*4882a593Smuzhiyun authen = DOT11_AUTH_SK;
1420*4882a593Smuzhiyun } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
1421*4882a593Smuzhiyun authen = DOT11_AUTH_OS;
1422*4882a593Smuzhiyun } else {
1423*4882a593Smuzhiyun ret = -EINVAL;
1424*4882a593Smuzhiyun goto out;
1425*4882a593Smuzhiyun }
1426*4882a593Smuzhiyun break;
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun default:
1429*4882a593Smuzhiyun return -EOPNOTSUPP;
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun /* Set all the values */
1433*4882a593Smuzhiyun down_write(&priv->mib_sem);
1434*4882a593Smuzhiyun priv->wpa = wpa;
1435*4882a593Smuzhiyun up_write(&priv->mib_sem);
1436*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
1437*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
1438*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
1439*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
1440*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun out:
1443*4882a593Smuzhiyun return ret;
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
prism54_get_auth(struct net_device * ndev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1446*4882a593Smuzhiyun static int prism54_get_auth(struct net_device *ndev,
1447*4882a593Smuzhiyun struct iw_request_info *info,
1448*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
1449*4882a593Smuzhiyun {
1450*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1451*4882a593Smuzhiyun struct iw_param *param = &wrqu->param;
1452*4882a593Smuzhiyun u32 wpa = 0;
1453*4882a593Smuzhiyun int ret = 0;
1454*4882a593Smuzhiyun union oid_res_t r;
1455*4882a593Smuzhiyun
1456*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
1457*4882a593Smuzhiyun return 0;
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun /* first get the flags */
1460*4882a593Smuzhiyun down_write(&priv->mib_sem);
1461*4882a593Smuzhiyun wpa = priv->wpa;
1462*4882a593Smuzhiyun up_write(&priv->mib_sem);
1463*4882a593Smuzhiyun
1464*4882a593Smuzhiyun switch (param->flags & IW_AUTH_INDEX) {
1465*4882a593Smuzhiyun case IW_AUTH_CIPHER_PAIRWISE:
1466*4882a593Smuzhiyun case IW_AUTH_CIPHER_GROUP:
1467*4882a593Smuzhiyun case IW_AUTH_KEY_MGMT:
1468*4882a593Smuzhiyun /*
1469*4882a593Smuzhiyun * wpa_supplicant will control these internally
1470*4882a593Smuzhiyun */
1471*4882a593Smuzhiyun ret = -EOPNOTSUPP;
1472*4882a593Smuzhiyun break;
1473*4882a593Smuzhiyun
1474*4882a593Smuzhiyun case IW_AUTH_WPA_VERSION:
1475*4882a593Smuzhiyun switch (wpa) {
1476*4882a593Smuzhiyun case 1:
1477*4882a593Smuzhiyun param->value = IW_AUTH_WPA_VERSION_WPA;
1478*4882a593Smuzhiyun break;
1479*4882a593Smuzhiyun case 2:
1480*4882a593Smuzhiyun param->value = IW_AUTH_WPA_VERSION_WPA2;
1481*4882a593Smuzhiyun break;
1482*4882a593Smuzhiyun case 0:
1483*4882a593Smuzhiyun default:
1484*4882a593Smuzhiyun param->value = IW_AUTH_WPA_VERSION_DISABLED;
1485*4882a593Smuzhiyun break;
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun break;
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun case IW_AUTH_DROP_UNENCRYPTED:
1490*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1491*4882a593Smuzhiyun if (ret >= 0)
1492*4882a593Smuzhiyun param->value = r.u > 0 ? 1 : 0;
1493*4882a593Smuzhiyun break;
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun case IW_AUTH_80211_AUTH_ALG:
1496*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1497*4882a593Smuzhiyun if (ret >= 0) {
1498*4882a593Smuzhiyun switch (r.u) {
1499*4882a593Smuzhiyun case DOT11_AUTH_OS:
1500*4882a593Smuzhiyun param->value = IW_AUTH_ALG_OPEN_SYSTEM;
1501*4882a593Smuzhiyun break;
1502*4882a593Smuzhiyun case DOT11_AUTH_BOTH:
1503*4882a593Smuzhiyun case DOT11_AUTH_SK:
1504*4882a593Smuzhiyun param->value = IW_AUTH_ALG_SHARED_KEY;
1505*4882a593Smuzhiyun break;
1506*4882a593Smuzhiyun case DOT11_AUTH_NONE:
1507*4882a593Smuzhiyun default:
1508*4882a593Smuzhiyun param->value = 0;
1509*4882a593Smuzhiyun break;
1510*4882a593Smuzhiyun }
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun break;
1513*4882a593Smuzhiyun
1514*4882a593Smuzhiyun case IW_AUTH_WPA_ENABLED:
1515*4882a593Smuzhiyun param->value = wpa > 0 ? 1 : 0;
1516*4882a593Smuzhiyun break;
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1519*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
1520*4882a593Smuzhiyun if (ret >= 0)
1521*4882a593Smuzhiyun param->value = r.u > 0 ? 1 : 0;
1522*4882a593Smuzhiyun break;
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun case IW_AUTH_PRIVACY_INVOKED:
1525*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1526*4882a593Smuzhiyun if (ret >= 0)
1527*4882a593Smuzhiyun param->value = r.u > 0 ? 1 : 0;
1528*4882a593Smuzhiyun break;
1529*4882a593Smuzhiyun
1530*4882a593Smuzhiyun default:
1531*4882a593Smuzhiyun return -EOPNOTSUPP;
1532*4882a593Smuzhiyun }
1533*4882a593Smuzhiyun return ret;
1534*4882a593Smuzhiyun }
1535*4882a593Smuzhiyun
prism54_set_encodeext(struct net_device * ndev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1536*4882a593Smuzhiyun static int prism54_set_encodeext(struct net_device *ndev,
1537*4882a593Smuzhiyun struct iw_request_info *info,
1538*4882a593Smuzhiyun union iwreq_data *wrqu,
1539*4882a593Smuzhiyun char *extra)
1540*4882a593Smuzhiyun {
1541*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1542*4882a593Smuzhiyun struct iw_point *encoding = &wrqu->encoding;
1543*4882a593Smuzhiyun struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1544*4882a593Smuzhiyun int idx, alg = ext->alg, set_key = 1;
1545*4882a593Smuzhiyun union oid_res_t r;
1546*4882a593Smuzhiyun int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
1547*4882a593Smuzhiyun int ret = 0;
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
1550*4882a593Smuzhiyun return 0;
1551*4882a593Smuzhiyun
1552*4882a593Smuzhiyun /* Determine and validate the key index */
1553*4882a593Smuzhiyun idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
1554*4882a593Smuzhiyun if (idx) {
1555*4882a593Smuzhiyun if (idx < 0 || idx > 3)
1556*4882a593Smuzhiyun return -EINVAL;
1557*4882a593Smuzhiyun } else {
1558*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1559*4882a593Smuzhiyun if (ret < 0)
1560*4882a593Smuzhiyun goto out;
1561*4882a593Smuzhiyun idx = r.u;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun
1564*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_DISABLED)
1565*4882a593Smuzhiyun alg = IW_ENCODE_ALG_NONE;
1566*4882a593Smuzhiyun
1567*4882a593Smuzhiyun if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1568*4882a593Smuzhiyun /* Only set transmit key index here, actual
1569*4882a593Smuzhiyun * key is set below if needed.
1570*4882a593Smuzhiyun */
1571*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
1572*4882a593Smuzhiyun set_key = ext->key_len > 0 ? 1 : 0;
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun if (set_key) {
1576*4882a593Smuzhiyun struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
1577*4882a593Smuzhiyun switch (alg) {
1578*4882a593Smuzhiyun case IW_ENCODE_ALG_NONE:
1579*4882a593Smuzhiyun break;
1580*4882a593Smuzhiyun case IW_ENCODE_ALG_WEP:
1581*4882a593Smuzhiyun if (ext->key_len > KEY_SIZE_WEP104) {
1582*4882a593Smuzhiyun ret = -EINVAL;
1583*4882a593Smuzhiyun goto out;
1584*4882a593Smuzhiyun }
1585*4882a593Smuzhiyun if (ext->key_len > KEY_SIZE_WEP40)
1586*4882a593Smuzhiyun key.length = KEY_SIZE_WEP104;
1587*4882a593Smuzhiyun else
1588*4882a593Smuzhiyun key.length = KEY_SIZE_WEP40;
1589*4882a593Smuzhiyun break;
1590*4882a593Smuzhiyun case IW_ENCODE_ALG_TKIP:
1591*4882a593Smuzhiyun if (ext->key_len > KEY_SIZE_TKIP) {
1592*4882a593Smuzhiyun ret = -EINVAL;
1593*4882a593Smuzhiyun goto out;
1594*4882a593Smuzhiyun }
1595*4882a593Smuzhiyun key.type = DOT11_PRIV_TKIP;
1596*4882a593Smuzhiyun key.length = KEY_SIZE_TKIP;
1597*4882a593Smuzhiyun break;
1598*4882a593Smuzhiyun default:
1599*4882a593Smuzhiyun return -EINVAL;
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun
1602*4882a593Smuzhiyun if (key.length) {
1603*4882a593Smuzhiyun memset(key.key, 0, sizeof(key.key));
1604*4882a593Smuzhiyun memcpy(key.key, ext->key, ext->key_len);
1605*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
1606*4882a593Smuzhiyun &key);
1607*4882a593Smuzhiyun if (ret < 0)
1608*4882a593Smuzhiyun goto out;
1609*4882a593Smuzhiyun }
1610*4882a593Smuzhiyun }
1611*4882a593Smuzhiyun
1612*4882a593Smuzhiyun /* Read the flags */
1613*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_DISABLED) {
1614*4882a593Smuzhiyun /* Encoding disabled,
1615*4882a593Smuzhiyun * authen = DOT11_AUTH_OS;
1616*4882a593Smuzhiyun * invoke = 0;
1617*4882a593Smuzhiyun * exunencrypt = 0; */
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_OPEN) {
1620*4882a593Smuzhiyun /* Encode but accept non-encoded packets. No auth */
1621*4882a593Smuzhiyun invoke = 1;
1622*4882a593Smuzhiyun }
1623*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_RESTRICTED) {
1624*4882a593Smuzhiyun /* Refuse non-encoded packets. Auth */
1625*4882a593Smuzhiyun authen = DOT11_AUTH_BOTH;
1626*4882a593Smuzhiyun invoke = 1;
1627*4882a593Smuzhiyun exunencrypt = 1;
1628*4882a593Smuzhiyun }
1629*4882a593Smuzhiyun
1630*4882a593Smuzhiyun /* do the change if requested */
1631*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_MODE) {
1632*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
1633*4882a593Smuzhiyun &authen);
1634*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
1635*4882a593Smuzhiyun &invoke);
1636*4882a593Smuzhiyun ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
1637*4882a593Smuzhiyun &exunencrypt);
1638*4882a593Smuzhiyun }
1639*4882a593Smuzhiyun
1640*4882a593Smuzhiyun out:
1641*4882a593Smuzhiyun return ret;
1642*4882a593Smuzhiyun }
1643*4882a593Smuzhiyun
1644*4882a593Smuzhiyun
prism54_get_encodeext(struct net_device * ndev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1645*4882a593Smuzhiyun static int prism54_get_encodeext(struct net_device *ndev,
1646*4882a593Smuzhiyun struct iw_request_info *info,
1647*4882a593Smuzhiyun union iwreq_data *wrqu,
1648*4882a593Smuzhiyun char *extra)
1649*4882a593Smuzhiyun {
1650*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1651*4882a593Smuzhiyun struct iw_point *encoding = &wrqu->encoding;
1652*4882a593Smuzhiyun struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
1653*4882a593Smuzhiyun int idx, max_key_len;
1654*4882a593Smuzhiyun union oid_res_t r;
1655*4882a593Smuzhiyun int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
1656*4882a593Smuzhiyun int ret = 0;
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
1659*4882a593Smuzhiyun return 0;
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun /* first get the flags */
1662*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
1663*4882a593Smuzhiyun authen = r.u;
1664*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
1665*4882a593Smuzhiyun invoke = r.u;
1666*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
1667*4882a593Smuzhiyun exunencrypt = r.u;
1668*4882a593Smuzhiyun if (ret < 0)
1669*4882a593Smuzhiyun goto out;
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun max_key_len = encoding->length - sizeof(*ext);
1672*4882a593Smuzhiyun if (max_key_len < 0)
1673*4882a593Smuzhiyun return -EINVAL;
1674*4882a593Smuzhiyun
1675*4882a593Smuzhiyun idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
1676*4882a593Smuzhiyun if (idx) {
1677*4882a593Smuzhiyun if (idx < 0 || idx > 3)
1678*4882a593Smuzhiyun return -EINVAL;
1679*4882a593Smuzhiyun } else {
1680*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
1681*4882a593Smuzhiyun if (ret < 0)
1682*4882a593Smuzhiyun goto out;
1683*4882a593Smuzhiyun idx = r.u;
1684*4882a593Smuzhiyun }
1685*4882a593Smuzhiyun
1686*4882a593Smuzhiyun encoding->flags = idx + 1;
1687*4882a593Smuzhiyun memset(ext, 0, sizeof(*ext));
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun switch (authen) {
1690*4882a593Smuzhiyun case DOT11_AUTH_BOTH:
1691*4882a593Smuzhiyun case DOT11_AUTH_SK:
1692*4882a593Smuzhiyun wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
1693*4882a593Smuzhiyun fallthrough;
1694*4882a593Smuzhiyun case DOT11_AUTH_OS:
1695*4882a593Smuzhiyun default:
1696*4882a593Smuzhiyun wrqu->encoding.flags |= IW_ENCODE_OPEN;
1697*4882a593Smuzhiyun break;
1698*4882a593Smuzhiyun }
1699*4882a593Smuzhiyun
1700*4882a593Smuzhiyun down_write(&priv->mib_sem);
1701*4882a593Smuzhiyun wpa = priv->wpa;
1702*4882a593Smuzhiyun up_write(&priv->mib_sem);
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
1705*4882a593Smuzhiyun /* No encryption */
1706*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_NONE;
1707*4882a593Smuzhiyun ext->key_len = 0;
1708*4882a593Smuzhiyun wrqu->encoding.flags |= IW_ENCODE_DISABLED;
1709*4882a593Smuzhiyun } else {
1710*4882a593Smuzhiyun struct obj_key *key;
1711*4882a593Smuzhiyun
1712*4882a593Smuzhiyun ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
1713*4882a593Smuzhiyun if (ret < 0)
1714*4882a593Smuzhiyun goto out;
1715*4882a593Smuzhiyun key = r.ptr;
1716*4882a593Smuzhiyun if (max_key_len < key->length) {
1717*4882a593Smuzhiyun ret = -E2BIG;
1718*4882a593Smuzhiyun goto out;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun memcpy(ext->key, key->key, key->length);
1721*4882a593Smuzhiyun ext->key_len = key->length;
1722*4882a593Smuzhiyun
1723*4882a593Smuzhiyun switch (key->type) {
1724*4882a593Smuzhiyun case DOT11_PRIV_TKIP:
1725*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_TKIP;
1726*4882a593Smuzhiyun break;
1727*4882a593Smuzhiyun default:
1728*4882a593Smuzhiyun case DOT11_PRIV_WEP:
1729*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_WEP;
1730*4882a593Smuzhiyun break;
1731*4882a593Smuzhiyun }
1732*4882a593Smuzhiyun wrqu->encoding.flags |= IW_ENCODE_ENABLED;
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun out:
1736*4882a593Smuzhiyun return ret;
1737*4882a593Smuzhiyun }
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun static int
prism54_reset(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)1741*4882a593Smuzhiyun prism54_reset(struct net_device *ndev, struct iw_request_info *info,
1742*4882a593Smuzhiyun __u32 * uwrq, char *extra)
1743*4882a593Smuzhiyun {
1744*4882a593Smuzhiyun islpci_reset(netdev_priv(ndev), 0);
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun return 0;
1747*4882a593Smuzhiyun }
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun static int
prism54_get_oid(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1750*4882a593Smuzhiyun prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
1751*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1752*4882a593Smuzhiyun {
1753*4882a593Smuzhiyun union oid_res_t r;
1754*4882a593Smuzhiyun int rvalue;
1755*4882a593Smuzhiyun enum oid_num_t n = dwrq->flags;
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r);
1758*4882a593Smuzhiyun dwrq->length = mgt_response_to_str(n, &r, extra);
1759*4882a593Smuzhiyun if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
1760*4882a593Smuzhiyun kfree(r.ptr);
1761*4882a593Smuzhiyun return rvalue;
1762*4882a593Smuzhiyun }
1763*4882a593Smuzhiyun
1764*4882a593Smuzhiyun static int
prism54_set_u32(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)1765*4882a593Smuzhiyun prism54_set_u32(struct net_device *ndev, struct iw_request_info *info,
1766*4882a593Smuzhiyun __u32 * uwrq, char *extra)
1767*4882a593Smuzhiyun {
1768*4882a593Smuzhiyun u32 oid = uwrq[0], u = uwrq[1];
1769*4882a593Smuzhiyun
1770*4882a593Smuzhiyun return mgt_set_request(netdev_priv(ndev), oid, 0, &u);
1771*4882a593Smuzhiyun }
1772*4882a593Smuzhiyun
1773*4882a593Smuzhiyun static int
prism54_set_raw(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1774*4882a593Smuzhiyun prism54_set_raw(struct net_device *ndev, struct iw_request_info *info,
1775*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun u32 oid = dwrq->flags;
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun return mgt_set_request(netdev_priv(ndev), oid, 0, extra);
1780*4882a593Smuzhiyun }
1781*4882a593Smuzhiyun
1782*4882a593Smuzhiyun void
prism54_acl_init(struct islpci_acl * acl)1783*4882a593Smuzhiyun prism54_acl_init(struct islpci_acl *acl)
1784*4882a593Smuzhiyun {
1785*4882a593Smuzhiyun mutex_init(&acl->lock);
1786*4882a593Smuzhiyun INIT_LIST_HEAD(&acl->mac_list);
1787*4882a593Smuzhiyun acl->size = 0;
1788*4882a593Smuzhiyun acl->policy = MAC_POLICY_OPEN;
1789*4882a593Smuzhiyun }
1790*4882a593Smuzhiyun
1791*4882a593Smuzhiyun static void
prism54_clear_mac(struct islpci_acl * acl)1792*4882a593Smuzhiyun prism54_clear_mac(struct islpci_acl *acl)
1793*4882a593Smuzhiyun {
1794*4882a593Smuzhiyun struct list_head *ptr, *next;
1795*4882a593Smuzhiyun struct mac_entry *entry;
1796*4882a593Smuzhiyun
1797*4882a593Smuzhiyun mutex_lock(&acl->lock);
1798*4882a593Smuzhiyun
1799*4882a593Smuzhiyun if (acl->size == 0) {
1800*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1801*4882a593Smuzhiyun return;
1802*4882a593Smuzhiyun }
1803*4882a593Smuzhiyun
1804*4882a593Smuzhiyun for (ptr = acl->mac_list.next, next = ptr->next;
1805*4882a593Smuzhiyun ptr != &acl->mac_list; ptr = next, next = ptr->next) {
1806*4882a593Smuzhiyun entry = list_entry(ptr, struct mac_entry, _list);
1807*4882a593Smuzhiyun list_del(ptr);
1808*4882a593Smuzhiyun kfree(entry);
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun acl->size = 0;
1811*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1812*4882a593Smuzhiyun }
1813*4882a593Smuzhiyun
1814*4882a593Smuzhiyun void
prism54_acl_clean(struct islpci_acl * acl)1815*4882a593Smuzhiyun prism54_acl_clean(struct islpci_acl *acl)
1816*4882a593Smuzhiyun {
1817*4882a593Smuzhiyun prism54_clear_mac(acl);
1818*4882a593Smuzhiyun }
1819*4882a593Smuzhiyun
1820*4882a593Smuzhiyun static int
prism54_add_mac(struct net_device * ndev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)1821*4882a593Smuzhiyun prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
1822*4882a593Smuzhiyun struct sockaddr *awrq, char *extra)
1823*4882a593Smuzhiyun {
1824*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1825*4882a593Smuzhiyun struct islpci_acl *acl = &priv->acl;
1826*4882a593Smuzhiyun struct mac_entry *entry;
1827*4882a593Smuzhiyun struct sockaddr *addr = (struct sockaddr *) extra;
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun if (addr->sa_family != ARPHRD_ETHER)
1830*4882a593Smuzhiyun return -EOPNOTSUPP;
1831*4882a593Smuzhiyun
1832*4882a593Smuzhiyun entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL);
1833*4882a593Smuzhiyun if (entry == NULL)
1834*4882a593Smuzhiyun return -ENOMEM;
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun memcpy(entry->addr, addr->sa_data, ETH_ALEN);
1837*4882a593Smuzhiyun
1838*4882a593Smuzhiyun if (mutex_lock_interruptible(&acl->lock)) {
1839*4882a593Smuzhiyun kfree(entry);
1840*4882a593Smuzhiyun return -ERESTARTSYS;
1841*4882a593Smuzhiyun }
1842*4882a593Smuzhiyun list_add_tail(&entry->_list, &acl->mac_list);
1843*4882a593Smuzhiyun acl->size++;
1844*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun return 0;
1847*4882a593Smuzhiyun }
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun static int
prism54_del_mac(struct net_device * ndev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)1850*4882a593Smuzhiyun prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
1851*4882a593Smuzhiyun struct sockaddr *awrq, char *extra)
1852*4882a593Smuzhiyun {
1853*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1854*4882a593Smuzhiyun struct islpci_acl *acl = &priv->acl;
1855*4882a593Smuzhiyun struct mac_entry *entry;
1856*4882a593Smuzhiyun struct sockaddr *addr = (struct sockaddr *) extra;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun if (addr->sa_family != ARPHRD_ETHER)
1859*4882a593Smuzhiyun return -EOPNOTSUPP;
1860*4882a593Smuzhiyun
1861*4882a593Smuzhiyun if (mutex_lock_interruptible(&acl->lock))
1862*4882a593Smuzhiyun return -ERESTARTSYS;
1863*4882a593Smuzhiyun list_for_each_entry(entry, &acl->mac_list, _list) {
1864*4882a593Smuzhiyun if (ether_addr_equal(entry->addr, addr->sa_data)) {
1865*4882a593Smuzhiyun list_del(&entry->_list);
1866*4882a593Smuzhiyun acl->size--;
1867*4882a593Smuzhiyun kfree(entry);
1868*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1869*4882a593Smuzhiyun return 0;
1870*4882a593Smuzhiyun }
1871*4882a593Smuzhiyun }
1872*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1873*4882a593Smuzhiyun return -EINVAL;
1874*4882a593Smuzhiyun }
1875*4882a593Smuzhiyun
1876*4882a593Smuzhiyun static int
prism54_get_mac(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1877*4882a593Smuzhiyun prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
1878*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1881*4882a593Smuzhiyun struct islpci_acl *acl = &priv->acl;
1882*4882a593Smuzhiyun struct mac_entry *entry;
1883*4882a593Smuzhiyun struct sockaddr *dst = (struct sockaddr *) extra;
1884*4882a593Smuzhiyun
1885*4882a593Smuzhiyun dwrq->length = 0;
1886*4882a593Smuzhiyun
1887*4882a593Smuzhiyun if (mutex_lock_interruptible(&acl->lock))
1888*4882a593Smuzhiyun return -ERESTARTSYS;
1889*4882a593Smuzhiyun
1890*4882a593Smuzhiyun list_for_each_entry(entry, &acl->mac_list, _list) {
1891*4882a593Smuzhiyun memcpy(dst->sa_data, entry->addr, ETH_ALEN);
1892*4882a593Smuzhiyun dst->sa_family = ARPHRD_ETHER;
1893*4882a593Smuzhiyun dwrq->length++;
1894*4882a593Smuzhiyun dst++;
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1897*4882a593Smuzhiyun return 0;
1898*4882a593Smuzhiyun }
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun /* Setting policy also clears the MAC acl, even if we don't change the default
1901*4882a593Smuzhiyun * policy
1902*4882a593Smuzhiyun */
1903*4882a593Smuzhiyun
1904*4882a593Smuzhiyun static int
prism54_set_policy(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)1905*4882a593Smuzhiyun prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
1906*4882a593Smuzhiyun __u32 * uwrq, char *extra)
1907*4882a593Smuzhiyun {
1908*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1909*4882a593Smuzhiyun struct islpci_acl *acl = &priv->acl;
1910*4882a593Smuzhiyun u32 mlmeautolevel;
1911*4882a593Smuzhiyun
1912*4882a593Smuzhiyun prism54_clear_mac(acl);
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT))
1915*4882a593Smuzhiyun return -EINVAL;
1916*4882a593Smuzhiyun
1917*4882a593Smuzhiyun down_write(&priv->mib_sem);
1918*4882a593Smuzhiyun
1919*4882a593Smuzhiyun acl->policy = *uwrq;
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun /* the ACL code needs an intermediate mlmeautolevel */
1922*4882a593Smuzhiyun if ((priv->iw_mode == IW_MODE_MASTER) &&
1923*4882a593Smuzhiyun (acl->policy != MAC_POLICY_OPEN))
1924*4882a593Smuzhiyun mlmeautolevel = DOT11_MLME_INTERMEDIATE;
1925*4882a593Smuzhiyun else
1926*4882a593Smuzhiyun mlmeautolevel = CARD_DEFAULT_MLME_MODE;
1927*4882a593Smuzhiyun if (priv->wpa)
1928*4882a593Smuzhiyun mlmeautolevel = DOT11_MLME_EXTENDED;
1929*4882a593Smuzhiyun mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel);
1930*4882a593Smuzhiyun /* restart the card with our new policy */
1931*4882a593Smuzhiyun if (mgt_commit(priv)) {
1932*4882a593Smuzhiyun up_write(&priv->mib_sem);
1933*4882a593Smuzhiyun return -EIO;
1934*4882a593Smuzhiyun }
1935*4882a593Smuzhiyun up_write(&priv->mib_sem);
1936*4882a593Smuzhiyun
1937*4882a593Smuzhiyun return 0;
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun
1940*4882a593Smuzhiyun static int
prism54_get_policy(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)1941*4882a593Smuzhiyun prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
1942*4882a593Smuzhiyun __u32 * uwrq, char *extra)
1943*4882a593Smuzhiyun {
1944*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
1945*4882a593Smuzhiyun struct islpci_acl *acl = &priv->acl;
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun *uwrq = acl->policy;
1948*4882a593Smuzhiyun
1949*4882a593Smuzhiyun return 0;
1950*4882a593Smuzhiyun }
1951*4882a593Smuzhiyun
1952*4882a593Smuzhiyun /* Return 1 only if client should be accepted. */
1953*4882a593Smuzhiyun
1954*4882a593Smuzhiyun static int
prism54_mac_accept(struct islpci_acl * acl,char * mac)1955*4882a593Smuzhiyun prism54_mac_accept(struct islpci_acl *acl, char *mac)
1956*4882a593Smuzhiyun {
1957*4882a593Smuzhiyun struct mac_entry *entry;
1958*4882a593Smuzhiyun int res = 0;
1959*4882a593Smuzhiyun
1960*4882a593Smuzhiyun if (mutex_lock_interruptible(&acl->lock))
1961*4882a593Smuzhiyun return -ERESTARTSYS;
1962*4882a593Smuzhiyun
1963*4882a593Smuzhiyun if (acl->policy == MAC_POLICY_OPEN) {
1964*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1965*4882a593Smuzhiyun return 1;
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun
1968*4882a593Smuzhiyun list_for_each_entry(entry, &acl->mac_list, _list) {
1969*4882a593Smuzhiyun if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
1970*4882a593Smuzhiyun res = 1;
1971*4882a593Smuzhiyun break;
1972*4882a593Smuzhiyun }
1973*4882a593Smuzhiyun }
1974*4882a593Smuzhiyun res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res;
1975*4882a593Smuzhiyun mutex_unlock(&acl->lock);
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun return res;
1978*4882a593Smuzhiyun }
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun static int
prism54_kick_all(struct net_device * ndev,struct iw_request_info * info,struct iw_point * dwrq,char * extra)1981*4882a593Smuzhiyun prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
1982*4882a593Smuzhiyun struct iw_point *dwrq, char *extra)
1983*4882a593Smuzhiyun {
1984*4882a593Smuzhiyun struct obj_mlme *mlme;
1985*4882a593Smuzhiyun int rvalue;
1986*4882a593Smuzhiyun
1987*4882a593Smuzhiyun mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
1988*4882a593Smuzhiyun if (mlme == NULL)
1989*4882a593Smuzhiyun return -ENOMEM;
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun /* Tell the card to kick every client */
1992*4882a593Smuzhiyun mlme->id = 0;
1993*4882a593Smuzhiyun rvalue =
1994*4882a593Smuzhiyun mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
1995*4882a593Smuzhiyun kfree(mlme);
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun return rvalue;
1998*4882a593Smuzhiyun }
1999*4882a593Smuzhiyun
2000*4882a593Smuzhiyun static int
prism54_kick_mac(struct net_device * ndev,struct iw_request_info * info,struct sockaddr * awrq,char * extra)2001*4882a593Smuzhiyun prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
2002*4882a593Smuzhiyun struct sockaddr *awrq, char *extra)
2003*4882a593Smuzhiyun {
2004*4882a593Smuzhiyun struct obj_mlme *mlme;
2005*4882a593Smuzhiyun struct sockaddr *addr = (struct sockaddr *) extra;
2006*4882a593Smuzhiyun int rvalue;
2007*4882a593Smuzhiyun
2008*4882a593Smuzhiyun if (addr->sa_family != ARPHRD_ETHER)
2009*4882a593Smuzhiyun return -EOPNOTSUPP;
2010*4882a593Smuzhiyun
2011*4882a593Smuzhiyun mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL);
2012*4882a593Smuzhiyun if (mlme == NULL)
2013*4882a593Smuzhiyun return -ENOMEM;
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun /* Tell the card to only kick the corresponding bastard */
2016*4882a593Smuzhiyun memcpy(mlme->address, addr->sa_data, ETH_ALEN);
2017*4882a593Smuzhiyun mlme->id = -1;
2018*4882a593Smuzhiyun rvalue =
2019*4882a593Smuzhiyun mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
2020*4882a593Smuzhiyun
2021*4882a593Smuzhiyun kfree(mlme);
2022*4882a593Smuzhiyun
2023*4882a593Smuzhiyun return rvalue;
2024*4882a593Smuzhiyun }
2025*4882a593Smuzhiyun
2026*4882a593Smuzhiyun /* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */
2027*4882a593Smuzhiyun
2028*4882a593Smuzhiyun static void
format_event(islpci_private * priv,char * dest,const char * str,const struct obj_mlme * mlme,u16 * length,int error)2029*4882a593Smuzhiyun format_event(islpci_private *priv, char *dest, const char *str,
2030*4882a593Smuzhiyun const struct obj_mlme *mlme, u16 *length, int error)
2031*4882a593Smuzhiyun {
2032*4882a593Smuzhiyun int n = snprintf(dest, IW_CUSTOM_MAX,
2033*4882a593Smuzhiyun "%s %s %pM %s (%2.2X)",
2034*4882a593Smuzhiyun str,
2035*4882a593Smuzhiyun ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
2036*4882a593Smuzhiyun mlme->address,
2037*4882a593Smuzhiyun (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
2038*4882a593Smuzhiyun : ""), mlme->code);
2039*4882a593Smuzhiyun WARN_ON(n >= IW_CUSTOM_MAX);
2040*4882a593Smuzhiyun *length = n;
2041*4882a593Smuzhiyun }
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun static void
send_formatted_event(islpci_private * priv,const char * str,const struct obj_mlme * mlme,int error)2044*4882a593Smuzhiyun send_formatted_event(islpci_private *priv, const char *str,
2045*4882a593Smuzhiyun const struct obj_mlme *mlme, int error)
2046*4882a593Smuzhiyun {
2047*4882a593Smuzhiyun union iwreq_data wrqu;
2048*4882a593Smuzhiyun char *memptr;
2049*4882a593Smuzhiyun
2050*4882a593Smuzhiyun memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
2051*4882a593Smuzhiyun if (!memptr)
2052*4882a593Smuzhiyun return;
2053*4882a593Smuzhiyun wrqu.data.pointer = memptr;
2054*4882a593Smuzhiyun wrqu.data.length = 0;
2055*4882a593Smuzhiyun format_event(priv, memptr, str, mlme, &wrqu.data.length,
2056*4882a593Smuzhiyun error);
2057*4882a593Smuzhiyun wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
2058*4882a593Smuzhiyun kfree(memptr);
2059*4882a593Smuzhiyun }
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun static void
send_simple_event(islpci_private * priv,const char * str)2062*4882a593Smuzhiyun send_simple_event(islpci_private *priv, const char *str)
2063*4882a593Smuzhiyun {
2064*4882a593Smuzhiyun union iwreq_data wrqu;
2065*4882a593Smuzhiyun char *memptr;
2066*4882a593Smuzhiyun int n = strlen(str);
2067*4882a593Smuzhiyun
2068*4882a593Smuzhiyun memptr = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL);
2069*4882a593Smuzhiyun if (!memptr)
2070*4882a593Smuzhiyun return;
2071*4882a593Smuzhiyun BUG_ON(n >= IW_CUSTOM_MAX);
2072*4882a593Smuzhiyun wrqu.data.pointer = memptr;
2073*4882a593Smuzhiyun wrqu.data.length = n;
2074*4882a593Smuzhiyun strcpy(memptr, str);
2075*4882a593Smuzhiyun wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, memptr);
2076*4882a593Smuzhiyun kfree(memptr);
2077*4882a593Smuzhiyun }
2078*4882a593Smuzhiyun
2079*4882a593Smuzhiyun static void
link_changed(struct net_device * ndev,u32 bitrate)2080*4882a593Smuzhiyun link_changed(struct net_device *ndev, u32 bitrate)
2081*4882a593Smuzhiyun {
2082*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2083*4882a593Smuzhiyun
2084*4882a593Smuzhiyun if (bitrate) {
2085*4882a593Smuzhiyun netif_carrier_on(ndev);
2086*4882a593Smuzhiyun if (priv->iw_mode == IW_MODE_INFRA) {
2087*4882a593Smuzhiyun union iwreq_data uwrq;
2088*4882a593Smuzhiyun prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq,
2089*4882a593Smuzhiyun NULL);
2090*4882a593Smuzhiyun wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
2091*4882a593Smuzhiyun } else
2092*4882a593Smuzhiyun send_simple_event(netdev_priv(ndev),
2093*4882a593Smuzhiyun "Link established");
2094*4882a593Smuzhiyun } else {
2095*4882a593Smuzhiyun netif_carrier_off(ndev);
2096*4882a593Smuzhiyun send_simple_event(netdev_priv(ndev), "Link lost");
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun }
2099*4882a593Smuzhiyun
2100*4882a593Smuzhiyun /* Beacon/ProbeResp payload header */
2101*4882a593Smuzhiyun struct ieee80211_beacon_phdr {
2102*4882a593Smuzhiyun u8 timestamp[8];
2103*4882a593Smuzhiyun u16 beacon_int;
2104*4882a593Smuzhiyun u16 capab_info;
2105*4882a593Smuzhiyun } __packed;
2106*4882a593Smuzhiyun
2107*4882a593Smuzhiyun #define WLAN_EID_GENERIC 0xdd
2108*4882a593Smuzhiyun static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
2109*4882a593Smuzhiyun
2110*4882a593Smuzhiyun static void
prism54_wpa_bss_ie_add(islpci_private * priv,u8 * bssid,u8 * wpa_ie,size_t wpa_ie_len)2111*4882a593Smuzhiyun prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
2112*4882a593Smuzhiyun u8 *wpa_ie, size_t wpa_ie_len)
2113*4882a593Smuzhiyun {
2114*4882a593Smuzhiyun struct list_head *ptr;
2115*4882a593Smuzhiyun struct islpci_bss_wpa_ie *bss = NULL;
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun if (wpa_ie_len > MAX_WPA_IE_LEN)
2118*4882a593Smuzhiyun wpa_ie_len = MAX_WPA_IE_LEN;
2119*4882a593Smuzhiyun
2120*4882a593Smuzhiyun mutex_lock(&priv->wpa_lock);
2121*4882a593Smuzhiyun
2122*4882a593Smuzhiyun /* try to use existing entry */
2123*4882a593Smuzhiyun list_for_each(ptr, &priv->bss_wpa_list) {
2124*4882a593Smuzhiyun bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
2125*4882a593Smuzhiyun if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
2126*4882a593Smuzhiyun list_move(&bss->list, &priv->bss_wpa_list);
2127*4882a593Smuzhiyun break;
2128*4882a593Smuzhiyun }
2129*4882a593Smuzhiyun bss = NULL;
2130*4882a593Smuzhiyun }
2131*4882a593Smuzhiyun
2132*4882a593Smuzhiyun if (bss == NULL) {
2133*4882a593Smuzhiyun /* add a new BSS entry; if max number of entries is already
2134*4882a593Smuzhiyun * reached, replace the least recently updated */
2135*4882a593Smuzhiyun if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) {
2136*4882a593Smuzhiyun bss = list_entry(priv->bss_wpa_list.prev,
2137*4882a593Smuzhiyun struct islpci_bss_wpa_ie, list);
2138*4882a593Smuzhiyun list_del(&bss->list);
2139*4882a593Smuzhiyun } else {
2140*4882a593Smuzhiyun bss = kzalloc(sizeof (*bss), GFP_ATOMIC);
2141*4882a593Smuzhiyun if (bss != NULL)
2142*4882a593Smuzhiyun priv->num_bss_wpa++;
2143*4882a593Smuzhiyun }
2144*4882a593Smuzhiyun if (bss != NULL) {
2145*4882a593Smuzhiyun memcpy(bss->bssid, bssid, ETH_ALEN);
2146*4882a593Smuzhiyun list_add(&bss->list, &priv->bss_wpa_list);
2147*4882a593Smuzhiyun }
2148*4882a593Smuzhiyun }
2149*4882a593Smuzhiyun
2150*4882a593Smuzhiyun if (bss != NULL) {
2151*4882a593Smuzhiyun memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len);
2152*4882a593Smuzhiyun bss->wpa_ie_len = wpa_ie_len;
2153*4882a593Smuzhiyun bss->last_update = jiffies;
2154*4882a593Smuzhiyun } else {
2155*4882a593Smuzhiyun printk(KERN_DEBUG "Failed to add BSS WPA entry for "
2156*4882a593Smuzhiyun "%pM\n", bssid);
2157*4882a593Smuzhiyun }
2158*4882a593Smuzhiyun
2159*4882a593Smuzhiyun /* expire old entries from WPA list */
2160*4882a593Smuzhiyun while (priv->num_bss_wpa > 0) {
2161*4882a593Smuzhiyun bss = list_entry(priv->bss_wpa_list.prev,
2162*4882a593Smuzhiyun struct islpci_bss_wpa_ie, list);
2163*4882a593Smuzhiyun if (!time_after(jiffies, bss->last_update + 60 * HZ))
2164*4882a593Smuzhiyun break;
2165*4882a593Smuzhiyun
2166*4882a593Smuzhiyun list_del(&bss->list);
2167*4882a593Smuzhiyun priv->num_bss_wpa--;
2168*4882a593Smuzhiyun kfree(bss);
2169*4882a593Smuzhiyun }
2170*4882a593Smuzhiyun
2171*4882a593Smuzhiyun mutex_unlock(&priv->wpa_lock);
2172*4882a593Smuzhiyun }
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun static size_t
prism54_wpa_bss_ie_get(islpci_private * priv,u8 * bssid,u8 * wpa_ie)2175*4882a593Smuzhiyun prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
2176*4882a593Smuzhiyun {
2177*4882a593Smuzhiyun struct list_head *ptr;
2178*4882a593Smuzhiyun struct islpci_bss_wpa_ie *bss = NULL;
2179*4882a593Smuzhiyun size_t len = 0;
2180*4882a593Smuzhiyun
2181*4882a593Smuzhiyun mutex_lock(&priv->wpa_lock);
2182*4882a593Smuzhiyun
2183*4882a593Smuzhiyun list_for_each(ptr, &priv->bss_wpa_list) {
2184*4882a593Smuzhiyun bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
2185*4882a593Smuzhiyun if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
2186*4882a593Smuzhiyun break;
2187*4882a593Smuzhiyun bss = NULL;
2188*4882a593Smuzhiyun }
2189*4882a593Smuzhiyun if (bss) {
2190*4882a593Smuzhiyun len = bss->wpa_ie_len;
2191*4882a593Smuzhiyun memcpy(wpa_ie, bss->wpa_ie, len);
2192*4882a593Smuzhiyun }
2193*4882a593Smuzhiyun mutex_unlock(&priv->wpa_lock);
2194*4882a593Smuzhiyun
2195*4882a593Smuzhiyun return len;
2196*4882a593Smuzhiyun }
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun void
prism54_wpa_bss_ie_init(islpci_private * priv)2199*4882a593Smuzhiyun prism54_wpa_bss_ie_init(islpci_private *priv)
2200*4882a593Smuzhiyun {
2201*4882a593Smuzhiyun INIT_LIST_HEAD(&priv->bss_wpa_list);
2202*4882a593Smuzhiyun mutex_init(&priv->wpa_lock);
2203*4882a593Smuzhiyun }
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun void
prism54_wpa_bss_ie_clean(islpci_private * priv)2206*4882a593Smuzhiyun prism54_wpa_bss_ie_clean(islpci_private *priv)
2207*4882a593Smuzhiyun {
2208*4882a593Smuzhiyun struct islpci_bss_wpa_ie *bss, *n;
2209*4882a593Smuzhiyun
2210*4882a593Smuzhiyun list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) {
2211*4882a593Smuzhiyun kfree(bss);
2212*4882a593Smuzhiyun }
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun
2215*4882a593Smuzhiyun static void
prism54_process_bss_data(islpci_private * priv,u32 oid,u8 * addr,u8 * payload,size_t len)2216*4882a593Smuzhiyun prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
2217*4882a593Smuzhiyun u8 *payload, size_t len)
2218*4882a593Smuzhiyun {
2219*4882a593Smuzhiyun struct ieee80211_beacon_phdr *hdr;
2220*4882a593Smuzhiyun u8 *pos, *end;
2221*4882a593Smuzhiyun
2222*4882a593Smuzhiyun if (!priv->wpa)
2223*4882a593Smuzhiyun return;
2224*4882a593Smuzhiyun
2225*4882a593Smuzhiyun hdr = (struct ieee80211_beacon_phdr *) payload;
2226*4882a593Smuzhiyun pos = (u8 *) (hdr + 1);
2227*4882a593Smuzhiyun end = payload + len;
2228*4882a593Smuzhiyun while (pos < end) {
2229*4882a593Smuzhiyun if (pos + 2 + pos[1] > end) {
2230*4882a593Smuzhiyun printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
2231*4882a593Smuzhiyun "for %pM\n", addr);
2232*4882a593Smuzhiyun return;
2233*4882a593Smuzhiyun }
2234*4882a593Smuzhiyun if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
2235*4882a593Smuzhiyun memcmp(pos + 2, wpa_oid, 4) == 0) {
2236*4882a593Smuzhiyun prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
2237*4882a593Smuzhiyun return;
2238*4882a593Smuzhiyun }
2239*4882a593Smuzhiyun pos += 2 + pos[1];
2240*4882a593Smuzhiyun }
2241*4882a593Smuzhiyun }
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun static void
handle_request(islpci_private * priv,struct obj_mlme * mlme,enum oid_num_t oid)2244*4882a593Smuzhiyun handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid)
2245*4882a593Smuzhiyun {
2246*4882a593Smuzhiyun if (((mlme->state == DOT11_STATE_AUTHING) ||
2247*4882a593Smuzhiyun (mlme->state == DOT11_STATE_ASSOCING))
2248*4882a593Smuzhiyun && mgt_mlme_answer(priv)) {
2249*4882a593Smuzhiyun /* Someone is requesting auth and we must respond. Just send back
2250*4882a593Smuzhiyun * the trap with error code set accordingly.
2251*4882a593Smuzhiyun */
2252*4882a593Smuzhiyun mlme->code = prism54_mac_accept(&priv->acl,
2253*4882a593Smuzhiyun mlme->address) ? 0 : 1;
2254*4882a593Smuzhiyun mgt_set_request(priv, oid, 0, mlme);
2255*4882a593Smuzhiyun }
2256*4882a593Smuzhiyun }
2257*4882a593Smuzhiyun
2258*4882a593Smuzhiyun static int
prism54_process_trap_helper(islpci_private * priv,enum oid_num_t oid,char * data)2259*4882a593Smuzhiyun prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
2260*4882a593Smuzhiyun char *data)
2261*4882a593Smuzhiyun {
2262*4882a593Smuzhiyun struct obj_mlme *mlme = (struct obj_mlme *) data;
2263*4882a593Smuzhiyun struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
2264*4882a593Smuzhiyun struct obj_mlmeex *confirm;
2265*4882a593Smuzhiyun u8 wpa_ie[MAX_WPA_IE_LEN];
2266*4882a593Smuzhiyun int wpa_ie_len;
2267*4882a593Smuzhiyun size_t len = 0; /* u16, better? */
2268*4882a593Smuzhiyun u8 *payload = NULL, *pos = NULL;
2269*4882a593Smuzhiyun int ret;
2270*4882a593Smuzhiyun
2271*4882a593Smuzhiyun /* I think all trapable objects are listed here.
2272*4882a593Smuzhiyun * Some oids have a EX version. The difference is that they are emitted
2273*4882a593Smuzhiyun * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL)
2274*4882a593Smuzhiyun * with more info.
2275*4882a593Smuzhiyun * The few events already defined by the wireless tools are not really
2276*4882a593Smuzhiyun * suited. We use the more flexible custom event facility.
2277*4882a593Smuzhiyun */
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun if (oid >= DOT11_OID_BEACON) {
2280*4882a593Smuzhiyun len = mlmeex->size;
2281*4882a593Smuzhiyun payload = pos = mlmeex->data;
2282*4882a593Smuzhiyun }
2283*4882a593Smuzhiyun
2284*4882a593Smuzhiyun /* I fear prism54_process_bss_data won't work with big endian data */
2285*4882a593Smuzhiyun if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
2286*4882a593Smuzhiyun prism54_process_bss_data(priv, oid, mlmeex->address,
2287*4882a593Smuzhiyun payload, len);
2288*4882a593Smuzhiyun
2289*4882a593Smuzhiyun mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
2290*4882a593Smuzhiyun
2291*4882a593Smuzhiyun switch (oid) {
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun case GEN_OID_LINKSTATE:
2294*4882a593Smuzhiyun link_changed(priv->ndev, (u32) *data);
2295*4882a593Smuzhiyun break;
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun case DOT11_OID_MICFAILURE:
2298*4882a593Smuzhiyun send_simple_event(priv, "Mic failure");
2299*4882a593Smuzhiyun break;
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun case DOT11_OID_DEAUTHENTICATE:
2302*4882a593Smuzhiyun send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
2303*4882a593Smuzhiyun break;
2304*4882a593Smuzhiyun
2305*4882a593Smuzhiyun case DOT11_OID_AUTHENTICATE:
2306*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2307*4882a593Smuzhiyun send_formatted_event(priv, "Authenticate request", mlme, 1);
2308*4882a593Smuzhiyun break;
2309*4882a593Smuzhiyun
2310*4882a593Smuzhiyun case DOT11_OID_DISASSOCIATE:
2311*4882a593Smuzhiyun send_formatted_event(priv, "Disassociate request", mlme, 0);
2312*4882a593Smuzhiyun break;
2313*4882a593Smuzhiyun
2314*4882a593Smuzhiyun case DOT11_OID_ASSOCIATE:
2315*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2316*4882a593Smuzhiyun send_formatted_event(priv, "Associate request", mlme, 1);
2317*4882a593Smuzhiyun break;
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun case DOT11_OID_REASSOCIATE:
2320*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2321*4882a593Smuzhiyun send_formatted_event(priv, "ReAssociate request", mlme, 1);
2322*4882a593Smuzhiyun break;
2323*4882a593Smuzhiyun
2324*4882a593Smuzhiyun case DOT11_OID_BEACON:
2325*4882a593Smuzhiyun send_formatted_event(priv,
2326*4882a593Smuzhiyun "Received a beacon from an unknown AP",
2327*4882a593Smuzhiyun mlme, 0);
2328*4882a593Smuzhiyun break;
2329*4882a593Smuzhiyun
2330*4882a593Smuzhiyun case DOT11_OID_PROBE:
2331*4882a593Smuzhiyun /* we received a probe from a client. */
2332*4882a593Smuzhiyun send_formatted_event(priv, "Received a probe from client", mlme,
2333*4882a593Smuzhiyun 0);
2334*4882a593Smuzhiyun break;
2335*4882a593Smuzhiyun
2336*4882a593Smuzhiyun /* Note : "mlme" is actually a "struct obj_mlmeex *" here, but this
2337*4882a593Smuzhiyun * is backward compatible layout-wise with "struct obj_mlme".
2338*4882a593Smuzhiyun */
2339*4882a593Smuzhiyun
2340*4882a593Smuzhiyun case DOT11_OID_DEAUTHENTICATEEX:
2341*4882a593Smuzhiyun send_formatted_event(priv, "DeAuthenticate request", mlme, 0);
2342*4882a593Smuzhiyun break;
2343*4882a593Smuzhiyun
2344*4882a593Smuzhiyun case DOT11_OID_AUTHENTICATEEX:
2345*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2346*4882a593Smuzhiyun send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun if (priv->iw_mode != IW_MODE_MASTER
2349*4882a593Smuzhiyun && mlmeex->state != DOT11_STATE_AUTHING)
2350*4882a593Smuzhiyun break;
2351*4882a593Smuzhiyun
2352*4882a593Smuzhiyun confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun if (!confirm)
2355*4882a593Smuzhiyun break;
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyun memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2358*4882a593Smuzhiyun printk(KERN_DEBUG "Authenticate from: address:\t%pM\n",
2359*4882a593Smuzhiyun mlmeex->address);
2360*4882a593Smuzhiyun confirm->id = -1; /* or mlmeex->id ? */
2361*4882a593Smuzhiyun confirm->state = 0; /* not used */
2362*4882a593Smuzhiyun confirm->code = 0;
2363*4882a593Smuzhiyun confirm->size = 6;
2364*4882a593Smuzhiyun confirm->data[0] = 0x00;
2365*4882a593Smuzhiyun confirm->data[1] = 0x00;
2366*4882a593Smuzhiyun confirm->data[2] = 0x02;
2367*4882a593Smuzhiyun confirm->data[3] = 0x00;
2368*4882a593Smuzhiyun confirm->data[4] = 0x00;
2369*4882a593Smuzhiyun confirm->data[5] = 0x00;
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
2372*4882a593Smuzhiyun
2373*4882a593Smuzhiyun kfree(confirm);
2374*4882a593Smuzhiyun if (ret)
2375*4882a593Smuzhiyun return ret;
2376*4882a593Smuzhiyun break;
2377*4882a593Smuzhiyun
2378*4882a593Smuzhiyun case DOT11_OID_DISASSOCIATEEX:
2379*4882a593Smuzhiyun send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
2380*4882a593Smuzhiyun break;
2381*4882a593Smuzhiyun
2382*4882a593Smuzhiyun case DOT11_OID_ASSOCIATEEX:
2383*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2384*4882a593Smuzhiyun send_formatted_event(priv, "Associate request (ex)", mlme, 1);
2385*4882a593Smuzhiyun
2386*4882a593Smuzhiyun if (priv->iw_mode != IW_MODE_MASTER
2387*4882a593Smuzhiyun && mlmeex->state != DOT11_STATE_ASSOCING)
2388*4882a593Smuzhiyun break;
2389*4882a593Smuzhiyun
2390*4882a593Smuzhiyun confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
2391*4882a593Smuzhiyun
2392*4882a593Smuzhiyun if (!confirm)
2393*4882a593Smuzhiyun break;
2394*4882a593Smuzhiyun
2395*4882a593Smuzhiyun memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2396*4882a593Smuzhiyun
2397*4882a593Smuzhiyun confirm->id = ((struct obj_mlmeex *)mlme)->id;
2398*4882a593Smuzhiyun confirm->state = 0; /* not used */
2399*4882a593Smuzhiyun confirm->code = 0;
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
2402*4882a593Smuzhiyun
2403*4882a593Smuzhiyun if (!wpa_ie_len) {
2404*4882a593Smuzhiyun printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
2405*4882a593Smuzhiyun mlmeex->address);
2406*4882a593Smuzhiyun kfree(confirm);
2407*4882a593Smuzhiyun break;
2408*4882a593Smuzhiyun }
2409*4882a593Smuzhiyun
2410*4882a593Smuzhiyun confirm->size = wpa_ie_len;
2411*4882a593Smuzhiyun memcpy(&confirm->data, wpa_ie, wpa_ie_len);
2412*4882a593Smuzhiyun
2413*4882a593Smuzhiyun mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
2414*4882a593Smuzhiyun
2415*4882a593Smuzhiyun kfree(confirm);
2416*4882a593Smuzhiyun
2417*4882a593Smuzhiyun break;
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun case DOT11_OID_REASSOCIATEEX:
2420*4882a593Smuzhiyun handle_request(priv, mlme, oid);
2421*4882a593Smuzhiyun send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
2422*4882a593Smuzhiyun
2423*4882a593Smuzhiyun if (priv->iw_mode != IW_MODE_MASTER
2424*4882a593Smuzhiyun && mlmeex->state != DOT11_STATE_ASSOCING)
2425*4882a593Smuzhiyun break;
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
2428*4882a593Smuzhiyun
2429*4882a593Smuzhiyun if (!confirm)
2430*4882a593Smuzhiyun break;
2431*4882a593Smuzhiyun
2432*4882a593Smuzhiyun memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
2433*4882a593Smuzhiyun
2434*4882a593Smuzhiyun confirm->id = mlmeex->id;
2435*4882a593Smuzhiyun confirm->state = 0; /* not used */
2436*4882a593Smuzhiyun confirm->code = 0;
2437*4882a593Smuzhiyun
2438*4882a593Smuzhiyun wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun if (!wpa_ie_len) {
2441*4882a593Smuzhiyun printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n",
2442*4882a593Smuzhiyun mlmeex->address);
2443*4882a593Smuzhiyun kfree(confirm);
2444*4882a593Smuzhiyun break;
2445*4882a593Smuzhiyun }
2446*4882a593Smuzhiyun
2447*4882a593Smuzhiyun confirm->size = wpa_ie_len;
2448*4882a593Smuzhiyun memcpy(&confirm->data, wpa_ie, wpa_ie_len);
2449*4882a593Smuzhiyun
2450*4882a593Smuzhiyun mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
2451*4882a593Smuzhiyun
2452*4882a593Smuzhiyun kfree(confirm);
2453*4882a593Smuzhiyun
2454*4882a593Smuzhiyun break;
2455*4882a593Smuzhiyun
2456*4882a593Smuzhiyun default:
2457*4882a593Smuzhiyun return -EINVAL;
2458*4882a593Smuzhiyun }
2459*4882a593Smuzhiyun
2460*4882a593Smuzhiyun return 0;
2461*4882a593Smuzhiyun }
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun /*
2464*4882a593Smuzhiyun * Process a device trap. This is called via schedule_work(), outside of
2465*4882a593Smuzhiyun * interrupt context, no locks held.
2466*4882a593Smuzhiyun */
2467*4882a593Smuzhiyun void
prism54_process_trap(struct work_struct * work)2468*4882a593Smuzhiyun prism54_process_trap(struct work_struct *work)
2469*4882a593Smuzhiyun {
2470*4882a593Smuzhiyun struct islpci_mgmtframe *frame =
2471*4882a593Smuzhiyun container_of(work, struct islpci_mgmtframe, ws);
2472*4882a593Smuzhiyun struct net_device *ndev = frame->ndev;
2473*4882a593Smuzhiyun enum oid_num_t n = mgt_oidtonum(frame->header->oid);
2474*4882a593Smuzhiyun
2475*4882a593Smuzhiyun if (n != OID_NUM_LAST)
2476*4882a593Smuzhiyun prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
2477*4882a593Smuzhiyun islpci_mgt_release(frame);
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun
2480*4882a593Smuzhiyun int
prism54_set_mac_address(struct net_device * ndev,void * addr)2481*4882a593Smuzhiyun prism54_set_mac_address(struct net_device *ndev, void *addr)
2482*4882a593Smuzhiyun {
2483*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2484*4882a593Smuzhiyun int ret;
2485*4882a593Smuzhiyun
2486*4882a593Smuzhiyun if (ndev->addr_len != 6)
2487*4882a593Smuzhiyun return -EINVAL;
2488*4882a593Smuzhiyun ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0,
2489*4882a593Smuzhiyun &((struct sockaddr *) addr)->sa_data);
2490*4882a593Smuzhiyun if (!ret)
2491*4882a593Smuzhiyun memcpy(priv->ndev->dev_addr,
2492*4882a593Smuzhiyun &((struct sockaddr *) addr)->sa_data, ETH_ALEN);
2493*4882a593Smuzhiyun
2494*4882a593Smuzhiyun return ret;
2495*4882a593Smuzhiyun }
2496*4882a593Smuzhiyun
2497*4882a593Smuzhiyun #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
2498*4882a593Smuzhiyun
2499*4882a593Smuzhiyun static int
prism54_set_wpa(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)2500*4882a593Smuzhiyun prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
2501*4882a593Smuzhiyun __u32 * uwrq, char *extra)
2502*4882a593Smuzhiyun {
2503*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2504*4882a593Smuzhiyun u32 mlme, authen, dot1x, filter, wep;
2505*4882a593Smuzhiyun
2506*4882a593Smuzhiyun if (islpci_get_state(priv) < PRV_STATE_INIT)
2507*4882a593Smuzhiyun return 0;
2508*4882a593Smuzhiyun
2509*4882a593Smuzhiyun wep = 1; /* For privacy invoked */
2510*4882a593Smuzhiyun filter = 1; /* Filter out all unencrypted frames */
2511*4882a593Smuzhiyun dot1x = 0x01; /* To enable eap filter */
2512*4882a593Smuzhiyun mlme = DOT11_MLME_EXTENDED;
2513*4882a593Smuzhiyun authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
2514*4882a593Smuzhiyun
2515*4882a593Smuzhiyun down_write(&priv->mib_sem);
2516*4882a593Smuzhiyun priv->wpa = *uwrq;
2517*4882a593Smuzhiyun
2518*4882a593Smuzhiyun switch (priv->wpa) {
2519*4882a593Smuzhiyun default:
2520*4882a593Smuzhiyun case 0: /* Clears/disables WPA and friends */
2521*4882a593Smuzhiyun wep = 0;
2522*4882a593Smuzhiyun filter = 0; /* Do not filter un-encrypted data */
2523*4882a593Smuzhiyun dot1x = 0;
2524*4882a593Smuzhiyun mlme = DOT11_MLME_AUTO;
2525*4882a593Smuzhiyun printk("%s: Disabling WPA\n", ndev->name);
2526*4882a593Smuzhiyun break;
2527*4882a593Smuzhiyun case 2:
2528*4882a593Smuzhiyun case 1: /* WPA */
2529*4882a593Smuzhiyun printk("%s: Enabling WPA\n", ndev->name);
2530*4882a593Smuzhiyun break;
2531*4882a593Smuzhiyun }
2532*4882a593Smuzhiyun up_write(&priv->mib_sem);
2533*4882a593Smuzhiyun
2534*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
2535*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
2536*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
2537*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
2538*4882a593Smuzhiyun mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
2539*4882a593Smuzhiyun
2540*4882a593Smuzhiyun return 0;
2541*4882a593Smuzhiyun }
2542*4882a593Smuzhiyun
2543*4882a593Smuzhiyun static int
prism54_get_wpa(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)2544*4882a593Smuzhiyun prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
2545*4882a593Smuzhiyun __u32 * uwrq, char *extra)
2546*4882a593Smuzhiyun {
2547*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2548*4882a593Smuzhiyun *uwrq = priv->wpa;
2549*4882a593Smuzhiyun return 0;
2550*4882a593Smuzhiyun }
2551*4882a593Smuzhiyun
2552*4882a593Smuzhiyun static int
prism54_set_prismhdr(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)2553*4882a593Smuzhiyun prism54_set_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2554*4882a593Smuzhiyun __u32 * uwrq, char *extra)
2555*4882a593Smuzhiyun {
2556*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2557*4882a593Smuzhiyun priv->monitor_type =
2558*4882a593Smuzhiyun (*uwrq ? ARPHRD_IEEE80211_PRISM : ARPHRD_IEEE80211);
2559*4882a593Smuzhiyun if (priv->iw_mode == IW_MODE_MONITOR)
2560*4882a593Smuzhiyun priv->ndev->type = priv->monitor_type;
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun return 0;
2563*4882a593Smuzhiyun }
2564*4882a593Smuzhiyun
2565*4882a593Smuzhiyun static int
prism54_get_prismhdr(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)2566*4882a593Smuzhiyun prism54_get_prismhdr(struct net_device *ndev, struct iw_request_info *info,
2567*4882a593Smuzhiyun __u32 * uwrq, char *extra)
2568*4882a593Smuzhiyun {
2569*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2570*4882a593Smuzhiyun *uwrq = (priv->monitor_type == ARPHRD_IEEE80211_PRISM);
2571*4882a593Smuzhiyun return 0;
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun
2574*4882a593Smuzhiyun static int
prism54_debug_oid(struct net_device * ndev,struct iw_request_info * info,__u32 * uwrq,char * extra)2575*4882a593Smuzhiyun prism54_debug_oid(struct net_device *ndev, struct iw_request_info *info,
2576*4882a593Smuzhiyun __u32 * uwrq, char *extra)
2577*4882a593Smuzhiyun {
2578*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2579*4882a593Smuzhiyun
2580*4882a593Smuzhiyun priv->priv_oid = *uwrq;
2581*4882a593Smuzhiyun printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
2582*4882a593Smuzhiyun
2583*4882a593Smuzhiyun return 0;
2584*4882a593Smuzhiyun }
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun static int
prism54_debug_get_oid(struct net_device * ndev,struct iw_request_info * info,struct iw_point * data,char * extra)2587*4882a593Smuzhiyun prism54_debug_get_oid(struct net_device *ndev, struct iw_request_info *info,
2588*4882a593Smuzhiyun struct iw_point *data, char *extra)
2589*4882a593Smuzhiyun {
2590*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2591*4882a593Smuzhiyun struct islpci_mgmtframe *response;
2592*4882a593Smuzhiyun int ret = -EIO;
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
2595*4882a593Smuzhiyun data->length = 0;
2596*4882a593Smuzhiyun
2597*4882a593Smuzhiyun if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2598*4882a593Smuzhiyun ret =
2599*4882a593Smuzhiyun islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
2600*4882a593Smuzhiyun priv->priv_oid, extra, 256,
2601*4882a593Smuzhiyun &response);
2602*4882a593Smuzhiyun printk("%s: ret: %i\n", ndev->name, ret);
2603*4882a593Smuzhiyun if (ret || !response
2604*4882a593Smuzhiyun || response->header->operation == PIMFOR_OP_ERROR) {
2605*4882a593Smuzhiyun if (response) {
2606*4882a593Smuzhiyun islpci_mgt_release(response);
2607*4882a593Smuzhiyun }
2608*4882a593Smuzhiyun printk("%s: EIO\n", ndev->name);
2609*4882a593Smuzhiyun ret = -EIO;
2610*4882a593Smuzhiyun }
2611*4882a593Smuzhiyun if (!ret) {
2612*4882a593Smuzhiyun data->length = response->header->length;
2613*4882a593Smuzhiyun memcpy(extra, response->data, data->length);
2614*4882a593Smuzhiyun islpci_mgt_release(response);
2615*4882a593Smuzhiyun printk("%s: len: %i\n", ndev->name, data->length);
2616*4882a593Smuzhiyun }
2617*4882a593Smuzhiyun }
2618*4882a593Smuzhiyun
2619*4882a593Smuzhiyun return ret;
2620*4882a593Smuzhiyun }
2621*4882a593Smuzhiyun
2622*4882a593Smuzhiyun static int
prism54_debug_set_oid(struct net_device * ndev,struct iw_request_info * info,struct iw_point * data,char * extra)2623*4882a593Smuzhiyun prism54_debug_set_oid(struct net_device *ndev, struct iw_request_info *info,
2624*4882a593Smuzhiyun struct iw_point *data, char *extra)
2625*4882a593Smuzhiyun {
2626*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2627*4882a593Smuzhiyun struct islpci_mgmtframe *response;
2628*4882a593Smuzhiyun int ret = 0, response_op = PIMFOR_OP_ERROR;
2629*4882a593Smuzhiyun
2630*4882a593Smuzhiyun printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
2631*4882a593Smuzhiyun data->length);
2632*4882a593Smuzhiyun
2633*4882a593Smuzhiyun if (islpci_get_state(priv) >= PRV_STATE_INIT) {
2634*4882a593Smuzhiyun ret =
2635*4882a593Smuzhiyun islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
2636*4882a593Smuzhiyun priv->priv_oid, extra, data->length,
2637*4882a593Smuzhiyun &response);
2638*4882a593Smuzhiyun printk("%s: ret: %i\n", ndev->name, ret);
2639*4882a593Smuzhiyun if (ret || !response
2640*4882a593Smuzhiyun || response->header->operation == PIMFOR_OP_ERROR) {
2641*4882a593Smuzhiyun if (response) {
2642*4882a593Smuzhiyun islpci_mgt_release(response);
2643*4882a593Smuzhiyun }
2644*4882a593Smuzhiyun printk("%s: EIO\n", ndev->name);
2645*4882a593Smuzhiyun ret = -EIO;
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun if (!ret) {
2648*4882a593Smuzhiyun response_op = response->header->operation;
2649*4882a593Smuzhiyun printk("%s: response_op: %i\n", ndev->name,
2650*4882a593Smuzhiyun response_op);
2651*4882a593Smuzhiyun islpci_mgt_release(response);
2652*4882a593Smuzhiyun }
2653*4882a593Smuzhiyun }
2654*4882a593Smuzhiyun
2655*4882a593Smuzhiyun return (ret ? ret : -EINPROGRESS);
2656*4882a593Smuzhiyun }
2657*4882a593Smuzhiyun
2658*4882a593Smuzhiyun static int
prism54_set_spy(struct net_device * ndev,struct iw_request_info * info,union iwreq_data * uwrq,char * extra)2659*4882a593Smuzhiyun prism54_set_spy(struct net_device *ndev,
2660*4882a593Smuzhiyun struct iw_request_info *info,
2661*4882a593Smuzhiyun union iwreq_data *uwrq, char *extra)
2662*4882a593Smuzhiyun {
2663*4882a593Smuzhiyun islpci_private *priv = netdev_priv(ndev);
2664*4882a593Smuzhiyun u32 u;
2665*4882a593Smuzhiyun enum oid_num_t oid = OID_INL_CONFIG;
2666*4882a593Smuzhiyun
2667*4882a593Smuzhiyun down_write(&priv->mib_sem);
2668*4882a593Smuzhiyun mgt_get(priv, OID_INL_CONFIG, &u);
2669*4882a593Smuzhiyun
2670*4882a593Smuzhiyun if ((uwrq->data.length == 0) && (priv->spy_data.spy_number > 0))
2671*4882a593Smuzhiyun /* disable spy */
2672*4882a593Smuzhiyun u &= ~INL_CONFIG_RXANNEX;
2673*4882a593Smuzhiyun else if ((uwrq->data.length > 0) && (priv->spy_data.spy_number == 0))
2674*4882a593Smuzhiyun /* enable spy */
2675*4882a593Smuzhiyun u |= INL_CONFIG_RXANNEX;
2676*4882a593Smuzhiyun
2677*4882a593Smuzhiyun mgt_set(priv, OID_INL_CONFIG, &u);
2678*4882a593Smuzhiyun mgt_commit_list(priv, &oid, 1);
2679*4882a593Smuzhiyun up_write(&priv->mib_sem);
2680*4882a593Smuzhiyun
2681*4882a593Smuzhiyun return iw_handler_set_spy(ndev, info, uwrq, extra);
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun
2684*4882a593Smuzhiyun static const iw_handler prism54_handler[] = {
2685*4882a593Smuzhiyun (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */
2686*4882a593Smuzhiyun (iw_handler) prism54_get_name, /* SIOCGIWNAME */
2687*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCSIWNWID */
2688*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCGIWNWID */
2689*4882a593Smuzhiyun (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */
2690*4882a593Smuzhiyun (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */
2691*4882a593Smuzhiyun (iw_handler) prism54_set_mode, /* SIOCSIWMODE */
2692*4882a593Smuzhiyun (iw_handler) prism54_get_mode, /* SIOCGIWMODE */
2693*4882a593Smuzhiyun (iw_handler) prism54_set_sens, /* SIOCSIWSENS */
2694*4882a593Smuzhiyun (iw_handler) prism54_get_sens, /* SIOCGIWSENS */
2695*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCSIWRANGE */
2696*4882a593Smuzhiyun (iw_handler) prism54_get_range, /* SIOCGIWRANGE */
2697*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCSIWPRIV */
2698*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCGIWPRIV */
2699*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCSIWSTATS */
2700*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCGIWSTATS */
2701*4882a593Smuzhiyun prism54_set_spy, /* SIOCSIWSPY */
2702*4882a593Smuzhiyun iw_handler_get_spy, /* SIOCGIWSPY */
2703*4882a593Smuzhiyun iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
2704*4882a593Smuzhiyun iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
2705*4882a593Smuzhiyun (iw_handler) prism54_set_wap, /* SIOCSIWAP */
2706*4882a593Smuzhiyun (iw_handler) prism54_get_wap, /* SIOCGIWAP */
2707*4882a593Smuzhiyun (iw_handler) NULL, /* -- hole -- */
2708*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */
2709*4882a593Smuzhiyun (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */
2710*4882a593Smuzhiyun (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */
2711*4882a593Smuzhiyun (iw_handler) prism54_set_essid, /* SIOCSIWESSID */
2712*4882a593Smuzhiyun (iw_handler) prism54_get_essid, /* SIOCGIWESSID */
2713*4882a593Smuzhiyun (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */
2714*4882a593Smuzhiyun (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */
2715*4882a593Smuzhiyun (iw_handler) NULL, /* -- hole -- */
2716*4882a593Smuzhiyun (iw_handler) NULL, /* -- hole -- */
2717*4882a593Smuzhiyun (iw_handler) prism54_set_rate, /* SIOCSIWRATE */
2718*4882a593Smuzhiyun (iw_handler) prism54_get_rate, /* SIOCGIWRATE */
2719*4882a593Smuzhiyun (iw_handler) prism54_set_rts, /* SIOCSIWRTS */
2720*4882a593Smuzhiyun (iw_handler) prism54_get_rts, /* SIOCGIWRTS */
2721*4882a593Smuzhiyun (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */
2722*4882a593Smuzhiyun (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */
2723*4882a593Smuzhiyun (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */
2724*4882a593Smuzhiyun (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */
2725*4882a593Smuzhiyun (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */
2726*4882a593Smuzhiyun (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */
2727*4882a593Smuzhiyun (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */
2728*4882a593Smuzhiyun (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
2729*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCSIWPOWER */
2730*4882a593Smuzhiyun (iw_handler) NULL, /* SIOCGIWPOWER */
2731*4882a593Smuzhiyun NULL, /* -- hole -- */
2732*4882a593Smuzhiyun NULL, /* -- hole -- */
2733*4882a593Smuzhiyun (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
2734*4882a593Smuzhiyun (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
2735*4882a593Smuzhiyun (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */
2736*4882a593Smuzhiyun (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */
2737*4882a593Smuzhiyun (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
2738*4882a593Smuzhiyun (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
2739*4882a593Smuzhiyun NULL, /* SIOCSIWPMKSA */
2740*4882a593Smuzhiyun };
2741*4882a593Smuzhiyun
2742*4882a593Smuzhiyun /* The low order bit identify a SET (0) or a GET (1) ioctl. */
2743*4882a593Smuzhiyun
2744*4882a593Smuzhiyun #define PRISM54_RESET SIOCIWFIRSTPRIV
2745*4882a593Smuzhiyun #define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+1
2746*4882a593Smuzhiyun #define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+2
2747*4882a593Smuzhiyun #define PRISM54_GET_MAC SIOCIWFIRSTPRIV+3
2748*4882a593Smuzhiyun #define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+4
2749*4882a593Smuzhiyun
2750*4882a593Smuzhiyun #define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+6
2751*4882a593Smuzhiyun
2752*4882a593Smuzhiyun #define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+8
2753*4882a593Smuzhiyun
2754*4882a593Smuzhiyun #define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+10
2755*4882a593Smuzhiyun
2756*4882a593Smuzhiyun #define PRISM54_GET_WPA SIOCIWFIRSTPRIV+11
2757*4882a593Smuzhiyun #define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
2758*4882a593Smuzhiyun
2759*4882a593Smuzhiyun #define PRISM54_DBG_OID SIOCIWFIRSTPRIV+14
2760*4882a593Smuzhiyun #define PRISM54_DBG_GET_OID SIOCIWFIRSTPRIV+15
2761*4882a593Smuzhiyun #define PRISM54_DBG_SET_OID SIOCIWFIRSTPRIV+16
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun #define PRISM54_GET_OID SIOCIWFIRSTPRIV+17
2764*4882a593Smuzhiyun #define PRISM54_SET_OID_U32 SIOCIWFIRSTPRIV+18
2765*4882a593Smuzhiyun #define PRISM54_SET_OID_STR SIOCIWFIRSTPRIV+20
2766*4882a593Smuzhiyun #define PRISM54_SET_OID_ADDR SIOCIWFIRSTPRIV+22
2767*4882a593Smuzhiyun
2768*4882a593Smuzhiyun #define PRISM54_GET_PRISMHDR SIOCIWFIRSTPRIV+23
2769*4882a593Smuzhiyun #define PRISM54_SET_PRISMHDR SIOCIWFIRSTPRIV+24
2770*4882a593Smuzhiyun
2771*4882a593Smuzhiyun #define IWPRIV_SET_U32(n,x) { n, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2772*4882a593Smuzhiyun #define IWPRIV_SET_SSID(n,x) { n, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2773*4882a593Smuzhiyun #define IWPRIV_SET_ADDR(n,x) { n, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "s_"x }
2774*4882a593Smuzhiyun #define IWPRIV_GET(n,x) { n, 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, "g_"x }
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun #define IWPRIV_U32(n,x) IWPRIV_SET_U32(n,x), IWPRIV_GET(n,x)
2777*4882a593Smuzhiyun #define IWPRIV_SSID(n,x) IWPRIV_SET_SSID(n,x), IWPRIV_GET(n,x)
2778*4882a593Smuzhiyun #define IWPRIV_ADDR(n,x) IWPRIV_SET_ADDR(n,x), IWPRIV_GET(n,x)
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun /* Note : limited to 128 private ioctls (wireless tools 26) */
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun static const struct iw_priv_args prism54_private_args[] = {
2783*4882a593Smuzhiyun /*{ cmd, set_args, get_args, name } */
2784*4882a593Smuzhiyun {PRISM54_RESET, 0, 0, "reset"},
2785*4882a593Smuzhiyun {PRISM54_GET_PRISMHDR, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2786*4882a593Smuzhiyun "get_prismhdr"},
2787*4882a593Smuzhiyun {PRISM54_SET_PRISMHDR, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2788*4882a593Smuzhiyun "set_prismhdr"},
2789*4882a593Smuzhiyun {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2790*4882a593Smuzhiyun "getPolicy"},
2791*4882a593Smuzhiyun {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2792*4882a593Smuzhiyun "setPolicy"},
2793*4882a593Smuzhiyun {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"},
2794*4882a593Smuzhiyun {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2795*4882a593Smuzhiyun "addMac"},
2796*4882a593Smuzhiyun {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2797*4882a593Smuzhiyun "delMac"},
2798*4882a593Smuzhiyun {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,
2799*4882a593Smuzhiyun "kickMac"},
2800*4882a593Smuzhiyun {PRISM54_KICK_ALL, 0, 0, "kickAll"},
2801*4882a593Smuzhiyun {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2802*4882a593Smuzhiyun "get_wpa"},
2803*4882a593Smuzhiyun {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2804*4882a593Smuzhiyun "set_wpa"},
2805*4882a593Smuzhiyun {PRISM54_DBG_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0,
2806*4882a593Smuzhiyun "dbg_oid"},
2807*4882a593Smuzhiyun {PRISM54_DBG_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "dbg_get_oid"},
2808*4882a593Smuzhiyun {PRISM54_DBG_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "dbg_set_oid"},
2809*4882a593Smuzhiyun /* --- sub-ioctls handlers --- */
2810*4882a593Smuzhiyun {PRISM54_GET_OID,
2811*4882a593Smuzhiyun 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | PRIV_STR_SIZE, ""},
2812*4882a593Smuzhiyun {PRISM54_SET_OID_U32,
2813*4882a593Smuzhiyun IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2814*4882a593Smuzhiyun {PRISM54_SET_OID_STR,
2815*4882a593Smuzhiyun IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2816*4882a593Smuzhiyun {PRISM54_SET_OID_ADDR,
2817*4882a593Smuzhiyun IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, ""},
2818*4882a593Smuzhiyun /* --- sub-ioctls definitions --- */
2819*4882a593Smuzhiyun IWPRIV_ADDR(GEN_OID_MACADDRESS, "addr"),
2820*4882a593Smuzhiyun IWPRIV_GET(GEN_OID_LINKSTATE, "linkstate"),
2821*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_BSSTYPE, "bsstype"),
2822*4882a593Smuzhiyun IWPRIV_ADDR(DOT11_OID_BSSID, "bssid"),
2823*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_STATE, "state"),
2824*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_AID, "aid"),
2825*4882a593Smuzhiyun
2826*4882a593Smuzhiyun IWPRIV_SSID(DOT11_OID_SSIDOVERRIDE, "ssidoverride"),
2827*4882a593Smuzhiyun
2828*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_MEDIUMLIMIT, "medlimit"),
2829*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_BEACONPERIOD, "beacon"),
2830*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_DTIMPERIOD, "dtimperiod"),
2831*4882a593Smuzhiyun
2832*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_AUTHENABLE, "authenable"),
2833*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_PRIVACYINVOKED, "privinvok"),
2834*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_EXUNENCRYPTED, "exunencrypt"),
2835*4882a593Smuzhiyun
2836*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_REKEYTHRESHOLD, "rekeythresh"),
2837*4882a593Smuzhiyun
2838*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_MAXTXLIFETIME, "maxtxlife"),
2839*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_MAXRXLIFETIME, "maxrxlife"),
2840*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_ALOFT_FIXEDRATE, "fixedrate"),
2841*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_MAXFRAMEBURST, "frameburst"),
2842*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_PSM, "psm"),
2843*4882a593Smuzhiyun
2844*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_BRIDGELOCAL, "bridge"),
2845*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_CLIENTS, "clients"),
2846*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_CLIENTSASSOCIATED, "clientassoc"),
2847*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_DOT1XENABLE, "dot1xenable"),
2848*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_ANTENNARX, "rxant"),
2849*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_ANTENNATX, "txant"),
2850*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_ANTENNADIVERSITY, "antdivers"),
2851*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_EDTHRESHOLD, "edthresh"),
2852*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_PREAMBLESETTINGS, "preamble"),
2853*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_RATES, "rates"),
2854*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_OUTPUTPOWER, ".11outpower"),
2855*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_SUPPORTEDRATES, "supprates"),
2856*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_SUPPORTEDFREQUENCIES, "suppfreq"),
2857*4882a593Smuzhiyun
2858*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_NOISEFLOOR, "noisefloor"),
2859*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_FREQUENCYACTIVITY, "freqactivity"),
2860*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_NONERPPROTECTION, "nonerpprotec"),
2861*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_PROFILES, "profile"),
2862*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_EXTENDEDRATES, "extrates"),
2863*4882a593Smuzhiyun IWPRIV_U32(DOT11_OID_MLMEAUTOLEVEL, "mlmelevel"),
2864*4882a593Smuzhiyun
2865*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_BSSS, "bsss"),
2866*4882a593Smuzhiyun IWPRIV_GET(DOT11_OID_BSSLIST, "bsslist"),
2867*4882a593Smuzhiyun IWPRIV_U32(OID_INL_MODE, "mode"),
2868*4882a593Smuzhiyun IWPRIV_U32(OID_INL_CONFIG, "config"),
2869*4882a593Smuzhiyun IWPRIV_U32(OID_INL_DOT11D_CONFORMANCE, ".11dconform"),
2870*4882a593Smuzhiyun IWPRIV_GET(OID_INL_PHYCAPABILITIES, "phycapa"),
2871*4882a593Smuzhiyun IWPRIV_U32(OID_INL_OUTPUTPOWER, "outpower"),
2872*4882a593Smuzhiyun };
2873*4882a593Smuzhiyun
2874*4882a593Smuzhiyun static const iw_handler prism54_private_handler[] = {
2875*4882a593Smuzhiyun (iw_handler) prism54_reset,
2876*4882a593Smuzhiyun (iw_handler) prism54_get_policy,
2877*4882a593Smuzhiyun (iw_handler) prism54_set_policy,
2878*4882a593Smuzhiyun (iw_handler) prism54_get_mac,
2879*4882a593Smuzhiyun (iw_handler) prism54_add_mac,
2880*4882a593Smuzhiyun (iw_handler) NULL,
2881*4882a593Smuzhiyun (iw_handler) prism54_del_mac,
2882*4882a593Smuzhiyun (iw_handler) NULL,
2883*4882a593Smuzhiyun (iw_handler) prism54_kick_mac,
2884*4882a593Smuzhiyun (iw_handler) NULL,
2885*4882a593Smuzhiyun (iw_handler) prism54_kick_all,
2886*4882a593Smuzhiyun (iw_handler) prism54_get_wpa,
2887*4882a593Smuzhiyun (iw_handler) prism54_set_wpa,
2888*4882a593Smuzhiyun (iw_handler) NULL,
2889*4882a593Smuzhiyun (iw_handler) prism54_debug_oid,
2890*4882a593Smuzhiyun (iw_handler) prism54_debug_get_oid,
2891*4882a593Smuzhiyun (iw_handler) prism54_debug_set_oid,
2892*4882a593Smuzhiyun (iw_handler) prism54_get_oid,
2893*4882a593Smuzhiyun (iw_handler) prism54_set_u32,
2894*4882a593Smuzhiyun (iw_handler) NULL,
2895*4882a593Smuzhiyun (iw_handler) prism54_set_raw,
2896*4882a593Smuzhiyun (iw_handler) NULL,
2897*4882a593Smuzhiyun (iw_handler) prism54_set_raw,
2898*4882a593Smuzhiyun (iw_handler) prism54_get_prismhdr,
2899*4882a593Smuzhiyun (iw_handler) prism54_set_prismhdr,
2900*4882a593Smuzhiyun };
2901*4882a593Smuzhiyun
2902*4882a593Smuzhiyun const struct iw_handler_def prism54_handler_def = {
2903*4882a593Smuzhiyun .num_standard = ARRAY_SIZE(prism54_handler),
2904*4882a593Smuzhiyun .num_private = ARRAY_SIZE(prism54_private_handler),
2905*4882a593Smuzhiyun .num_private_args = ARRAY_SIZE(prism54_private_args),
2906*4882a593Smuzhiyun .standard = (iw_handler *) prism54_handler,
2907*4882a593Smuzhiyun .private = (iw_handler *) prism54_private_handler,
2908*4882a593Smuzhiyun .private_args = (struct iw_priv_args *) prism54_private_args,
2909*4882a593Smuzhiyun .get_wireless_stats = prism54_get_wireless_stats,
2910*4882a593Smuzhiyun };
2911