1 /* src/p80211/p80211wext.c
3 * Glue code to make linux-wlan-ng a happy wireless extension camper.
5 * original author: Reyk Floeter <reyk@synack.de>
6 * Completely re-written by Solomon Peachy <solomon@linux-wlan.com>
8 * Copyright (C) 2002 AbsoluteValue Systems, Inc. All Rights Reserved.
9 * --------------------------------------------------------------------
13 * The contents of this file are subject to the Mozilla Public
14 * License Version 1.1 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.mozilla.org/MPL/
18 * Software distributed under the License is distributed on an "AS
19 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
20 * implied. See the License for the specific language governing
21 * rights and limitations under the License.
23 * Alternatively, the contents of this file may be used under the
24 * terms of the GNU Public License version 2 (the "GPL"), in which
25 * case the provisions of the GPL are applicable instead of the
26 * above. If you wish to allow the use of your version of this file
27 * only under the terms of the GPL and not to allow others to use
28 * your version of this file under the MPL, indicate your decision
29 * by deleting the provisions above and replace them with the notice
30 * and other provisions required by the GPL. If you do not delete
31 * the provisions above, a recipient may use your version of this
32 * file under either the MPL or the GPL.
34 * --------------------------------------------------------------------
37 /*================================================================*/
40 #include <linux/kernel.h>
41 #include <linux/sched.h>
42 #include <linux/types.h>
43 #include <linux/netdevice.h>
44 #include <linux/etherdevice.h>
45 #include <linux/wireless.h>
46 #include <net/iw_handler.h>
47 #include <linux/if_arp.h>
48 #include <linux/bitops.h>
49 #include <linux/uaccess.h>
50 #include <asm/byteorder.h>
51 #include <linux/if_ether.h>
53 #include "p80211types.h"
54 #include "p80211hdr.h"
55 #include "p80211conv.h"
56 #include "p80211mgmt.h"
57 #include "p80211msg.h"
58 #include "p80211metastruct.h"
59 #include "p80211metadef.h"
60 #include "p80211netdev.h"
61 #include "p80211ioctl.h"
62 #include "p80211req.h"
64 static int p80211wext_giwrate(netdevice_t
*dev
,
65 struct iw_request_info
*info
,
66 struct iw_param
*rrq
, char *extra
);
67 static int p80211wext_giwessid(netdevice_t
*dev
,
68 struct iw_request_info
*info
,
69 struct iw_point
*data
, char *essid
);
71 static u8
p80211_mhz_to_channel(u16 mhz
)
74 return (mhz
- 5000) / 5;
80 return (mhz
- 2407) / 5;
85 static u16
p80211_channel_to_mhz(u8 ch
, int dot11a
)
95 return 5000 + (5 * ch
);
101 if ((ch
< 14) && (ch
> 0))
102 return 2407 + (5 * ch
);
107 /* taken from orinoco.c ;-) */
108 static const long p80211wext_channel_freq
[] = {
109 2412, 2417, 2422, 2427, 2432, 2437, 2442,
110 2447, 2452, 2457, 2462, 2467, 2472, 2484
113 #define NUM_CHANNELS ARRAY_SIZE(p80211wext_channel_freq)
115 /* steal a spare bit to store the shared/opensystems state.
116 should default to open if not set */
117 #define HOSTWEP_SHAREDKEY BIT(3)
119 static int qual_as_percent(int snr
)
128 static int p80211wext_setmib(wlandevice_t
*wlandev
, u32 did
, u32 data
)
130 p80211msg_dot11req_mibset_t msg
;
131 p80211item_uint32_t
*mibitem
=
132 (p80211item_uint32_t
*)&msg
.mibattribute
.data
;
135 msg
.msgcode
= DIDmsg_dot11req_mibset
;
136 memset(mibitem
, 0, sizeof(*mibitem
));
138 mibitem
->data
= data
;
139 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
145 * get a 32 bit mib value
147 static int p80211wext_getmib(wlandevice_t
*wlandev
, u32 did
, u32
*data
)
149 p80211msg_dot11req_mibset_t msg
;
150 p80211item_uint32_t
*mibitem
=
151 (p80211item_uint32_t
*)&msg
.mibattribute
.data
;
154 msg
.msgcode
= DIDmsg_dot11req_mibget
;
155 memset(mibitem
, 0, sizeof(*mibitem
));
157 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
159 *data
= mibitem
->data
;
164 static int p80211wext_autojoin(wlandevice_t
*wlandev
)
166 p80211msg_lnxreq_autojoin_t msg
;
167 struct iw_point data
;
168 char ssid
[IW_ESSID_MAX_SIZE
];
174 result
= p80211wext_giwessid(wlandev
->netdev
, NULL
, &data
, ssid
);
181 if (wlandev
->hostwep
& HOSTWEP_SHAREDKEY
)
182 msg
.authtype
.data
= P80211ENUM_authalg_sharedkey
;
184 msg
.authtype
.data
= P80211ENUM_authalg_opensystem
;
186 msg
.msgcode
= DIDmsg_lnxreq_autojoin
;
188 /* Trim the last '\0' to fit the SSID format */
190 if (data
.length
&& ssid
[data
.length
- 1] == '\0')
191 data
.length
= data
.length
- 1;
193 memcpy(msg
.ssid
.data
.data
, ssid
, data
.length
);
194 msg
.ssid
.data
.len
= data
.length
;
196 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
209 /* called by /proc/net/wireless */
210 struct iw_statistics
*p80211wext_get_wireless_stats(netdevice_t
*dev
)
212 p80211msg_lnxreq_commsquality_t quality
;
213 wlandevice_t
*wlandev
= dev
->ml_priv
;
214 struct iw_statistics
*wstats
= &wlandev
->wstats
;
218 if ((wlandev
== NULL
) || (wlandev
->msdstate
!= WLAN_MSD_RUNNING
))
221 /* XXX Only valid in station mode */
224 /* build request message */
225 quality
.msgcode
= DIDmsg_lnxreq_commsquality
;
226 quality
.dbm
.data
= P80211ENUM_truth_true
;
227 quality
.dbm
.status
= P80211ENUM_msgitem_status_data_ok
;
229 /* send message to nsd */
230 if (wlandev
->mlmerequest
== NULL
)
233 retval
= wlandev
->mlmerequest(wlandev
, (p80211msg_t
*) &quality
);
235 wstats
->qual
.qual
= qual_as_percent(quality
.link
.data
); /* overall link quality */
236 wstats
->qual
.level
= quality
.level
.data
; /* instant signal level */
237 wstats
->qual
.noise
= quality
.noise
.data
; /* instant noise level */
239 wstats
->qual
.updated
= IW_QUAL_ALL_UPDATED
| IW_QUAL_DBM
;
240 wstats
->discard
.code
= wlandev
->rx
.decrypt_err
;
241 wstats
->discard
.nwid
= 0;
242 wstats
->discard
.misc
= 0;
244 wstats
->discard
.fragment
= 0; /* incomplete fragments */
245 wstats
->discard
.retries
= 0; /* tx retries. */
246 wstats
->miss
.beacon
= 0;
251 static int p80211wext_giwname(netdevice_t
*dev
,
252 struct iw_request_info
*info
,
253 char *name
, char *extra
)
255 struct iw_param rate
;
259 result
= p80211wext_giwrate(dev
, NULL
, &rate
, NULL
);
266 switch (rate
.value
) {
269 strcpy(name
, "IEEE 802.11-DS");
273 strcpy(name
, "IEEE 802.11-b");
280 static int p80211wext_giwfreq(netdevice_t
*dev
,
281 struct iw_request_info
*info
,
282 struct iw_freq
*freq
, char *extra
)
284 wlandevice_t
*wlandev
= dev
->ml_priv
;
289 result
= p80211wext_getmib(wlandev
,
290 DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel
,
297 if (value
> NUM_CHANNELS
) {
302 /* convert into frequency instead of a channel */
304 freq
->m
= p80211_channel_to_mhz(value
, 0) * 100000;
310 static int p80211wext_siwfreq(netdevice_t
*dev
,
311 struct iw_request_info
*info
,
312 struct iw_freq
*freq
, char *extra
)
314 wlandevice_t
*wlandev
= dev
->ml_priv
;
319 if (!wlan_wext_write
) {
324 if ((freq
->e
== 0) && (freq
->m
<= 1000))
327 value
= p80211_mhz_to_channel(freq
->m
);
329 result
= p80211wext_setmib(wlandev
,
330 DIDmib_dot11phy_dot11PhyDSSSTable_dot11CurrentChannel
,
342 static int p80211wext_giwmode(netdevice_t
*dev
,
343 struct iw_request_info
*info
,
344 __u32
*mode
, char *extra
)
346 wlandevice_t
*wlandev
= dev
->ml_priv
;
348 switch (wlandev
->macmode
) {
349 case WLAN_MACMODE_IBSS_STA
:
350 *mode
= IW_MODE_ADHOC
;
352 case WLAN_MACMODE_ESS_STA
:
353 *mode
= IW_MODE_INFRA
;
355 case WLAN_MACMODE_ESS_AP
:
356 *mode
= IW_MODE_MASTER
;
360 *mode
= IW_MODE_AUTO
;
366 static int p80211wext_siwmode(netdevice_t
*dev
,
367 struct iw_request_info
*info
,
368 __u32
*mode
, char *extra
)
370 wlandevice_t
*wlandev
= dev
->ml_priv
;
374 if (!wlan_wext_write
) {
379 if (*mode
!= IW_MODE_ADHOC
&& *mode
!= IW_MODE_INFRA
&&
380 *mode
!= IW_MODE_MASTER
) {
385 /* Operation mode is the same with current mode */
386 if (*mode
== wlandev
->macmode
)
391 wlandev
->macmode
= WLAN_MACMODE_IBSS_STA
;
394 wlandev
->macmode
= WLAN_MACMODE_ESS_STA
;
397 wlandev
->macmode
= WLAN_MACMODE_ESS_AP
;
401 printk(KERN_INFO
"Operation mode: %d not support\n", *mode
);
405 /* Set Operation mode to the PORT TYPE RID */
406 result
= p80211wext_setmib(wlandev
,
407 DIDmib_p2_p2Static_p2CnfPortType
,
408 (*mode
== IW_MODE_ADHOC
) ? 0 : 1);
415 static int p80211wext_giwrange(netdevice_t
*dev
,
416 struct iw_request_info
*info
,
417 struct iw_point
*data
, char *extra
)
419 struct iw_range
*range
= (struct iw_range
*)extra
;
422 /* for backward compatability set size and zero everything we don't understand */
423 data
->length
= sizeof(*range
);
424 memset(range
, 0, sizeof(*range
));
426 range
->txpower_capa
= IW_TXPOW_DBM
;
427 /* XXX what about min/max_pmp, min/max_pmt, etc. */
429 range
->we_version_compiled
= WIRELESS_EXT
;
430 range
->we_version_source
= 13;
432 range
->retry_capa
= IW_RETRY_LIMIT
;
433 range
->retry_flags
= IW_RETRY_LIMIT
;
434 range
->min_retry
= 0;
435 range
->max_retry
= 255;
437 range
->event_capa
[0] = (IW_EVENT_CAPA_K_0
| /* mode/freq/ssid */
438 IW_EVENT_CAPA_MASK(SIOCGIWAP
) |
439 IW_EVENT_CAPA_MASK(SIOCGIWSCAN
));
440 range
->event_capa
[1] = IW_EVENT_CAPA_K_1
; /* encode */
441 range
->event_capa
[4] = (IW_EVENT_CAPA_MASK(IWEVQUAL
) |
442 IW_EVENT_CAPA_MASK(IWEVCUSTOM
));
444 range
->num_channels
= NUM_CHANNELS
;
446 /* XXX need to filter against the regulatory domain &| active set */
448 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
449 range
->freq
[val
].i
= i
+ 1;
450 range
->freq
[val
].m
= p80211wext_channel_freq
[i
] * 100000;
451 range
->freq
[val
].e
= 1;
455 range
->num_frequency
= val
;
457 /* Max of /proc/net/wireless */
458 range
->max_qual
.qual
= 100;
459 range
->max_qual
.level
= 0;
460 range
->max_qual
.noise
= 0;
461 range
->sensitivity
= 3;
462 /* XXX these need to be nsd-specific! */
465 range
->max_rts
= 2347;
466 range
->min_frag
= 256;
467 range
->max_frag
= 2346;
469 range
->max_encoding_tokens
= NUM_WEPKEYS
;
470 range
->num_encoding_sizes
= 2;
471 range
->encoding_size
[0] = 5;
472 range
->encoding_size
[1] = 13;
474 /* XXX what about num_bitrates/throughput? */
475 range
->num_bitrates
= 0;
477 /* estimated max throughput */
478 /* XXX need to cap it if we're running at ~2Mbps.. */
479 range
->throughput
= 5500000;
484 static int p80211wext_giwap(netdevice_t
*dev
,
485 struct iw_request_info
*info
,
486 struct sockaddr
*ap_addr
, char *extra
)
489 wlandevice_t
*wlandev
= dev
->ml_priv
;
491 memcpy(ap_addr
->sa_data
, wlandev
->bssid
, WLAN_BSSID_LEN
);
492 ap_addr
->sa_family
= ARPHRD_ETHER
;
497 static int p80211wext_giwencode(netdevice_t
*dev
,
498 struct iw_request_info
*info
,
499 struct iw_point
*erq
, char *key
)
501 wlandevice_t
*wlandev
= dev
->ml_priv
;
505 i
= (erq
->flags
& IW_ENCODE_INDEX
) - 1;
508 if (wlandev
->hostwep
& HOSTWEP_PRIVACYINVOKED
)
509 erq
->flags
|= IW_ENCODE_ENABLED
;
511 erq
->flags
|= IW_ENCODE_DISABLED
;
513 if (wlandev
->hostwep
& HOSTWEP_EXCLUDEUNENCRYPTED
)
514 erq
->flags
|= IW_ENCODE_RESTRICTED
;
516 erq
->flags
|= IW_ENCODE_OPEN
;
518 i
= (erq
->flags
& IW_ENCODE_INDEX
) - 1;
521 i
= wlandev
->hostwep
& HOSTWEP_DEFAULTKEY_MASK
;
523 if ((i
< 0) || (i
>= NUM_WEPKEYS
)) {
530 /* copy the key from the driver cache as the keys are read-only MIBs */
531 erq
->length
= wlandev
->wep_keylens
[i
];
532 memcpy(key
, wlandev
->wep_keys
[i
], erq
->length
);
538 static int p80211wext_siwencode(netdevice_t
*dev
,
539 struct iw_request_info
*info
,
540 struct iw_point
*erq
, char *key
)
542 wlandevice_t
*wlandev
= dev
->ml_priv
;
543 p80211msg_dot11req_mibset_t msg
;
544 p80211item_pstr32_t pstr
;
550 if (!wlan_wext_write
) {
555 /* Check the Key index first. */
556 i
= (erq
->flags
& IW_ENCODE_INDEX
);
558 if ((i
< 1) || (i
> NUM_WEPKEYS
)) {
564 /* Set current key number only if no keys are given */
565 if (erq
->flags
& IW_ENCODE_NOKEY
) {
567 p80211wext_setmib(wlandev
,
568 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID
,
578 /* Use defaultkey if no Key Index */
579 i
= wlandev
->hostwep
& HOSTWEP_DEFAULTKEY_MASK
;
582 /* Check if there is no key information in the iwconfig request */
583 if ((erq
->flags
& IW_ENCODE_NOKEY
) == 0) {
585 /*------------------------------------------------------------
586 * If there is WEP Key for setting, check the Key Information
587 * and then set it to the firmware.
588 -------------------------------------------------------------*/
590 if (erq
->length
> 0) {
591 /* copy the key from the driver cache as the keys are read-only MIBs */
592 wlandev
->wep_keylens
[i
] = erq
->length
;
593 memcpy(wlandev
->wep_keys
[i
], key
, erq
->length
);
595 /* Prepare data struture for p80211req_dorequest. */
596 memcpy(pstr
.data
.data
, key
, erq
->length
);
597 pstr
.data
.len
= erq
->length
;
602 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0
;
607 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1
;
612 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2
;
617 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3
;
625 msg
.msgcode
= DIDmsg_dot11req_mibset
;
626 memcpy(&msg
.mibattribute
.data
, &pstr
, sizeof(pstr
));
627 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
637 /* Check the PrivacyInvoked flag */
638 if (erq
->flags
& IW_ENCODE_DISABLED
) {
640 p80211wext_setmib(wlandev
,
641 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked
,
642 P80211ENUM_truth_false
);
645 p80211wext_setmib(wlandev
,
646 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked
,
647 P80211ENUM_truth_true
);
655 /* The security mode may be open or restricted, and its meaning
656 depends on the card used. With most cards, in open mode no
657 authentication is used and the card may also accept non-
658 encrypted sessions, whereas in restricted mode only encrypted
659 sessions are accepted and the card will use authentication if
662 if (erq
->flags
& IW_ENCODE_RESTRICTED
) {
664 p80211wext_setmib(wlandev
,
665 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted
,
666 P80211ENUM_truth_true
);
667 } else if (erq
->flags
& IW_ENCODE_OPEN
) {
669 p80211wext_setmib(wlandev
,
670 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted
,
671 P80211ENUM_truth_false
);
684 static int p80211wext_giwessid(netdevice_t
*dev
,
685 struct iw_request_info
*info
,
686 struct iw_point
*data
, char *essid
)
688 wlandevice_t
*wlandev
= dev
->ml_priv
;
690 if (wlandev
->ssid
.len
) {
691 data
->length
= wlandev
->ssid
.len
;
693 memcpy(essid
, wlandev
->ssid
.data
, data
->length
);
694 essid
[data
->length
] = 0;
696 memset(essid
, 0, sizeof(wlandev
->ssid
.data
));
704 static int p80211wext_siwessid(netdevice_t
*dev
,
705 struct iw_request_info
*info
,
706 struct iw_point
*data
, char *essid
)
708 wlandevice_t
*wlandev
= dev
->ml_priv
;
709 p80211msg_lnxreq_autojoin_t msg
;
713 int length
= data
->length
;
715 if (!wlan_wext_write
) {
720 if (wlandev
->hostwep
& HOSTWEP_SHAREDKEY
)
721 msg
.authtype
.data
= P80211ENUM_authalg_sharedkey
;
723 msg
.authtype
.data
= P80211ENUM_authalg_opensystem
;
725 msg
.msgcode
= DIDmsg_lnxreq_autojoin
;
727 /* Trim the last '\0' to fit the SSID format */
728 if (length
&& essid
[length
- 1] == '\0')
731 memcpy(msg
.ssid
.data
.data
, essid
, length
);
732 msg
.ssid
.data
.len
= length
;
734 pr_debug("autojoin_ssid for %s \n", essid
);
735 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
736 pr_debug("autojoin_ssid %d\n", result
);
747 static int p80211wext_siwcommit(netdevice_t
*dev
,
748 struct iw_request_info
*info
,
749 struct iw_point
*data
, char *essid
)
751 wlandevice_t
*wlandev
= dev
->ml_priv
;
754 if (!wlan_wext_write
) {
760 err
= p80211wext_autojoin(wlandev
);
766 static int p80211wext_giwrate(netdevice_t
*dev
,
767 struct iw_request_info
*info
,
768 struct iw_param
*rrq
, char *extra
)
770 wlandevice_t
*wlandev
= dev
->ml_priv
;
775 result
= p80211wext_getmib(wlandev
, DIDmib_p2_p2MAC_p2CurrentTxRate
, &value
);
781 rrq
->fixed
= 0; /* can it change? */
785 #define HFA384x_RATEBIT_1 ((u16)1)
786 #define HFA384x_RATEBIT_2 ((u16)2)
787 #define HFA384x_RATEBIT_5dot5 ((u16)4)
788 #define HFA384x_RATEBIT_11 ((u16)8)
791 case HFA384x_RATEBIT_1
:
792 rrq
->value
= 1000000;
794 case HFA384x_RATEBIT_2
:
795 rrq
->value
= 2000000;
797 case HFA384x_RATEBIT_5dot5
:
798 rrq
->value
= 5500000;
800 case HFA384x_RATEBIT_11
:
801 rrq
->value
= 11000000;
810 static int p80211wext_giwrts(netdevice_t
*dev
,
811 struct iw_request_info
*info
,
812 struct iw_param
*rts
, char *extra
)
814 wlandevice_t
*wlandev
= dev
->ml_priv
;
819 result
= p80211wext_getmib(wlandev
,
820 DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold
,
828 rts
->disabled
= (rts
->value
== 2347);
835 static int p80211wext_siwrts(netdevice_t
*dev
,
836 struct iw_request_info
*info
,
837 struct iw_param
*rts
, char *extra
)
839 wlandevice_t
*wlandev
= dev
->ml_priv
;
844 if (!wlan_wext_write
) {
854 result
= p80211wext_setmib(wlandev
,
855 DIDmib_dot11mac_dot11OperationTable_dot11RTSThreshold
,
866 static int p80211wext_giwfrag(netdevice_t
*dev
,
867 struct iw_request_info
*info
,
868 struct iw_param
*frag
, char *extra
)
870 wlandevice_t
*wlandev
= dev
->ml_priv
;
875 result
= p80211wext_getmib(wlandev
,
876 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold
,
884 frag
->disabled
= (frag
->value
== 2346);
891 static int p80211wext_siwfrag(netdevice_t
*dev
,
892 struct iw_request_info
*info
,
893 struct iw_param
*frag
, char *extra
)
895 wlandevice_t
*wlandev
= dev
->ml_priv
;
900 if (!wlan_wext_write
) {
910 result
= p80211wext_setmib(wlandev
,
911 DIDmib_dot11mac_dot11OperationTable_dot11FragmentationThreshold
,
923 #ifndef IW_RETRY_LONG
924 #define IW_RETRY_LONG IW_RETRY_MAX
927 #ifndef IW_RETRY_SHORT
928 #define IW_RETRY_SHORT IW_RETRY_MIN
931 static int p80211wext_giwretry(netdevice_t
*dev
,
932 struct iw_request_info
*info
,
933 struct iw_param
*rrq
, char *extra
)
935 wlandevice_t
*wlandev
= dev
->ml_priv
;
938 u16 shortretry
, longretry
, lifetime
;
941 result
= p80211wext_getmib(wlandev
,
942 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit
,
951 result
= p80211wext_getmib(wlandev
,
952 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit
,
961 result
= p80211wext_getmib(wlandev
,
962 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime
,
973 if ((rrq
->flags
& IW_RETRY_TYPE
) == IW_RETRY_LIFETIME
) {
974 rrq
->flags
= IW_RETRY_LIFETIME
;
975 rrq
->value
= lifetime
* 1024;
977 if (rrq
->flags
& IW_RETRY_LONG
) {
978 rrq
->flags
= IW_RETRY_LIMIT
| IW_RETRY_LONG
;
979 rrq
->value
= longretry
;
981 rrq
->flags
= IW_RETRY_LIMIT
;
982 rrq
->value
= shortretry
;
983 if (shortretry
!= longretry
)
984 rrq
->flags
|= IW_RETRY_SHORT
;
993 static int p80211wext_siwretry(netdevice_t
*dev
,
994 struct iw_request_info
*info
,
995 struct iw_param
*rrq
, char *extra
)
997 wlandevice_t
*wlandev
= dev
->ml_priv
;
998 p80211item_uint32_t mibitem
;
999 p80211msg_dot11req_mibset_t msg
;
1004 if (!wlan_wext_write
) {
1005 err
= (-EOPNOTSUPP
);
1009 if (rrq
->disabled
) {
1014 msg
.msgcode
= DIDmsg_dot11req_mibset
;
1016 if ((rrq
->flags
& IW_RETRY_TYPE
) == IW_RETRY_LIFETIME
) {
1018 value
= rrq
->value
/= 1024;
1019 result
= p80211wext_setmib(wlandev
,
1020 DIDmib_dot11mac_dot11OperationTable_dot11MaxTransmitMSDULifetime
,
1027 if (rrq
->flags
& IW_RETRY_LONG
) {
1028 result
= p80211wext_setmib(wlandev
,
1029 DIDmib_dot11mac_dot11OperationTable_dot11LongRetryLimit
,
1038 if (rrq
->flags
& IW_RETRY_SHORT
) {
1039 result
= p80211wext_setmib(wlandev
,
1040 DIDmib_dot11mac_dot11OperationTable_dot11ShortRetryLimit
,
1055 static int p80211wext_siwtxpow(netdevice_t
*dev
,
1056 struct iw_request_info
*info
,
1057 struct iw_param
*rrq
, char *extra
)
1059 wlandevice_t
*wlandev
= dev
->ml_priv
;
1060 p80211item_uint32_t mibitem
;
1061 p80211msg_dot11req_mibset_t msg
;
1066 if (!wlan_wext_write
) {
1067 err
= (-EOPNOTSUPP
);
1071 if (rrq
->fixed
== 0)
1075 result
= p80211wext_setmib(wlandev
,
1076 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel
,
1088 static int p80211wext_giwtxpow(netdevice_t
*dev
,
1089 struct iw_request_info
*info
,
1090 struct iw_param
*rrq
, char *extra
)
1092 wlandevice_t
*wlandev
= dev
->ml_priv
;
1097 result
= p80211wext_getmib(wlandev
,
1098 DIDmib_dot11phy_dot11PhyTxPowerTable_dot11CurrentTxPowerLevel
,
1106 /* XXX handle OFF by setting disabled = 1; */
1108 rrq
->flags
= 0; /* IW_TXPOW_DBM; */
1117 static int p80211wext_siwspy(netdevice_t
*dev
,
1118 struct iw_request_info
*info
,
1119 struct iw_point
*srq
, char *extra
)
1121 wlandevice_t
*wlandev
= dev
->ml_priv
;
1122 struct sockaddr address
[IW_MAX_SPY
];
1123 int number
= srq
->length
;
1126 /* Copy the data from the input buffer */
1127 memcpy(address
, extra
, sizeof(struct sockaddr
) * number
);
1129 wlandev
->spy_number
= 0;
1133 /* extract the addresses */
1134 for (i
= 0; i
< number
; i
++) {
1136 memcpy(wlandev
->spy_address
[i
], address
[i
].sa_data
,
1141 memset(wlandev
->spy_stat
, 0,
1142 sizeof(struct iw_quality
) * IW_MAX_SPY
);
1144 /* set number of addresses */
1145 wlandev
->spy_number
= number
;
1151 /* jkriegl: from orinoco, modified */
1152 static int p80211wext_giwspy(netdevice_t
*dev
,
1153 struct iw_request_info
*info
,
1154 struct iw_point
*srq
, char *extra
)
1156 wlandevice_t
*wlandev
= dev
->ml_priv
;
1158 struct sockaddr address
[IW_MAX_SPY
];
1159 struct iw_quality spy_stat
[IW_MAX_SPY
];
1163 number
= wlandev
->spy_number
;
1167 /* populate address and spy struct's */
1168 for (i
= 0; i
< number
; i
++) {
1169 memcpy(address
[i
].sa_data
, wlandev
->spy_address
[i
],
1171 address
[i
].sa_family
= AF_UNIX
;
1172 memcpy(&spy_stat
[i
], &wlandev
->spy_stat
[i
],
1173 sizeof(struct iw_quality
));
1176 /* reset update flag */
1177 for (i
= 0; i
< number
; i
++)
1178 wlandev
->spy_stat
[i
].updated
= 0;
1181 /* push stuff to user space */
1182 srq
->length
= number
;
1183 memcpy(extra
, address
, sizeof(struct sockaddr
) * number
);
1184 memcpy(extra
+ sizeof(struct sockaddr
) * number
, spy_stat
,
1185 sizeof(struct iw_quality
) * number
);
1190 static int prism2_result2err(int prism2_result
)
1194 switch (prism2_result
) {
1195 case P80211ENUM_resultcode_invalid_parameters
:
1198 case P80211ENUM_resultcode_implementation_failure
:
1201 case P80211ENUM_resultcode_not_supported
:
1212 static int p80211wext_siwscan(netdevice_t
*dev
,
1213 struct iw_request_info
*info
,
1214 struct iw_point
*srq
, char *extra
)
1216 wlandevice_t
*wlandev
= dev
->ml_priv
;
1217 p80211msg_dot11req_scan_t msg
;
1222 if (wlandev
->macmode
== WLAN_MACMODE_ESS_AP
) {
1223 printk(KERN_ERR
"Can't scan in AP mode\n");
1224 err
= (-EOPNOTSUPP
);
1228 memset(&msg
, 0x00, sizeof(p80211msg_dot11req_scan_t
));
1229 msg
.msgcode
= DIDmsg_dot11req_scan
;
1230 msg
.bsstype
.data
= P80211ENUM_bsstype_any
;
1232 memset(&(msg
.bssid
.data
), 0xFF, sizeof(p80211item_pstr6_t
));
1233 msg
.bssid
.data
.len
= 6;
1235 msg
.scantype
.data
= P80211ENUM_scantype_active
;
1236 msg
.probedelay
.data
= 0;
1238 for (i
= 1; i
<= 14; i
++)
1239 msg
.channellist
.data
.data
[i
- 1] = i
;
1240 msg
.channellist
.data
.len
= 14;
1242 msg
.maxchanneltime
.data
= 250;
1243 msg
.minchanneltime
.data
= 200;
1245 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
1247 err
= prism2_result2err(msg
.resultcode
.data
);
1253 /* Helper to translate scan into Wireless Extensions scan results.
1254 * Inspired by the prism54 code, which was in turn inspired by the
1257 static char *wext_translate_bss(struct iw_request_info
*info
, char *current_ev
,
1259 p80211msg_dot11req_scan_results_t
*bss
)
1261 struct iw_event iwe
; /* Temporary buffer */
1263 /* The first entry must be the MAC address */
1264 memcpy(iwe
.u
.ap_addr
.sa_data
, bss
->bssid
.data
.data
, WLAN_BSSID_LEN
);
1265 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1266 iwe
.cmd
= SIOCGIWAP
;
1268 iwe_stream_add_event(info
, current_ev
, end_buf
, &iwe
,
1271 /* The following entries will be displayed in the same order we give them */
1274 if (bss
->ssid
.data
.len
> 0) {
1275 char essid
[IW_ESSID_MAX_SIZE
+ 1];
1279 min_t(unsigned short, IW_ESSID_MAX_SIZE
,
1280 bss
->ssid
.data
.len
);
1281 memset(&essid
, 0, sizeof(essid
));
1282 memcpy(&essid
, bss
->ssid
.data
.data
, size
);
1283 pr_debug(" essid size = %d\n", size
);
1284 iwe
.u
.data
.length
= size
;
1285 iwe
.u
.data
.flags
= 1;
1286 iwe
.cmd
= SIOCGIWESSID
;
1288 iwe_stream_add_point(info
, current_ev
, end_buf
, &iwe
,
1290 pr_debug(" essid size OK.\n");
1293 switch (bss
->bsstype
.data
) {
1294 case P80211ENUM_bsstype_infrastructure
:
1295 iwe
.u
.mode
= IW_MODE_MASTER
;
1298 case P80211ENUM_bsstype_independent
:
1299 iwe
.u
.mode
= IW_MODE_ADHOC
;
1306 iwe
.cmd
= SIOCGIWMODE
;
1309 iwe_stream_add_event(info
, current_ev
, end_buf
, &iwe
,
1312 /* Encryption capability */
1313 if (bss
->privacy
.data
== P80211ENUM_truth_true
)
1314 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
1316 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
1317 iwe
.u
.data
.length
= 0;
1318 iwe
.cmd
= SIOCGIWENCODE
;
1320 iwe_stream_add_point(info
, current_ev
, end_buf
, &iwe
, NULL
);
1322 /* Add frequency. (short) bss->channel is the frequency in MHz */
1323 iwe
.u
.freq
.m
= bss
->dschannel
.data
;
1325 iwe
.cmd
= SIOCGIWFREQ
;
1327 iwe_stream_add_event(info
, current_ev
, end_buf
, &iwe
,
1330 /* Add quality statistics */
1331 iwe
.u
.qual
.level
= bss
->signal
.data
;
1332 iwe
.u
.qual
.noise
= bss
->noise
.data
;
1333 /* do a simple SNR for quality */
1334 iwe
.u
.qual
.qual
= qual_as_percent(bss
->signal
.data
- bss
->noise
.data
);
1337 iwe_stream_add_event(info
, current_ev
, end_buf
, &iwe
,
1343 static int p80211wext_giwscan(netdevice_t
*dev
,
1344 struct iw_request_info
*info
,
1345 struct iw_point
*srq
, char *extra
)
1347 wlandevice_t
*wlandev
= dev
->ml_priv
;
1348 p80211msg_dot11req_scan_results_t msg
;
1353 char *current_ev
= extra
;
1355 /* Since wireless tools doesn't really have a way of passing how
1356 * many scan results results there were back here, keep grabbing them
1360 memset(&msg
, 0, sizeof(msg
));
1361 msg
.msgcode
= DIDmsg_dot11req_scan_results
;
1362 msg
.bssindex
.data
= i
;
1364 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
1365 if ((result
!= 0) ||
1366 (msg
.resultcode
.data
!= P80211ENUM_resultcode_success
)) {
1371 wext_translate_bss(info
, current_ev
,
1372 extra
+ IW_SCAN_MAX_DATA
, &msg
);
1375 } while (i
< IW_MAX_AP
);
1377 srq
->length
= (current_ev
- extra
);
1378 srq
->flags
= 0; /* todo */
1380 if (result
&& !scan_good
)
1381 err
= prism2_result2err(msg
.resultcode
.data
);
1386 /* extra wireless extensions stuff to support NetworkManager (I hope) */
1388 /* SIOCSIWENCODEEXT */
1389 static int p80211wext_set_encodeext(struct net_device
*dev
,
1390 struct iw_request_info
*info
,
1391 union iwreq_data
*wrqu
, char *extra
)
1393 wlandevice_t
*wlandev
= dev
->ml_priv
;
1394 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
1395 p80211msg_dot11req_mibset_t msg
;
1396 p80211item_pstr32_t
*pstr
;
1399 struct iw_point
*encoding
= &wrqu
->encoding
;
1400 int idx
= encoding
->flags
& IW_ENCODE_INDEX
;
1402 pr_debug("set_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1403 ext
->ext_flags
, (int)ext
->alg
, (int)ext
->key_len
);
1405 if (ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) {
1406 /* set default key ? I'm not sure if this the the correct thing to do here */
1409 if (idx
< 1 || idx
> NUM_WEPKEYS
)
1414 pr_debug("setting default key (%d)\n", idx
);
1416 p80211wext_setmib(wlandev
,
1417 DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID
,
1423 if (ext
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
1424 if (ext
->alg
!= IW_ENCODE_ALG_WEP
) {
1425 pr_debug("asked to set a non wep key :(\n");
1429 if (idx
< 1 || idx
> NUM_WEPKEYS
)
1434 pr_debug("Set WEP key (%d)\n", idx
);
1435 wlandev
->wep_keylens
[idx
] = ext
->key_len
;
1436 memcpy(wlandev
->wep_keys
[idx
], ext
->key
, ext
->key_len
);
1438 memset(&msg
, 0, sizeof(msg
));
1439 pstr
= (p80211item_pstr32_t
*) &msg
.mibattribute
.data
;
1440 memcpy(pstr
->data
.data
, ext
->key
, ext
->key_len
);
1441 pstr
->data
.len
= ext
->key_len
;
1445 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0
;
1449 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1
;
1453 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2
;
1457 DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3
;
1462 msg
.msgcode
= DIDmsg_dot11req_mibset
;
1463 result
= p80211req_dorequest(wlandev
, (u8
*) &msg
);
1464 pr_debug("result (%d)\n", result
);
1469 /* SIOCGIWENCODEEXT */
1470 static int p80211wext_get_encodeext(struct net_device
*dev
,
1471 struct iw_request_info
*info
,
1472 union iwreq_data
*wrqu
, char *extra
)
1474 wlandevice_t
*wlandev
= dev
->ml_priv
;
1475 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
1477 struct iw_point
*encoding
= &wrqu
->encoding
;
1482 pr_debug("get_encode_ext flags[%d] alg[%d] keylen[%d]\n",
1483 ext
->ext_flags
, (int)ext
->alg
, (int)ext
->key_len
);
1485 max_len
= encoding
->length
- sizeof(*ext
);
1487 pr_debug("get_encodeext max_len [%d] invalid\n", max_len
);
1491 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
1493 pr_debug("get_encode_ext index [%d]\n", idx
);
1496 if (idx
< 1 || idx
> NUM_WEPKEYS
) {
1497 pr_debug("get_encode_ext invalid key index [%d]\n",
1504 /* default key ? not sure what to do */
1505 /* will just use key[0] for now ! FIX ME */
1508 encoding
->flags
= idx
+ 1;
1509 memset(ext
, 0, sizeof(*ext
));
1511 ext
->alg
= IW_ENCODE_ALG_WEP
;
1512 ext
->key_len
= wlandev
->wep_keylens
[idx
];
1513 memcpy(ext
->key
, wlandev
->wep_keys
[idx
], ext
->key_len
);
1515 encoding
->flags
|= IW_ENCODE_ENABLED
;
1521 static int p80211_wext_set_iwauth(struct net_device
*dev
,
1522 struct iw_request_info
*info
,
1523 union iwreq_data
*wrqu
, char *extra
)
1525 wlandevice_t
*wlandev
= dev
->ml_priv
;
1526 struct iw_param
*param
= &wrqu
->param
;
1529 pr_debug("set_iwauth flags[%d]\n", (int)param
->flags
& IW_AUTH_INDEX
);
1531 switch (param
->flags
& IW_AUTH_INDEX
) {
1532 case IW_AUTH_DROP_UNENCRYPTED
:
1533 pr_debug("drop_unencrypted %d\n", param
->value
);
1536 p80211wext_setmib(wlandev
,
1537 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted
,
1538 P80211ENUM_truth_true
);
1541 p80211wext_setmib(wlandev
,
1542 DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted
,
1543 P80211ENUM_truth_false
);
1546 case IW_AUTH_PRIVACY_INVOKED
:
1547 pr_debug("privacy invoked %d\n", param
->value
);
1550 p80211wext_setmib(wlandev
,
1551 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked
,
1552 P80211ENUM_truth_true
);
1555 p80211wext_setmib(wlandev
,
1556 DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked
,
1557 P80211ENUM_truth_false
);
1561 case IW_AUTH_80211_AUTH_ALG
:
1562 if (param
->value
& IW_AUTH_ALG_OPEN_SYSTEM
) {
1563 pr_debug("set open_system\n");
1564 wlandev
->hostwep
&= ~HOSTWEP_SHAREDKEY
;
1565 } else if (param
->value
& IW_AUTH_ALG_SHARED_KEY
) {
1566 pr_debug("set shared key\n");
1567 wlandev
->hostwep
|= HOSTWEP_SHAREDKEY
;
1569 /* don't know what to do know */
1570 pr_debug("unknown AUTH_ALG (%d)\n", param
->value
);
1583 static int p80211_wext_get_iwauth(struct net_device
*dev
,
1584 struct iw_request_info
*info
,
1585 union iwreq_data
*wrqu
, char *extra
)
1587 wlandevice_t
*wlandev
= dev
->ml_priv
;
1588 struct iw_param
*param
= &wrqu
->param
;
1591 pr_debug("get_iwauth flags[%d]\n", (int)param
->flags
& IW_AUTH_INDEX
);
1593 switch (param
->flags
& IW_AUTH_INDEX
) {
1594 case IW_AUTH_DROP_UNENCRYPTED
:
1596 wlandev
->hostwep
& HOSTWEP_EXCLUDEUNENCRYPTED
? 1 : 0;
1599 case IW_AUTH_PRIVACY_INVOKED
:
1601 wlandev
->hostwep
& HOSTWEP_PRIVACYINVOKED
? 1 : 0;
1604 case IW_AUTH_80211_AUTH_ALG
:
1606 wlandev
->hostwep
& HOSTWEP_SHAREDKEY
?
1607 IW_AUTH_ALG_SHARED_KEY
: IW_AUTH_ALG_OPEN_SYSTEM
;
1617 #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT]
1619 static iw_handler p80211wext_handlers
[] = {
1620 IW_IOCTL(SIOCSIWCOMMIT
) = (iw_handler
) p80211wext_siwcommit
,
1621 IW_IOCTL(SIOCGIWNAME
) = (iw_handler
) p80211wext_giwname
,
1622 /* SIOCSIWNWID,SIOCGIWNWID */
1623 IW_IOCTL(SIOCSIWFREQ
) = (iw_handler
) p80211wext_siwfreq
,
1624 IW_IOCTL(SIOCGIWFREQ
) = (iw_handler
) p80211wext_giwfreq
,
1625 IW_IOCTL(SIOCSIWMODE
) = (iw_handler
) p80211wext_siwmode
,
1626 IW_IOCTL(SIOCGIWMODE
) = (iw_handler
) p80211wext_giwmode
,
1627 /* SIOCSIWSENS,SIOCGIWSENS,SIOCSIWRANGE */
1628 IW_IOCTL(SIOCGIWRANGE
) = (iw_handler
) p80211wext_giwrange
,
1629 /* SIOCSIWPRIV,SIOCGIWPRIV,SIOCSIWSTATS,SIOCGIWSTATS */
1630 IW_IOCTL(SIOCSIWSPY
) = (iw_handler
) p80211wext_siwspy
,
1631 IW_IOCTL(SIOCGIWSPY
) = (iw_handler
) p80211wext_giwspy
,
1633 IW_IOCTL(SIOCGIWAP
) = (iw_handler
) p80211wext_giwap
,
1635 IW_IOCTL(SIOCSIWSCAN
) = (iw_handler
) p80211wext_siwscan
,
1636 IW_IOCTL(SIOCGIWSCAN
) = (iw_handler
) p80211wext_giwscan
,
1637 IW_IOCTL(SIOCSIWESSID
) = (iw_handler
) p80211wext_siwessid
,
1638 IW_IOCTL(SIOCGIWESSID
) = (iw_handler
) p80211wext_giwessid
,
1640 IW_IOCTL(SIOCGIWNICKN
) = (iw_handler
) p80211wext_giwessid
,
1642 IW_IOCTL(SIOCGIWRATE
) = (iw_handler
) p80211wext_giwrate
,
1643 IW_IOCTL(SIOCSIWRTS
) = (iw_handler
) p80211wext_siwrts
,
1644 IW_IOCTL(SIOCGIWRTS
) = (iw_handler
) p80211wext_giwrts
,
1645 IW_IOCTL(SIOCSIWFRAG
) = (iw_handler
) p80211wext_siwfrag
,
1646 IW_IOCTL(SIOCGIWFRAG
) = (iw_handler
) p80211wext_giwfrag
,
1647 IW_IOCTL(SIOCSIWTXPOW
) = (iw_handler
) p80211wext_siwtxpow
,
1648 IW_IOCTL(SIOCGIWTXPOW
) = (iw_handler
) p80211wext_giwtxpow
,
1649 IW_IOCTL(SIOCSIWRETRY
) = (iw_handler
) p80211wext_siwretry
,
1650 IW_IOCTL(SIOCGIWRETRY
) = (iw_handler
) p80211wext_giwretry
,
1651 IW_IOCTL(SIOCSIWENCODE
) = (iw_handler
) p80211wext_siwencode
,
1652 IW_IOCTL(SIOCGIWENCODE
) = (iw_handler
) p80211wext_giwencode
,
1653 /* SIOCSIWPOWER,SIOCGIWPOWER */
1654 /* WPA operations */
1655 /* SIOCSIWGENIE,SIOCGIWGENIE generic IE */
1656 IW_IOCTL(SIOCSIWAUTH
) = (iw_handler
) p80211_wext_set_iwauth
, /*set authentication mode params */
1657 IW_IOCTL(SIOCGIWAUTH
) = (iw_handler
) p80211_wext_get_iwauth
, /*get authentication mode params */
1658 IW_IOCTL(SIOCSIWENCODEEXT
) = (iw_handler
) p80211wext_set_encodeext
, /*set encoding token & mode */
1659 IW_IOCTL(SIOCGIWENCODEEXT
) = (iw_handler
) p80211wext_get_encodeext
, /*get encoding token & mode */
1660 /* SIOCSIWPMKSA PMKSA cache operation */
1663 struct iw_handler_def p80211wext_handler_def
= {
1664 .num_standard
= ARRAY_SIZE(p80211wext_handlers
),
1665 .standard
= p80211wext_handlers
,
1666 .get_wireless_stats
= p80211wext_get_wireless_stats
1669 int p80211wext_event_associated(wlandevice_t
*wlandev
, int assoc
)
1671 union iwreq_data data
;
1673 /* Send the association state first */
1674 data
.ap_addr
.sa_family
= ARPHRD_ETHER
;
1676 memcpy(data
.ap_addr
.sa_data
, wlandev
->bssid
, ETH_ALEN
);
1678 memset(data
.ap_addr
.sa_data
, 0, ETH_ALEN
);
1680 if (wlan_wext_write
)
1681 wireless_send_event(wlandev
->netdev
, SIOCGIWAP
, &data
, NULL
);
1686 /* XXX send association data, like IEs, etc etc. */