1*4882a593Smuzhiyun /* Wireless extensions support.
2*4882a593Smuzhiyun *
3*4882a593Smuzhiyun * See copyright notice in main.c
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun #include <linux/slab.h>
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/if_arp.h>
8*4882a593Smuzhiyun #include <linux/wireless.h>
9*4882a593Smuzhiyun #include <linux/ieee80211.h>
10*4882a593Smuzhiyun #include <linux/etherdevice.h>
11*4882a593Smuzhiyun #include <net/iw_handler.h>
12*4882a593Smuzhiyun #include <net/cfg80211.h>
13*4882a593Smuzhiyun #include <net/cfg80211-wext.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include "hermes.h"
16*4882a593Smuzhiyun #include "hermes_rid.h"
17*4882a593Smuzhiyun #include "orinoco.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "hw.h"
20*4882a593Smuzhiyun #include "mic.h"
21*4882a593Smuzhiyun #include "scan.h"
22*4882a593Smuzhiyun #include "main.h"
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include "wext.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define MAX_RID_LEN 1024
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* Helper routine to record keys
29*4882a593Smuzhiyun * It is called under orinoco_lock so it may not sleep */
orinoco_set_key(struct orinoco_private * priv,int index,enum orinoco_alg alg,const u8 * key,int key_len,const u8 * seq,int seq_len)30*4882a593Smuzhiyun static int orinoco_set_key(struct orinoco_private *priv, int index,
31*4882a593Smuzhiyun enum orinoco_alg alg, const u8 *key, int key_len,
32*4882a593Smuzhiyun const u8 *seq, int seq_len)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun kfree_sensitive(priv->keys[index].key);
35*4882a593Smuzhiyun kfree_sensitive(priv->keys[index].seq);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun if (key_len) {
38*4882a593Smuzhiyun priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
39*4882a593Smuzhiyun if (!priv->keys[index].key)
40*4882a593Smuzhiyun goto nomem;
41*4882a593Smuzhiyun } else
42*4882a593Smuzhiyun priv->keys[index].key = NULL;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun if (seq_len) {
45*4882a593Smuzhiyun priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
46*4882a593Smuzhiyun if (!priv->keys[index].seq)
47*4882a593Smuzhiyun goto free_key;
48*4882a593Smuzhiyun } else
49*4882a593Smuzhiyun priv->keys[index].seq = NULL;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun priv->keys[index].key_len = key_len;
52*4882a593Smuzhiyun priv->keys[index].seq_len = seq_len;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun if (key_len)
55*4882a593Smuzhiyun memcpy((void *)priv->keys[index].key, key, key_len);
56*4882a593Smuzhiyun if (seq_len)
57*4882a593Smuzhiyun memcpy((void *)priv->keys[index].seq, seq, seq_len);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun switch (alg) {
60*4882a593Smuzhiyun case ORINOCO_ALG_TKIP:
61*4882a593Smuzhiyun priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
62*4882a593Smuzhiyun break;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun case ORINOCO_ALG_WEP:
65*4882a593Smuzhiyun priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
66*4882a593Smuzhiyun WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
67*4882a593Smuzhiyun break;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun case ORINOCO_ALG_NONE:
70*4882a593Smuzhiyun default:
71*4882a593Smuzhiyun priv->keys[index].cipher = 0;
72*4882a593Smuzhiyun break;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return 0;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun free_key:
78*4882a593Smuzhiyun kfree(priv->keys[index].key);
79*4882a593Smuzhiyun priv->keys[index].key = NULL;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun nomem:
82*4882a593Smuzhiyun priv->keys[index].key_len = 0;
83*4882a593Smuzhiyun priv->keys[index].seq_len = 0;
84*4882a593Smuzhiyun priv->keys[index].cipher = 0;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun return -ENOMEM;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
orinoco_get_wireless_stats(struct net_device * dev)89*4882a593Smuzhiyun static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
92*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
93*4882a593Smuzhiyun struct iw_statistics *wstats = &priv->wstats;
94*4882a593Smuzhiyun int err;
95*4882a593Smuzhiyun unsigned long flags;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (!netif_device_present(dev)) {
98*4882a593Smuzhiyun printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
99*4882a593Smuzhiyun dev->name);
100*4882a593Smuzhiyun return NULL; /* FIXME: Can we do better than this? */
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun /* If busy, return the old stats. Returning NULL may cause
104*4882a593Smuzhiyun * the interface to disappear from /proc/net/wireless */
105*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
106*4882a593Smuzhiyun return wstats;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* We can't really wait for the tallies inquiry command to
109*4882a593Smuzhiyun * complete, so we just use the previous results and trigger
110*4882a593Smuzhiyun * a new tallies inquiry command for next time - Jean II */
111*4882a593Smuzhiyun /* FIXME: Really we should wait for the inquiry to come back -
112*4882a593Smuzhiyun * as it is the stats we give don't make a whole lot of sense.
113*4882a593Smuzhiyun * Unfortunately, it's not clear how to do that within the
114*4882a593Smuzhiyun * wireless extensions framework: I think we're in user
115*4882a593Smuzhiyun * context, but a lock seems to be held by the time we get in
116*4882a593Smuzhiyun * here so we're not safe to sleep here. */
117*4882a593Smuzhiyun hermes_inquire(hw, HERMES_INQ_TALLIES);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
120*4882a593Smuzhiyun memset(&wstats->qual, 0, sizeof(wstats->qual));
121*4882a593Smuzhiyun /* If a spy address is defined, we report stats of the
122*4882a593Smuzhiyun * first spy address - Jean II */
123*4882a593Smuzhiyun if (SPY_NUMBER(priv)) {
124*4882a593Smuzhiyun wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
125*4882a593Smuzhiyun wstats->qual.level = priv->spy_data.spy_stat[0].level;
126*4882a593Smuzhiyun wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
127*4882a593Smuzhiyun wstats->qual.updated =
128*4882a593Smuzhiyun priv->spy_data.spy_stat[0].updated;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun } else {
131*4882a593Smuzhiyun struct {
132*4882a593Smuzhiyun __le16 qual, signal, noise, unused;
133*4882a593Smuzhiyun } __packed cq;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun err = HERMES_READ_RECORD(hw, USER_BAP,
136*4882a593Smuzhiyun HERMES_RID_COMMSQUALITY, &cq);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (!err) {
139*4882a593Smuzhiyun wstats->qual.qual = (int)le16_to_cpu(cq.qual);
140*4882a593Smuzhiyun wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
141*4882a593Smuzhiyun wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
142*4882a593Smuzhiyun wstats->qual.updated =
143*4882a593Smuzhiyun IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
148*4882a593Smuzhiyun return wstats;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun /********************************************************************/
152*4882a593Smuzhiyun /* Wireless extensions */
153*4882a593Smuzhiyun /********************************************************************/
154*4882a593Smuzhiyun
orinoco_ioctl_setwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)155*4882a593Smuzhiyun static int orinoco_ioctl_setwap(struct net_device *dev,
156*4882a593Smuzhiyun struct iw_request_info *info,
157*4882a593Smuzhiyun struct sockaddr *ap_addr,
158*4882a593Smuzhiyun char *extra)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
161*4882a593Smuzhiyun int err = -EINPROGRESS; /* Call commit handler */
162*4882a593Smuzhiyun unsigned long flags;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
165*4882a593Smuzhiyun return -EBUSY;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* Enable automatic roaming - no sanity checks are needed */
168*4882a593Smuzhiyun if (is_zero_ether_addr(ap_addr->sa_data) ||
169*4882a593Smuzhiyun is_broadcast_ether_addr(ap_addr->sa_data)) {
170*4882a593Smuzhiyun priv->bssid_fixed = 0;
171*4882a593Smuzhiyun eth_zero_addr(priv->desired_bssid);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun /* "off" means keep existing connection */
174*4882a593Smuzhiyun if (ap_addr->sa_data[0] == 0) {
175*4882a593Smuzhiyun __orinoco_hw_set_wap(priv);
176*4882a593Smuzhiyun err = 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun goto out;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
182*4882a593Smuzhiyun printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
183*4882a593Smuzhiyun "support manual roaming\n",
184*4882a593Smuzhiyun dev->name);
185*4882a593Smuzhiyun err = -EOPNOTSUPP;
186*4882a593Smuzhiyun goto out;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (priv->iw_mode != NL80211_IFTYPE_STATION) {
190*4882a593Smuzhiyun printk(KERN_WARNING "%s: Manual roaming supported only in "
191*4882a593Smuzhiyun "managed mode\n", dev->name);
192*4882a593Smuzhiyun err = -EOPNOTSUPP;
193*4882a593Smuzhiyun goto out;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* Intersil firmware hangs without Desired ESSID */
197*4882a593Smuzhiyun if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
198*4882a593Smuzhiyun strlen(priv->desired_essid) == 0) {
199*4882a593Smuzhiyun printk(KERN_WARNING "%s: Desired ESSID must be set for "
200*4882a593Smuzhiyun "manual roaming\n", dev->name);
201*4882a593Smuzhiyun err = -EOPNOTSUPP;
202*4882a593Smuzhiyun goto out;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* Finally, enable manual roaming */
206*4882a593Smuzhiyun priv->bssid_fixed = 1;
207*4882a593Smuzhiyun memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun out:
210*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
211*4882a593Smuzhiyun return err;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
orinoco_ioctl_getwap(struct net_device * dev,struct iw_request_info * info,struct sockaddr * ap_addr,char * extra)214*4882a593Smuzhiyun static int orinoco_ioctl_getwap(struct net_device *dev,
215*4882a593Smuzhiyun struct iw_request_info *info,
216*4882a593Smuzhiyun struct sockaddr *ap_addr,
217*4882a593Smuzhiyun char *extra)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun int err = 0;
222*4882a593Smuzhiyun unsigned long flags;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
225*4882a593Smuzhiyun return -EBUSY;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ap_addr->sa_family = ARPHRD_ETHER;
228*4882a593Smuzhiyun err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun return err;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
orinoco_ioctl_setiwencode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)235*4882a593Smuzhiyun static int orinoco_ioctl_setiwencode(struct net_device *dev,
236*4882a593Smuzhiyun struct iw_request_info *info,
237*4882a593Smuzhiyun struct iw_point *erq,
238*4882a593Smuzhiyun char *keybuf)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
241*4882a593Smuzhiyun int index = (erq->flags & IW_ENCODE_INDEX) - 1;
242*4882a593Smuzhiyun int setindex = priv->tx_key;
243*4882a593Smuzhiyun enum orinoco_alg encode_alg = priv->encode_alg;
244*4882a593Smuzhiyun int restricted = priv->wep_restrict;
245*4882a593Smuzhiyun int err = -EINPROGRESS; /* Call commit handler */
246*4882a593Smuzhiyun unsigned long flags;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (!priv->has_wep)
249*4882a593Smuzhiyun return -EOPNOTSUPP;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (erq->pointer) {
252*4882a593Smuzhiyun /* We actually have a key to set - check its length */
253*4882a593Smuzhiyun if (erq->length > LARGE_KEY_SIZE)
254*4882a593Smuzhiyun return -E2BIG;
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
257*4882a593Smuzhiyun return -E2BIG;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
261*4882a593Smuzhiyun return -EBUSY;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Clear any TKIP key we have */
264*4882a593Smuzhiyun if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
265*4882a593Smuzhiyun (void) orinoco_clear_tkip_key(priv, setindex);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (erq->length > 0) {
268*4882a593Smuzhiyun if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
269*4882a593Smuzhiyun index = priv->tx_key;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Switch on WEP if off */
272*4882a593Smuzhiyun if (encode_alg != ORINOCO_ALG_WEP) {
273*4882a593Smuzhiyun setindex = index;
274*4882a593Smuzhiyun encode_alg = ORINOCO_ALG_WEP;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun } else {
277*4882a593Smuzhiyun /* Important note : if the user do "iwconfig eth0 enc off",
278*4882a593Smuzhiyun * we will arrive there with an index of -1. This is valid
279*4882a593Smuzhiyun * but need to be taken care off... Jean II */
280*4882a593Smuzhiyun if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
281*4882a593Smuzhiyun if ((index != -1) || (erq->flags == 0)) {
282*4882a593Smuzhiyun err = -EINVAL;
283*4882a593Smuzhiyun goto out;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun } else {
286*4882a593Smuzhiyun /* Set the index : Check that the key is valid */
287*4882a593Smuzhiyun if (priv->keys[index].key_len == 0) {
288*4882a593Smuzhiyun err = -EINVAL;
289*4882a593Smuzhiyun goto out;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun setindex = index;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (erq->flags & IW_ENCODE_DISABLED)
296*4882a593Smuzhiyun encode_alg = ORINOCO_ALG_NONE;
297*4882a593Smuzhiyun if (erq->flags & IW_ENCODE_OPEN)
298*4882a593Smuzhiyun restricted = 0;
299*4882a593Smuzhiyun if (erq->flags & IW_ENCODE_RESTRICTED)
300*4882a593Smuzhiyun restricted = 1;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun if (erq->pointer && erq->length > 0) {
303*4882a593Smuzhiyun err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
304*4882a593Smuzhiyun erq->length, NULL, 0);
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun priv->tx_key = setindex;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /* Try fast key change if connected and only keys are changed */
309*4882a593Smuzhiyun if ((priv->encode_alg == encode_alg) &&
310*4882a593Smuzhiyun (priv->wep_restrict == restricted) &&
311*4882a593Smuzhiyun netif_carrier_ok(dev)) {
312*4882a593Smuzhiyun err = __orinoco_hw_setup_wepkeys(priv);
313*4882a593Smuzhiyun /* No need to commit if successful */
314*4882a593Smuzhiyun goto out;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun priv->encode_alg = encode_alg;
318*4882a593Smuzhiyun priv->wep_restrict = restricted;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun out:
321*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun return err;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
orinoco_ioctl_getiwencode(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * keybuf)326*4882a593Smuzhiyun static int orinoco_ioctl_getiwencode(struct net_device *dev,
327*4882a593Smuzhiyun struct iw_request_info *info,
328*4882a593Smuzhiyun struct iw_point *erq,
329*4882a593Smuzhiyun char *keybuf)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
332*4882a593Smuzhiyun int index = (erq->flags & IW_ENCODE_INDEX) - 1;
333*4882a593Smuzhiyun unsigned long flags;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (!priv->has_wep)
336*4882a593Smuzhiyun return -EOPNOTSUPP;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
339*4882a593Smuzhiyun return -EBUSY;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
342*4882a593Smuzhiyun index = priv->tx_key;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun erq->flags = 0;
345*4882a593Smuzhiyun if (!priv->encode_alg)
346*4882a593Smuzhiyun erq->flags |= IW_ENCODE_DISABLED;
347*4882a593Smuzhiyun erq->flags |= index + 1;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (priv->wep_restrict)
350*4882a593Smuzhiyun erq->flags |= IW_ENCODE_RESTRICTED;
351*4882a593Smuzhiyun else
352*4882a593Smuzhiyun erq->flags |= IW_ENCODE_OPEN;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun erq->length = priv->keys[index].key_len;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun memcpy(keybuf, priv->keys[index].key, erq->length);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
359*4882a593Smuzhiyun return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
orinoco_ioctl_setessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * essidbuf)362*4882a593Smuzhiyun static int orinoco_ioctl_setessid(struct net_device *dev,
363*4882a593Smuzhiyun struct iw_request_info *info,
364*4882a593Smuzhiyun struct iw_point *erq,
365*4882a593Smuzhiyun char *essidbuf)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
368*4882a593Smuzhiyun unsigned long flags;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
371*4882a593Smuzhiyun * anyway... - Jean II */
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* Hum... Should not use Wireless Extension constant (may change),
374*4882a593Smuzhiyun * should use our own... - Jean II */
375*4882a593Smuzhiyun if (erq->length > IW_ESSID_MAX_SIZE)
376*4882a593Smuzhiyun return -E2BIG;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
379*4882a593Smuzhiyun return -EBUSY;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
382*4882a593Smuzhiyun memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* If not ANY, get the new ESSID */
385*4882a593Smuzhiyun if (erq->flags)
386*4882a593Smuzhiyun memcpy(priv->desired_essid, essidbuf, erq->length);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun return -EINPROGRESS; /* Call commit handler */
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
orinoco_ioctl_getessid(struct net_device * dev,struct iw_request_info * info,struct iw_point * erq,char * essidbuf)393*4882a593Smuzhiyun static int orinoco_ioctl_getessid(struct net_device *dev,
394*4882a593Smuzhiyun struct iw_request_info *info,
395*4882a593Smuzhiyun struct iw_point *erq,
396*4882a593Smuzhiyun char *essidbuf)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
399*4882a593Smuzhiyun int active;
400*4882a593Smuzhiyun int err = 0;
401*4882a593Smuzhiyun unsigned long flags;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (netif_running(dev)) {
404*4882a593Smuzhiyun err = orinoco_hw_get_essid(priv, &active, essidbuf);
405*4882a593Smuzhiyun if (err < 0)
406*4882a593Smuzhiyun return err;
407*4882a593Smuzhiyun erq->length = err;
408*4882a593Smuzhiyun } else {
409*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
410*4882a593Smuzhiyun return -EBUSY;
411*4882a593Smuzhiyun memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
412*4882a593Smuzhiyun erq->length = strlen(priv->desired_essid);
413*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun erq->flags = 1;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun return 0;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
orinoco_ioctl_setfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * frq,char * extra)421*4882a593Smuzhiyun static int orinoco_ioctl_setfreq(struct net_device *dev,
422*4882a593Smuzhiyun struct iw_request_info *info,
423*4882a593Smuzhiyun struct iw_freq *frq,
424*4882a593Smuzhiyun char *extra)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
427*4882a593Smuzhiyun int chan = -1;
428*4882a593Smuzhiyun unsigned long flags;
429*4882a593Smuzhiyun int err = -EINPROGRESS; /* Call commit handler */
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* In infrastructure mode the AP sets the channel */
432*4882a593Smuzhiyun if (priv->iw_mode == NL80211_IFTYPE_STATION)
433*4882a593Smuzhiyun return -EBUSY;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun if ((frq->e == 0) && (frq->m <= 1000)) {
436*4882a593Smuzhiyun /* Setting by channel number */
437*4882a593Smuzhiyun chan = frq->m;
438*4882a593Smuzhiyun } else {
439*4882a593Smuzhiyun /* Setting by frequency */
440*4882a593Smuzhiyun int denom = 1;
441*4882a593Smuzhiyun int i;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /* Calculate denominator to rescale to MHz */
444*4882a593Smuzhiyun for (i = 0; i < (6 - frq->e); i++)
445*4882a593Smuzhiyun denom *= 10;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun chan = ieee80211_frequency_to_channel(frq->m / denom);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if ((chan < 1) || (chan > NUM_CHANNELS) ||
451*4882a593Smuzhiyun !(priv->channel_mask & (1 << (chan - 1))))
452*4882a593Smuzhiyun return -EINVAL;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
455*4882a593Smuzhiyun return -EBUSY;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun priv->channel = chan;
458*4882a593Smuzhiyun if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
459*4882a593Smuzhiyun /* Fast channel change - no commit if successful */
460*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
461*4882a593Smuzhiyun err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
462*4882a593Smuzhiyun HERMES_TEST_SET_CHANNEL,
463*4882a593Smuzhiyun chan, NULL);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun return err;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
orinoco_ioctl_getfreq(struct net_device * dev,struct iw_request_info * info,struct iw_freq * frq,char * extra)470*4882a593Smuzhiyun static int orinoco_ioctl_getfreq(struct net_device *dev,
471*4882a593Smuzhiyun struct iw_request_info *info,
472*4882a593Smuzhiyun struct iw_freq *frq,
473*4882a593Smuzhiyun char *extra)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
476*4882a593Smuzhiyun int tmp;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /* Locking done in there */
479*4882a593Smuzhiyun tmp = orinoco_hw_get_freq(priv);
480*4882a593Smuzhiyun if (tmp < 0)
481*4882a593Smuzhiyun return tmp;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun frq->m = tmp * 100000;
484*4882a593Smuzhiyun frq->e = 1;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
orinoco_ioctl_getsens(struct net_device * dev,struct iw_request_info * info,struct iw_param * srq,char * extra)489*4882a593Smuzhiyun static int orinoco_ioctl_getsens(struct net_device *dev,
490*4882a593Smuzhiyun struct iw_request_info *info,
491*4882a593Smuzhiyun struct iw_param *srq,
492*4882a593Smuzhiyun char *extra)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
495*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
496*4882a593Smuzhiyun u16 val;
497*4882a593Smuzhiyun int err;
498*4882a593Smuzhiyun unsigned long flags;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun if (!priv->has_sensitivity)
501*4882a593Smuzhiyun return -EOPNOTSUPP;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
504*4882a593Smuzhiyun return -EBUSY;
505*4882a593Smuzhiyun err = hermes_read_wordrec(hw, USER_BAP,
506*4882a593Smuzhiyun HERMES_RID_CNFSYSTEMSCALE, &val);
507*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (err)
510*4882a593Smuzhiyun return err;
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun srq->value = val;
513*4882a593Smuzhiyun srq->fixed = 0; /* auto */
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun return 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
orinoco_ioctl_setsens(struct net_device * dev,struct iw_request_info * info,struct iw_param * srq,char * extra)518*4882a593Smuzhiyun static int orinoco_ioctl_setsens(struct net_device *dev,
519*4882a593Smuzhiyun struct iw_request_info *info,
520*4882a593Smuzhiyun struct iw_param *srq,
521*4882a593Smuzhiyun char *extra)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
524*4882a593Smuzhiyun int val = srq->value;
525*4882a593Smuzhiyun unsigned long flags;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (!priv->has_sensitivity)
528*4882a593Smuzhiyun return -EOPNOTSUPP;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun if ((val < 1) || (val > 3))
531*4882a593Smuzhiyun return -EINVAL;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
534*4882a593Smuzhiyun return -EBUSY;
535*4882a593Smuzhiyun priv->ap_density = val;
536*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return -EINPROGRESS; /* Call commit handler */
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
orinoco_ioctl_setrate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)541*4882a593Smuzhiyun static int orinoco_ioctl_setrate(struct net_device *dev,
542*4882a593Smuzhiyun struct iw_request_info *info,
543*4882a593Smuzhiyun struct iw_param *rrq,
544*4882a593Smuzhiyun char *extra)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
547*4882a593Smuzhiyun int ratemode;
548*4882a593Smuzhiyun int bitrate; /* 100s of kilobits */
549*4882a593Smuzhiyun unsigned long flags;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /* As the user space doesn't know our highest rate, it uses -1
552*4882a593Smuzhiyun * to ask us to set the highest rate. Test it using "iwconfig
553*4882a593Smuzhiyun * ethX rate auto" - Jean II */
554*4882a593Smuzhiyun if (rrq->value == -1)
555*4882a593Smuzhiyun bitrate = 110;
556*4882a593Smuzhiyun else {
557*4882a593Smuzhiyun if (rrq->value % 100000)
558*4882a593Smuzhiyun return -EINVAL;
559*4882a593Smuzhiyun bitrate = rrq->value / 100000;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun if (ratemode == -1)
565*4882a593Smuzhiyun return -EINVAL;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
568*4882a593Smuzhiyun return -EBUSY;
569*4882a593Smuzhiyun priv->bitratemode = ratemode;
570*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun return -EINPROGRESS;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
orinoco_ioctl_getrate(struct net_device * dev,struct iw_request_info * info,struct iw_param * rrq,char * extra)575*4882a593Smuzhiyun static int orinoco_ioctl_getrate(struct net_device *dev,
576*4882a593Smuzhiyun struct iw_request_info *info,
577*4882a593Smuzhiyun struct iw_param *rrq,
578*4882a593Smuzhiyun char *extra)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
581*4882a593Smuzhiyun int err = 0;
582*4882a593Smuzhiyun int bitrate, automatic;
583*4882a593Smuzhiyun unsigned long flags;
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
586*4882a593Smuzhiyun return -EBUSY;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun /* If the interface is running we try to find more about the
591*4882a593Smuzhiyun current mode */
592*4882a593Smuzhiyun if (netif_running(dev)) {
593*4882a593Smuzhiyun int act_bitrate;
594*4882a593Smuzhiyun int lerr;
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /* Ignore errors if we can't get the actual bitrate */
597*4882a593Smuzhiyun lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
598*4882a593Smuzhiyun if (!lerr)
599*4882a593Smuzhiyun bitrate = act_bitrate;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun rrq->value = bitrate;
605*4882a593Smuzhiyun rrq->fixed = !automatic;
606*4882a593Smuzhiyun rrq->disabled = 0;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun return err;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
orinoco_ioctl_setpower(struct net_device * dev,struct iw_request_info * info,struct iw_param * prq,char * extra)611*4882a593Smuzhiyun static int orinoco_ioctl_setpower(struct net_device *dev,
612*4882a593Smuzhiyun struct iw_request_info *info,
613*4882a593Smuzhiyun struct iw_param *prq,
614*4882a593Smuzhiyun char *extra)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
617*4882a593Smuzhiyun int err = -EINPROGRESS; /* Call commit handler */
618*4882a593Smuzhiyun unsigned long flags;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
621*4882a593Smuzhiyun return -EBUSY;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun if (prq->disabled) {
624*4882a593Smuzhiyun priv->pm_on = 0;
625*4882a593Smuzhiyun } else {
626*4882a593Smuzhiyun switch (prq->flags & IW_POWER_MODE) {
627*4882a593Smuzhiyun case IW_POWER_UNICAST_R:
628*4882a593Smuzhiyun priv->pm_mcast = 0;
629*4882a593Smuzhiyun priv->pm_on = 1;
630*4882a593Smuzhiyun break;
631*4882a593Smuzhiyun case IW_POWER_ALL_R:
632*4882a593Smuzhiyun priv->pm_mcast = 1;
633*4882a593Smuzhiyun priv->pm_on = 1;
634*4882a593Smuzhiyun break;
635*4882a593Smuzhiyun case IW_POWER_ON:
636*4882a593Smuzhiyun /* No flags : but we may have a value - Jean II */
637*4882a593Smuzhiyun break;
638*4882a593Smuzhiyun default:
639*4882a593Smuzhiyun err = -EINVAL;
640*4882a593Smuzhiyun goto out;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun if (prq->flags & IW_POWER_TIMEOUT) {
644*4882a593Smuzhiyun priv->pm_on = 1;
645*4882a593Smuzhiyun priv->pm_timeout = prq->value / 1000;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun if (prq->flags & IW_POWER_PERIOD) {
648*4882a593Smuzhiyun priv->pm_on = 1;
649*4882a593Smuzhiyun priv->pm_period = prq->value / 1000;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun /* It's valid to not have a value if we are just toggling
652*4882a593Smuzhiyun * the flags... Jean II */
653*4882a593Smuzhiyun if (!priv->pm_on) {
654*4882a593Smuzhiyun err = -EINVAL;
655*4882a593Smuzhiyun goto out;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun out:
660*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun return err;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
orinoco_ioctl_getpower(struct net_device * dev,struct iw_request_info * info,struct iw_param * prq,char * extra)665*4882a593Smuzhiyun static int orinoco_ioctl_getpower(struct net_device *dev,
666*4882a593Smuzhiyun struct iw_request_info *info,
667*4882a593Smuzhiyun struct iw_param *prq,
668*4882a593Smuzhiyun char *extra)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
671*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
672*4882a593Smuzhiyun int err = 0;
673*4882a593Smuzhiyun u16 enable, period, timeout, mcast;
674*4882a593Smuzhiyun unsigned long flags;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
677*4882a593Smuzhiyun return -EBUSY;
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun err = hermes_read_wordrec(hw, USER_BAP,
680*4882a593Smuzhiyun HERMES_RID_CNFPMENABLED, &enable);
681*4882a593Smuzhiyun if (err)
682*4882a593Smuzhiyun goto out;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun err = hermes_read_wordrec(hw, USER_BAP,
685*4882a593Smuzhiyun HERMES_RID_CNFMAXSLEEPDURATION, &period);
686*4882a593Smuzhiyun if (err)
687*4882a593Smuzhiyun goto out;
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun err = hermes_read_wordrec(hw, USER_BAP,
690*4882a593Smuzhiyun HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
691*4882a593Smuzhiyun if (err)
692*4882a593Smuzhiyun goto out;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun err = hermes_read_wordrec(hw, USER_BAP,
695*4882a593Smuzhiyun HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
696*4882a593Smuzhiyun if (err)
697*4882a593Smuzhiyun goto out;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun prq->disabled = !enable;
700*4882a593Smuzhiyun /* Note : by default, display the period */
701*4882a593Smuzhiyun if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
702*4882a593Smuzhiyun prq->flags = IW_POWER_TIMEOUT;
703*4882a593Smuzhiyun prq->value = timeout * 1000;
704*4882a593Smuzhiyun } else {
705*4882a593Smuzhiyun prq->flags = IW_POWER_PERIOD;
706*4882a593Smuzhiyun prq->value = period * 1000;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun if (mcast)
709*4882a593Smuzhiyun prq->flags |= IW_POWER_ALL_R;
710*4882a593Smuzhiyun else
711*4882a593Smuzhiyun prq->flags |= IW_POWER_UNICAST_R;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun out:
714*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun return err;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
orinoco_ioctl_set_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)719*4882a593Smuzhiyun static int orinoco_ioctl_set_encodeext(struct net_device *dev,
720*4882a593Smuzhiyun struct iw_request_info *info,
721*4882a593Smuzhiyun union iwreq_data *wrqu,
722*4882a593Smuzhiyun char *extra)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
725*4882a593Smuzhiyun struct iw_point *encoding = &wrqu->encoding;
726*4882a593Smuzhiyun struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
727*4882a593Smuzhiyun int idx, alg = ext->alg, set_key = 1;
728*4882a593Smuzhiyun unsigned long flags;
729*4882a593Smuzhiyun int err = -EINVAL;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
732*4882a593Smuzhiyun return -EBUSY;
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun /* Determine and validate the key index */
735*4882a593Smuzhiyun idx = encoding->flags & IW_ENCODE_INDEX;
736*4882a593Smuzhiyun if (idx) {
737*4882a593Smuzhiyun if ((idx < 1) || (idx > 4))
738*4882a593Smuzhiyun goto out;
739*4882a593Smuzhiyun idx--;
740*4882a593Smuzhiyun } else
741*4882a593Smuzhiyun idx = priv->tx_key;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (encoding->flags & IW_ENCODE_DISABLED)
744*4882a593Smuzhiyun alg = IW_ENCODE_ALG_NONE;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
747*4882a593Smuzhiyun /* Clear any TKIP TX key we had */
748*4882a593Smuzhiyun (void) orinoco_clear_tkip_key(priv, priv->tx_key);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
752*4882a593Smuzhiyun priv->tx_key = idx;
753*4882a593Smuzhiyun set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
754*4882a593Smuzhiyun (ext->key_len > 0)) ? 1 : 0;
755*4882a593Smuzhiyun }
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun if (set_key) {
758*4882a593Smuzhiyun /* Set the requested key first */
759*4882a593Smuzhiyun switch (alg) {
760*4882a593Smuzhiyun case IW_ENCODE_ALG_NONE:
761*4882a593Smuzhiyun priv->encode_alg = ORINOCO_ALG_NONE;
762*4882a593Smuzhiyun err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
763*4882a593Smuzhiyun NULL, 0, NULL, 0);
764*4882a593Smuzhiyun break;
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun case IW_ENCODE_ALG_WEP:
767*4882a593Smuzhiyun if (ext->key_len <= 0)
768*4882a593Smuzhiyun goto out;
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun priv->encode_alg = ORINOCO_ALG_WEP;
771*4882a593Smuzhiyun err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
772*4882a593Smuzhiyun ext->key, ext->key_len, NULL, 0);
773*4882a593Smuzhiyun break;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun case IW_ENCODE_ALG_TKIP:
776*4882a593Smuzhiyun {
777*4882a593Smuzhiyun u8 *tkip_iv = NULL;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun if (!priv->has_wpa ||
780*4882a593Smuzhiyun (ext->key_len > sizeof(struct orinoco_tkip_key)))
781*4882a593Smuzhiyun goto out;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun priv->encode_alg = ORINOCO_ALG_TKIP;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
786*4882a593Smuzhiyun tkip_iv = &ext->rx_seq[0];
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
789*4882a593Smuzhiyun ext->key, ext->key_len, tkip_iv,
790*4882a593Smuzhiyun ORINOCO_SEQ_LEN);
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun err = __orinoco_hw_set_tkip_key(priv, idx,
793*4882a593Smuzhiyun ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
794*4882a593Smuzhiyun priv->keys[idx].key,
795*4882a593Smuzhiyun tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
796*4882a593Smuzhiyun if (err)
797*4882a593Smuzhiyun printk(KERN_ERR "%s: Error %d setting TKIP key"
798*4882a593Smuzhiyun "\n", dev->name, err);
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun goto out;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun default:
803*4882a593Smuzhiyun goto out;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun err = -EINPROGRESS;
807*4882a593Smuzhiyun out:
808*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun return err;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun
orinoco_ioctl_get_encodeext(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)813*4882a593Smuzhiyun static int orinoco_ioctl_get_encodeext(struct net_device *dev,
814*4882a593Smuzhiyun struct iw_request_info *info,
815*4882a593Smuzhiyun union iwreq_data *wrqu,
816*4882a593Smuzhiyun char *extra)
817*4882a593Smuzhiyun {
818*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
819*4882a593Smuzhiyun struct iw_point *encoding = &wrqu->encoding;
820*4882a593Smuzhiyun struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
821*4882a593Smuzhiyun int idx, max_key_len;
822*4882a593Smuzhiyun unsigned long flags;
823*4882a593Smuzhiyun int err;
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
826*4882a593Smuzhiyun return -EBUSY;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun err = -EINVAL;
829*4882a593Smuzhiyun max_key_len = encoding->length - sizeof(*ext);
830*4882a593Smuzhiyun if (max_key_len < 0)
831*4882a593Smuzhiyun goto out;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun idx = encoding->flags & IW_ENCODE_INDEX;
834*4882a593Smuzhiyun if (idx) {
835*4882a593Smuzhiyun if ((idx < 1) || (idx > 4))
836*4882a593Smuzhiyun goto out;
837*4882a593Smuzhiyun idx--;
838*4882a593Smuzhiyun } else
839*4882a593Smuzhiyun idx = priv->tx_key;
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun encoding->flags = idx + 1;
842*4882a593Smuzhiyun memset(ext, 0, sizeof(*ext));
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun switch (priv->encode_alg) {
845*4882a593Smuzhiyun case ORINOCO_ALG_NONE:
846*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_NONE;
847*4882a593Smuzhiyun ext->key_len = 0;
848*4882a593Smuzhiyun encoding->flags |= IW_ENCODE_DISABLED;
849*4882a593Smuzhiyun break;
850*4882a593Smuzhiyun case ORINOCO_ALG_WEP:
851*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_WEP;
852*4882a593Smuzhiyun ext->key_len = min(priv->keys[idx].key_len, max_key_len);
853*4882a593Smuzhiyun memcpy(ext->key, priv->keys[idx].key, ext->key_len);
854*4882a593Smuzhiyun encoding->flags |= IW_ENCODE_ENABLED;
855*4882a593Smuzhiyun break;
856*4882a593Smuzhiyun case ORINOCO_ALG_TKIP:
857*4882a593Smuzhiyun ext->alg = IW_ENCODE_ALG_TKIP;
858*4882a593Smuzhiyun ext->key_len = min(priv->keys[idx].key_len, max_key_len);
859*4882a593Smuzhiyun memcpy(ext->key, priv->keys[idx].key, ext->key_len);
860*4882a593Smuzhiyun encoding->flags |= IW_ENCODE_ENABLED;
861*4882a593Smuzhiyun break;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun err = 0;
865*4882a593Smuzhiyun out:
866*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun return err;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
orinoco_ioctl_set_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)871*4882a593Smuzhiyun static int orinoco_ioctl_set_auth(struct net_device *dev,
872*4882a593Smuzhiyun struct iw_request_info *info,
873*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
874*4882a593Smuzhiyun {
875*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
876*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
877*4882a593Smuzhiyun struct iw_param *param = &wrqu->param;
878*4882a593Smuzhiyun unsigned long flags;
879*4882a593Smuzhiyun int ret = -EINPROGRESS;
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
882*4882a593Smuzhiyun return -EBUSY;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun switch (param->flags & IW_AUTH_INDEX) {
885*4882a593Smuzhiyun case IW_AUTH_WPA_VERSION:
886*4882a593Smuzhiyun case IW_AUTH_CIPHER_PAIRWISE:
887*4882a593Smuzhiyun case IW_AUTH_CIPHER_GROUP:
888*4882a593Smuzhiyun case IW_AUTH_RX_UNENCRYPTED_EAPOL:
889*4882a593Smuzhiyun case IW_AUTH_PRIVACY_INVOKED:
890*4882a593Smuzhiyun case IW_AUTH_DROP_UNENCRYPTED:
891*4882a593Smuzhiyun /*
892*4882a593Smuzhiyun * orinoco does not use these parameters
893*4882a593Smuzhiyun */
894*4882a593Smuzhiyun break;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun case IW_AUTH_MFP:
897*4882a593Smuzhiyun /* Management Frame Protection not supported.
898*4882a593Smuzhiyun * Only fail if set to required.
899*4882a593Smuzhiyun */
900*4882a593Smuzhiyun if (param->value == IW_AUTH_MFP_REQUIRED)
901*4882a593Smuzhiyun ret = -EINVAL;
902*4882a593Smuzhiyun break;
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun case IW_AUTH_KEY_MGMT:
905*4882a593Smuzhiyun /* wl_lkm implies value 2 == PSK for Hermes I
906*4882a593Smuzhiyun * which ties in with WEXT
907*4882a593Smuzhiyun * no other hints tho :(
908*4882a593Smuzhiyun */
909*4882a593Smuzhiyun priv->key_mgmt = param->value;
910*4882a593Smuzhiyun break;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun case IW_AUTH_TKIP_COUNTERMEASURES:
913*4882a593Smuzhiyun /* When countermeasures are enabled, shut down the
914*4882a593Smuzhiyun * card; when disabled, re-enable the card. This must
915*4882a593Smuzhiyun * take effect immediately.
916*4882a593Smuzhiyun *
917*4882a593Smuzhiyun * TODO: Make sure that the EAPOL message is getting
918*4882a593Smuzhiyun * out before card disabled
919*4882a593Smuzhiyun */
920*4882a593Smuzhiyun if (param->value) {
921*4882a593Smuzhiyun priv->tkip_cm_active = 1;
922*4882a593Smuzhiyun ret = hermes_disable_port(hw, 0);
923*4882a593Smuzhiyun } else {
924*4882a593Smuzhiyun priv->tkip_cm_active = 0;
925*4882a593Smuzhiyun ret = hermes_enable_port(hw, 0);
926*4882a593Smuzhiyun }
927*4882a593Smuzhiyun break;
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun case IW_AUTH_80211_AUTH_ALG:
930*4882a593Smuzhiyun if (param->value & IW_AUTH_ALG_SHARED_KEY)
931*4882a593Smuzhiyun priv->wep_restrict = 1;
932*4882a593Smuzhiyun else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
933*4882a593Smuzhiyun priv->wep_restrict = 0;
934*4882a593Smuzhiyun else
935*4882a593Smuzhiyun ret = -EINVAL;
936*4882a593Smuzhiyun break;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun case IW_AUTH_WPA_ENABLED:
939*4882a593Smuzhiyun if (priv->has_wpa) {
940*4882a593Smuzhiyun priv->wpa_enabled = param->value ? 1 : 0;
941*4882a593Smuzhiyun } else {
942*4882a593Smuzhiyun if (param->value)
943*4882a593Smuzhiyun ret = -EOPNOTSUPP;
944*4882a593Smuzhiyun /* else silently accept disable of WPA */
945*4882a593Smuzhiyun priv->wpa_enabled = 0;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun break;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun default:
950*4882a593Smuzhiyun ret = -EOPNOTSUPP;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
954*4882a593Smuzhiyun return ret;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
orinoco_ioctl_get_auth(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)957*4882a593Smuzhiyun static int orinoco_ioctl_get_auth(struct net_device *dev,
958*4882a593Smuzhiyun struct iw_request_info *info,
959*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
962*4882a593Smuzhiyun struct iw_param *param = &wrqu->param;
963*4882a593Smuzhiyun unsigned long flags;
964*4882a593Smuzhiyun int ret = 0;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
967*4882a593Smuzhiyun return -EBUSY;
968*4882a593Smuzhiyun
969*4882a593Smuzhiyun switch (param->flags & IW_AUTH_INDEX) {
970*4882a593Smuzhiyun case IW_AUTH_KEY_MGMT:
971*4882a593Smuzhiyun param->value = priv->key_mgmt;
972*4882a593Smuzhiyun break;
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun case IW_AUTH_TKIP_COUNTERMEASURES:
975*4882a593Smuzhiyun param->value = priv->tkip_cm_active;
976*4882a593Smuzhiyun break;
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun case IW_AUTH_80211_AUTH_ALG:
979*4882a593Smuzhiyun if (priv->wep_restrict)
980*4882a593Smuzhiyun param->value = IW_AUTH_ALG_SHARED_KEY;
981*4882a593Smuzhiyun else
982*4882a593Smuzhiyun param->value = IW_AUTH_ALG_OPEN_SYSTEM;
983*4882a593Smuzhiyun break;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun case IW_AUTH_WPA_ENABLED:
986*4882a593Smuzhiyun param->value = priv->wpa_enabled;
987*4882a593Smuzhiyun break;
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun default:
990*4882a593Smuzhiyun ret = -EOPNOTSUPP;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
994*4882a593Smuzhiyun return ret;
995*4882a593Smuzhiyun }
996*4882a593Smuzhiyun
orinoco_ioctl_set_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)997*4882a593Smuzhiyun static int orinoco_ioctl_set_genie(struct net_device *dev,
998*4882a593Smuzhiyun struct iw_request_info *info,
999*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
1000*4882a593Smuzhiyun {
1001*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1002*4882a593Smuzhiyun u8 *buf;
1003*4882a593Smuzhiyun unsigned long flags;
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun /* cut off at IEEE80211_MAX_DATA_LEN */
1006*4882a593Smuzhiyun if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
1007*4882a593Smuzhiyun (wrqu->data.length && (extra == NULL)))
1008*4882a593Smuzhiyun return -EINVAL;
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun if (wrqu->data.length) {
1011*4882a593Smuzhiyun buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
1012*4882a593Smuzhiyun if (buf == NULL)
1013*4882a593Smuzhiyun return -ENOMEM;
1014*4882a593Smuzhiyun } else
1015*4882a593Smuzhiyun buf = NULL;
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0) {
1018*4882a593Smuzhiyun kfree(buf);
1019*4882a593Smuzhiyun return -EBUSY;
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun kfree(priv->wpa_ie);
1023*4882a593Smuzhiyun priv->wpa_ie = buf;
1024*4882a593Smuzhiyun priv->wpa_ie_len = wrqu->data.length;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun if (priv->wpa_ie) {
1027*4882a593Smuzhiyun /* Looks like wl_lkm wants to check the auth alg, and
1028*4882a593Smuzhiyun * somehow pass it to the firmware.
1029*4882a593Smuzhiyun * Instead it just calls the key mgmt rid
1030*4882a593Smuzhiyun * - we do this in set auth.
1031*4882a593Smuzhiyun */
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1035*4882a593Smuzhiyun return 0;
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun
orinoco_ioctl_get_genie(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1038*4882a593Smuzhiyun static int orinoco_ioctl_get_genie(struct net_device *dev,
1039*4882a593Smuzhiyun struct iw_request_info *info,
1040*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1043*4882a593Smuzhiyun unsigned long flags;
1044*4882a593Smuzhiyun int err = 0;
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1047*4882a593Smuzhiyun return -EBUSY;
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
1050*4882a593Smuzhiyun wrqu->data.length = 0;
1051*4882a593Smuzhiyun goto out;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun if (wrqu->data.length < priv->wpa_ie_len) {
1055*4882a593Smuzhiyun err = -E2BIG;
1056*4882a593Smuzhiyun goto out;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun wrqu->data.length = priv->wpa_ie_len;
1060*4882a593Smuzhiyun memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun out:
1063*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1064*4882a593Smuzhiyun return err;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
orinoco_ioctl_set_mlme(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1067*4882a593Smuzhiyun static int orinoco_ioctl_set_mlme(struct net_device *dev,
1068*4882a593Smuzhiyun struct iw_request_info *info,
1069*4882a593Smuzhiyun union iwreq_data *wrqu, char *extra)
1070*4882a593Smuzhiyun {
1071*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1072*4882a593Smuzhiyun struct iw_mlme *mlme = (struct iw_mlme *)extra;
1073*4882a593Smuzhiyun unsigned long flags;
1074*4882a593Smuzhiyun int ret = 0;
1075*4882a593Smuzhiyun
1076*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1077*4882a593Smuzhiyun return -EBUSY;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun switch (mlme->cmd) {
1080*4882a593Smuzhiyun case IW_MLME_DEAUTH:
1081*4882a593Smuzhiyun /* silently ignore */
1082*4882a593Smuzhiyun break;
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun case IW_MLME_DISASSOC:
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
1087*4882a593Smuzhiyun mlme->reason_code);
1088*4882a593Smuzhiyun break;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun default:
1091*4882a593Smuzhiyun ret = -EOPNOTSUPP;
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1095*4882a593Smuzhiyun return ret;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun
orinoco_ioctl_reset(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1098*4882a593Smuzhiyun static int orinoco_ioctl_reset(struct net_device *dev,
1099*4882a593Smuzhiyun struct iw_request_info *info,
1100*4882a593Smuzhiyun void *wrqu,
1101*4882a593Smuzhiyun char *extra)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun if (!capable(CAP_NET_ADMIN))
1106*4882a593Smuzhiyun return -EPERM;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
1109*4882a593Smuzhiyun printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun /* Firmware reset */
1112*4882a593Smuzhiyun orinoco_reset(&priv->reset_work);
1113*4882a593Smuzhiyun } else {
1114*4882a593Smuzhiyun printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun schedule_work(&priv->reset_work);
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun return 0;
1120*4882a593Smuzhiyun }
1121*4882a593Smuzhiyun
orinoco_ioctl_setibssport(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1122*4882a593Smuzhiyun static int orinoco_ioctl_setibssport(struct net_device *dev,
1123*4882a593Smuzhiyun struct iw_request_info *info,
1124*4882a593Smuzhiyun void *wrqu,
1125*4882a593Smuzhiyun char *extra)
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1129*4882a593Smuzhiyun int val = *((int *) extra);
1130*4882a593Smuzhiyun unsigned long flags;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1133*4882a593Smuzhiyun return -EBUSY;
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun priv->ibss_port = val;
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun /* Actually update the mode we are using */
1138*4882a593Smuzhiyun set_port_type(priv);
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1141*4882a593Smuzhiyun return -EINPROGRESS; /* Call commit handler */
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
orinoco_ioctl_getibssport(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1144*4882a593Smuzhiyun static int orinoco_ioctl_getibssport(struct net_device *dev,
1145*4882a593Smuzhiyun struct iw_request_info *info,
1146*4882a593Smuzhiyun void *wrqu,
1147*4882a593Smuzhiyun char *extra)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1150*4882a593Smuzhiyun int *val = (int *) extra;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun *val = priv->ibss_port;
1153*4882a593Smuzhiyun return 0;
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun
orinoco_ioctl_setport3(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1156*4882a593Smuzhiyun static int orinoco_ioctl_setport3(struct net_device *dev,
1157*4882a593Smuzhiyun struct iw_request_info *info,
1158*4882a593Smuzhiyun void *wrqu,
1159*4882a593Smuzhiyun char *extra)
1160*4882a593Smuzhiyun {
1161*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1162*4882a593Smuzhiyun int val = *((int *) extra);
1163*4882a593Smuzhiyun int err = 0;
1164*4882a593Smuzhiyun unsigned long flags;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1167*4882a593Smuzhiyun return -EBUSY;
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun switch (val) {
1170*4882a593Smuzhiyun case 0: /* Try to do IEEE ad-hoc mode */
1171*4882a593Smuzhiyun if (!priv->has_ibss) {
1172*4882a593Smuzhiyun err = -EINVAL;
1173*4882a593Smuzhiyun break;
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun priv->prefer_port3 = 0;
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun break;
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun case 1: /* Try to do Lucent proprietary ad-hoc mode */
1180*4882a593Smuzhiyun if (!priv->has_port3) {
1181*4882a593Smuzhiyun err = -EINVAL;
1182*4882a593Smuzhiyun break;
1183*4882a593Smuzhiyun }
1184*4882a593Smuzhiyun priv->prefer_port3 = 1;
1185*4882a593Smuzhiyun break;
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun default:
1188*4882a593Smuzhiyun err = -EINVAL;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun if (!err) {
1192*4882a593Smuzhiyun /* Actually update the mode we are using */
1193*4882a593Smuzhiyun set_port_type(priv);
1194*4882a593Smuzhiyun err = -EINPROGRESS;
1195*4882a593Smuzhiyun }
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun return err;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun
orinoco_ioctl_getport3(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1202*4882a593Smuzhiyun static int orinoco_ioctl_getport3(struct net_device *dev,
1203*4882a593Smuzhiyun struct iw_request_info *info,
1204*4882a593Smuzhiyun void *wrqu,
1205*4882a593Smuzhiyun char *extra)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1208*4882a593Smuzhiyun int *val = (int *) extra;
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun *val = priv->prefer_port3;
1211*4882a593Smuzhiyun return 0;
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun
orinoco_ioctl_setpreamble(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1214*4882a593Smuzhiyun static int orinoco_ioctl_setpreamble(struct net_device *dev,
1215*4882a593Smuzhiyun struct iw_request_info *info,
1216*4882a593Smuzhiyun void *wrqu,
1217*4882a593Smuzhiyun char *extra)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1220*4882a593Smuzhiyun unsigned long flags;
1221*4882a593Smuzhiyun int val;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun if (!priv->has_preamble)
1224*4882a593Smuzhiyun return -EOPNOTSUPP;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun /* 802.11b has recently defined some short preamble.
1227*4882a593Smuzhiyun * Basically, the Phy header has been reduced in size.
1228*4882a593Smuzhiyun * This increase performance, especially at high rates
1229*4882a593Smuzhiyun * (the preamble is transmitted at 1Mb/s), unfortunately
1230*4882a593Smuzhiyun * this give compatibility troubles... - Jean II */
1231*4882a593Smuzhiyun val = *((int *) extra);
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1234*4882a593Smuzhiyun return -EBUSY;
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun if (val)
1237*4882a593Smuzhiyun priv->preamble = 1;
1238*4882a593Smuzhiyun else
1239*4882a593Smuzhiyun priv->preamble = 0;
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun return -EINPROGRESS; /* Call commit handler */
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun
orinoco_ioctl_getpreamble(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1246*4882a593Smuzhiyun static int orinoco_ioctl_getpreamble(struct net_device *dev,
1247*4882a593Smuzhiyun struct iw_request_info *info,
1248*4882a593Smuzhiyun void *wrqu,
1249*4882a593Smuzhiyun char *extra)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1252*4882a593Smuzhiyun int *val = (int *) extra;
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun if (!priv->has_preamble)
1255*4882a593Smuzhiyun return -EOPNOTSUPP;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun *val = priv->preamble;
1258*4882a593Smuzhiyun return 0;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun /* ioctl interface to hermes_read_ltv()
1262*4882a593Smuzhiyun * To use with iwpriv, pass the RID as the token argument, e.g.
1263*4882a593Smuzhiyun * iwpriv get_rid [0xfc00]
1264*4882a593Smuzhiyun * At least Wireless Tools 25 is required to use iwpriv.
1265*4882a593Smuzhiyun * For Wireless Tools 25 and 26 append "dummy" are the end. */
orinoco_ioctl_getrid(struct net_device * dev,struct iw_request_info * info,struct iw_point * data,char * extra)1266*4882a593Smuzhiyun static int orinoco_ioctl_getrid(struct net_device *dev,
1267*4882a593Smuzhiyun struct iw_request_info *info,
1268*4882a593Smuzhiyun struct iw_point *data,
1269*4882a593Smuzhiyun char *extra)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1272*4882a593Smuzhiyun struct hermes *hw = &priv->hw;
1273*4882a593Smuzhiyun int rid = data->flags;
1274*4882a593Smuzhiyun u16 length;
1275*4882a593Smuzhiyun int err;
1276*4882a593Smuzhiyun unsigned long flags;
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun /* It's a "get" function, but we don't want users to access the
1279*4882a593Smuzhiyun * WEP key and other raw firmware data */
1280*4882a593Smuzhiyun if (!capable(CAP_NET_ADMIN))
1281*4882a593Smuzhiyun return -EPERM;
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun if (rid < 0xfc00 || rid > 0xffff)
1284*4882a593Smuzhiyun return -EINVAL;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1287*4882a593Smuzhiyun return -EBUSY;
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
1290*4882a593Smuzhiyun extra);
1291*4882a593Smuzhiyun if (err)
1292*4882a593Smuzhiyun goto out;
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
1295*4882a593Smuzhiyun MAX_RID_LEN);
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun out:
1298*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1299*4882a593Smuzhiyun return err;
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun /* Commit handler, called after set operations */
orinoco_ioctl_commit(struct net_device * dev,struct iw_request_info * info,void * wrqu,char * extra)1304*4882a593Smuzhiyun static int orinoco_ioctl_commit(struct net_device *dev,
1305*4882a593Smuzhiyun struct iw_request_info *info,
1306*4882a593Smuzhiyun void *wrqu,
1307*4882a593Smuzhiyun char *extra)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun struct orinoco_private *priv = ndev_priv(dev);
1310*4882a593Smuzhiyun unsigned long flags;
1311*4882a593Smuzhiyun int err = 0;
1312*4882a593Smuzhiyun
1313*4882a593Smuzhiyun if (!priv->open)
1314*4882a593Smuzhiyun return 0;
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun if (orinoco_lock(priv, &flags) != 0)
1317*4882a593Smuzhiyun return err;
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun err = orinoco_commit(priv);
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun orinoco_unlock(priv, &flags);
1322*4882a593Smuzhiyun return err;
1323*4882a593Smuzhiyun }
1324*4882a593Smuzhiyun
1325*4882a593Smuzhiyun static const struct iw_priv_args orinoco_privtab[] = {
1326*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
1327*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
1328*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1329*4882a593Smuzhiyun 0, "set_port3" },
1330*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1331*4882a593Smuzhiyun "get_port3" },
1332*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1333*4882a593Smuzhiyun 0, "set_preamble" },
1334*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1335*4882a593Smuzhiyun "get_preamble" },
1336*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1337*4882a593Smuzhiyun 0, "set_ibssport" },
1338*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1339*4882a593Smuzhiyun "get_ibssport" },
1340*4882a593Smuzhiyun { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
1341*4882a593Smuzhiyun "get_rid" },
1342*4882a593Smuzhiyun };
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun /*
1346*4882a593Smuzhiyun * Structures to export the Wireless Handlers
1347*4882a593Smuzhiyun */
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun static const iw_handler orinoco_handler[] = {
1350*4882a593Smuzhiyun IW_HANDLER(SIOCSIWCOMMIT, (iw_handler)orinoco_ioctl_commit),
1351*4882a593Smuzhiyun IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname),
1352*4882a593Smuzhiyun IW_HANDLER(SIOCSIWFREQ, (iw_handler)orinoco_ioctl_setfreq),
1353*4882a593Smuzhiyun IW_HANDLER(SIOCGIWFREQ, (iw_handler)orinoco_ioctl_getfreq),
1354*4882a593Smuzhiyun IW_HANDLER(SIOCSIWMODE, (iw_handler)cfg80211_wext_siwmode),
1355*4882a593Smuzhiyun IW_HANDLER(SIOCGIWMODE, (iw_handler)cfg80211_wext_giwmode),
1356*4882a593Smuzhiyun IW_HANDLER(SIOCSIWSENS, (iw_handler)orinoco_ioctl_setsens),
1357*4882a593Smuzhiyun IW_HANDLER(SIOCGIWSENS, (iw_handler)orinoco_ioctl_getsens),
1358*4882a593Smuzhiyun IW_HANDLER(SIOCGIWRANGE, (iw_handler)cfg80211_wext_giwrange),
1359*4882a593Smuzhiyun IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
1360*4882a593Smuzhiyun IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
1361*4882a593Smuzhiyun IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
1362*4882a593Smuzhiyun IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
1363*4882a593Smuzhiyun IW_HANDLER(SIOCSIWAP, (iw_handler)orinoco_ioctl_setwap),
1364*4882a593Smuzhiyun IW_HANDLER(SIOCGIWAP, (iw_handler)orinoco_ioctl_getwap),
1365*4882a593Smuzhiyun IW_HANDLER(SIOCSIWSCAN, (iw_handler)cfg80211_wext_siwscan),
1366*4882a593Smuzhiyun IW_HANDLER(SIOCGIWSCAN, (iw_handler)cfg80211_wext_giwscan),
1367*4882a593Smuzhiyun IW_HANDLER(SIOCSIWESSID, (iw_handler)orinoco_ioctl_setessid),
1368*4882a593Smuzhiyun IW_HANDLER(SIOCGIWESSID, (iw_handler)orinoco_ioctl_getessid),
1369*4882a593Smuzhiyun IW_HANDLER(SIOCSIWRATE, (iw_handler)orinoco_ioctl_setrate),
1370*4882a593Smuzhiyun IW_HANDLER(SIOCGIWRATE, (iw_handler)orinoco_ioctl_getrate),
1371*4882a593Smuzhiyun IW_HANDLER(SIOCSIWRTS, (iw_handler)cfg80211_wext_siwrts),
1372*4882a593Smuzhiyun IW_HANDLER(SIOCGIWRTS, (iw_handler)cfg80211_wext_giwrts),
1373*4882a593Smuzhiyun IW_HANDLER(SIOCSIWFRAG, (iw_handler)cfg80211_wext_siwfrag),
1374*4882a593Smuzhiyun IW_HANDLER(SIOCGIWFRAG, (iw_handler)cfg80211_wext_giwfrag),
1375*4882a593Smuzhiyun IW_HANDLER(SIOCGIWRETRY, (iw_handler)cfg80211_wext_giwretry),
1376*4882a593Smuzhiyun IW_HANDLER(SIOCSIWENCODE, (iw_handler)orinoco_ioctl_setiwencode),
1377*4882a593Smuzhiyun IW_HANDLER(SIOCGIWENCODE, (iw_handler)orinoco_ioctl_getiwencode),
1378*4882a593Smuzhiyun IW_HANDLER(SIOCSIWPOWER, (iw_handler)orinoco_ioctl_setpower),
1379*4882a593Smuzhiyun IW_HANDLER(SIOCGIWPOWER, (iw_handler)orinoco_ioctl_getpower),
1380*4882a593Smuzhiyun IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
1381*4882a593Smuzhiyun IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
1382*4882a593Smuzhiyun IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
1383*4882a593Smuzhiyun IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
1384*4882a593Smuzhiyun IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
1385*4882a593Smuzhiyun IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
1386*4882a593Smuzhiyun IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
1387*4882a593Smuzhiyun };
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun /*
1391*4882a593Smuzhiyun Added typecasting since we no longer use iwreq_data -- Moustafa
1392*4882a593Smuzhiyun */
1393*4882a593Smuzhiyun static const iw_handler orinoco_private_handler[] = {
1394*4882a593Smuzhiyun [0] = (iw_handler)orinoco_ioctl_reset,
1395*4882a593Smuzhiyun [1] = (iw_handler)orinoco_ioctl_reset,
1396*4882a593Smuzhiyun [2] = (iw_handler)orinoco_ioctl_setport3,
1397*4882a593Smuzhiyun [3] = (iw_handler)orinoco_ioctl_getport3,
1398*4882a593Smuzhiyun [4] = (iw_handler)orinoco_ioctl_setpreamble,
1399*4882a593Smuzhiyun [5] = (iw_handler)orinoco_ioctl_getpreamble,
1400*4882a593Smuzhiyun [6] = (iw_handler)orinoco_ioctl_setibssport,
1401*4882a593Smuzhiyun [7] = (iw_handler)orinoco_ioctl_getibssport,
1402*4882a593Smuzhiyun [9] = (iw_handler)orinoco_ioctl_getrid,
1403*4882a593Smuzhiyun };
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun const struct iw_handler_def orinoco_handler_def = {
1406*4882a593Smuzhiyun .num_standard = ARRAY_SIZE(orinoco_handler),
1407*4882a593Smuzhiyun .num_private = ARRAY_SIZE(orinoco_private_handler),
1408*4882a593Smuzhiyun .num_private_args = ARRAY_SIZE(orinoco_privtab),
1409*4882a593Smuzhiyun .standard = orinoco_handler,
1410*4882a593Smuzhiyun .private = orinoco_private_handler,
1411*4882a593Smuzhiyun .private_args = orinoco_privtab,
1412*4882a593Smuzhiyun .get_wireless_stats = orinoco_get_wireless_stats,
1413*4882a593Smuzhiyun };
1414