2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/netdevice.h>
13 #include <linux/types.h>
14 #include <linux/slab.h>
15 #include <linux/skbuff.h>
16 #include <linux/etherdevice.h>
17 #include <linux/if_arp.h>
18 #include <linux/wireless.h>
19 #include <net/iw_handler.h>
20 #include <asm/uaccess.h>
22 #include <net/mac80211.h>
23 #include "ieee80211_i.h"
30 static int ieee80211_ioctl_siwgenie(struct net_device
*dev
,
31 struct iw_request_info
*info
,
32 struct iw_point
*data
, char *extra
)
34 struct ieee80211_sub_if_data
*sdata
;
36 sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
38 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
39 int ret
= ieee80211_sta_set_extra_ie(sdata
, extra
, data
->length
);
40 if (ret
&& ret
!= -EALREADY
)
42 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_AUTO_BSSID_SEL
;
43 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_EXT_SME
;
44 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_CONTROL_PORT
;
46 ieee80211_sta_req_auth(sdata
);
53 static int ieee80211_ioctl_siwfreq(struct net_device
*dev
,
54 struct iw_request_info
*info
,
55 struct iw_freq
*freq
, char *extra
)
57 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
59 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
60 return cfg80211_ibss_wext_siwfreq(dev
, info
, freq
, extra
);
61 else if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
)
62 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_AUTO_CHANNEL_SEL
;
64 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
67 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
)
69 IEEE80211_STA_AUTO_CHANNEL_SEL
;
72 return ieee80211_set_freq(sdata
,
73 ieee80211_channel_to_frequency(freq
->m
));
76 for (i
= 0; i
< freq
->e
; i
++)
79 return ieee80211_set_freq(sdata
, freq
->m
/ div
);
86 static int ieee80211_ioctl_giwfreq(struct net_device
*dev
,
87 struct iw_request_info
*info
,
88 struct iw_freq
*freq
, char *extra
)
90 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
91 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
93 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
94 return cfg80211_ibss_wext_giwfreq(dev
, info
, freq
, extra
);
96 freq
->m
= local
->oper_channel
->center_freq
;
103 static int ieee80211_ioctl_siwessid(struct net_device
*dev
,
104 struct iw_request_info
*info
,
105 struct iw_point
*data
, char *ssid
)
107 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
108 size_t len
= data
->length
;
111 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
112 return cfg80211_ibss_wext_siwessid(dev
, info
, data
, ssid
);
114 /* iwconfig uses nul termination in SSID.. */
115 if (len
> 0 && ssid
[len
- 1] == '\0')
118 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
120 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_AUTO_SSID_SEL
;
122 sdata
->u
.mgd
.flags
|= IEEE80211_STA_AUTO_SSID_SEL
;
124 ret
= ieee80211_sta_set_ssid(sdata
, ssid
, len
);
128 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_EXT_SME
;
129 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_CONTROL_PORT
;
130 ieee80211_sta_req_auth(sdata
);
138 static int ieee80211_ioctl_giwessid(struct net_device
*dev
,
139 struct iw_request_info
*info
,
140 struct iw_point
*data
, char *ssid
)
143 struct ieee80211_sub_if_data
*sdata
;
145 sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
147 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
148 return cfg80211_ibss_wext_giwessid(dev
, info
, data
, ssid
);
150 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
151 int res
= ieee80211_sta_get_ssid(sdata
, ssid
, &len
);
164 static int ieee80211_ioctl_siwap(struct net_device
*dev
,
165 struct iw_request_info
*info
,
166 struct sockaddr
*ap_addr
, char *extra
)
168 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
170 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
171 return cfg80211_ibss_wext_siwap(dev
, info
, ap_addr
, extra
);
173 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
176 if (is_zero_ether_addr((u8
*) &ap_addr
->sa_data
))
177 sdata
->u
.mgd
.flags
|= IEEE80211_STA_AUTO_BSSID_SEL
|
178 IEEE80211_STA_AUTO_CHANNEL_SEL
;
179 else if (is_broadcast_ether_addr((u8
*) &ap_addr
->sa_data
))
180 sdata
->u
.mgd
.flags
|= IEEE80211_STA_AUTO_BSSID_SEL
;
182 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_AUTO_BSSID_SEL
;
183 ret
= ieee80211_sta_set_bssid(sdata
, (u8
*) &ap_addr
->sa_data
);
186 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_EXT_SME
;
187 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_CONTROL_PORT
;
188 ieee80211_sta_req_auth(sdata
);
190 } else if (sdata
->vif
.type
== NL80211_IFTYPE_WDS
) {
192 * If it is necessary to update the WDS peer address
193 * while the interface is running, then we need to do
194 * more work here, namely if it is running we need to
195 * add a new and remove the old STA entry, this is
196 * normally handled by _open() and _stop().
198 if (netif_running(dev
))
201 memcpy(&sdata
->u
.wds
.remote_addr
, (u8
*) &ap_addr
->sa_data
,
211 static int ieee80211_ioctl_giwap(struct net_device
*dev
,
212 struct iw_request_info
*info
,
213 struct sockaddr
*ap_addr
, char *extra
)
215 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
217 if (sdata
->vif
.type
== NL80211_IFTYPE_ADHOC
)
218 return cfg80211_ibss_wext_giwap(dev
, info
, ap_addr
, extra
);
220 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
221 if (sdata
->u
.mgd
.state
== IEEE80211_STA_MLME_ASSOCIATED
) {
222 ap_addr
->sa_family
= ARPHRD_ETHER
;
223 memcpy(&ap_addr
->sa_data
, sdata
->u
.mgd
.bssid
, ETH_ALEN
);
225 memset(&ap_addr
->sa_data
, 0, ETH_ALEN
);
227 } else if (sdata
->vif
.type
== NL80211_IFTYPE_WDS
) {
228 ap_addr
->sa_family
= ARPHRD_ETHER
;
229 memcpy(&ap_addr
->sa_data
, sdata
->u
.wds
.remote_addr
, ETH_ALEN
);
237 static int ieee80211_ioctl_siwrate(struct net_device
*dev
,
238 struct iw_request_info
*info
,
239 struct iw_param
*rate
, char *extra
)
241 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
242 int i
, err
= -EINVAL
;
243 u32 target_rate
= rate
->value
/ 100000;
244 struct ieee80211_sub_if_data
*sdata
;
245 struct ieee80211_supported_band
*sband
;
247 sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
249 sband
= local
->hw
.wiphy
->bands
[local
->hw
.conf
.channel
->band
];
251 /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
252 * target_rate = X, rate->fixed = 1 means only rate X
253 * target_rate = X, rate->fixed = 0 means all rates <= X */
254 sdata
->max_ratectrl_rateidx
= -1;
255 sdata
->force_unicast_rateidx
= -1;
259 for (i
=0; i
< sband
->n_bitrates
; i
++) {
260 struct ieee80211_rate
*brate
= &sband
->bitrates
[i
];
261 int this_rate
= brate
->bitrate
;
263 if (target_rate
== this_rate
) {
264 sdata
->max_ratectrl_rateidx
= i
;
266 sdata
->force_unicast_rateidx
= i
;
274 static int ieee80211_ioctl_giwrate(struct net_device
*dev
,
275 struct iw_request_info
*info
,
276 struct iw_param
*rate
, char *extra
)
278 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
279 struct sta_info
*sta
;
280 struct ieee80211_sub_if_data
*sdata
;
281 struct ieee80211_supported_band
*sband
;
283 sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
285 if (sdata
->vif
.type
!= NL80211_IFTYPE_STATION
)
288 sband
= local
->hw
.wiphy
->bands
[local
->hw
.conf
.channel
->band
];
292 sta
= sta_info_get(local
, sdata
->u
.mgd
.bssid
);
294 if (sta
&& !(sta
->last_tx_rate
.flags
& IEEE80211_TX_RC_MCS
))
295 rate
->value
= sband
->bitrates
[sta
->last_tx_rate
.idx
].bitrate
;
304 rate
->value
*= 100000;
309 static int ieee80211_ioctl_siwpower(struct net_device
*dev
,
310 struct iw_request_info
*info
,
311 struct iw_param
*wrq
,
314 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
315 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
316 struct ieee80211_conf
*conf
= &local
->hw
.conf
;
320 if (!(local
->hw
.flags
& IEEE80211_HW_SUPPORTS_PS
))
323 if (sdata
->vif
.type
!= NL80211_IFTYPE_STATION
)
332 switch (wrq
->flags
& IW_POWER_MODE
) {
333 case IW_POWER_ON
: /* If not specified */
334 case IW_POWER_MODE
: /* If set all mask */
335 case IW_POWER_ALL_R
: /* If explicitely state all */
338 default: /* Otherwise we ignore */
342 if (wrq
->flags
& ~(IW_POWER_MODE
| IW_POWER_TIMEOUT
))
345 if (wrq
->flags
& IW_POWER_TIMEOUT
)
346 timeout
= wrq
->value
/ 1000;
349 if (ps
== sdata
->u
.mgd
.powersave
&& timeout
== conf
->dynamic_ps_timeout
)
352 sdata
->u
.mgd
.powersave
= ps
;
353 conf
->dynamic_ps_timeout
= timeout
;
355 if (local
->hw
.flags
& IEEE80211_HW_SUPPORTS_DYNAMIC_PS
)
356 ieee80211_hw_config(local
, IEEE80211_CONF_CHANGE_PS
);
358 ieee80211_recalc_ps(local
, -1);
363 static int ieee80211_ioctl_giwpower(struct net_device
*dev
,
364 struct iw_request_info
*info
,
365 union iwreq_data
*wrqu
,
368 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
370 wrqu
->power
.disabled
= !sdata
->u
.mgd
.powersave
;
375 static int ieee80211_ioctl_siwauth(struct net_device
*dev
,
376 struct iw_request_info
*info
,
377 struct iw_param
*data
, char *extra
)
379 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
382 switch (data
->flags
& IW_AUTH_INDEX
) {
383 case IW_AUTH_WPA_VERSION
:
384 case IW_AUTH_CIPHER_GROUP
:
385 case IW_AUTH_WPA_ENABLED
:
386 case IW_AUTH_RX_UNENCRYPTED_EAPOL
:
387 case IW_AUTH_KEY_MGMT
:
388 case IW_AUTH_CIPHER_GROUP_MGMT
:
390 case IW_AUTH_CIPHER_PAIRWISE
:
391 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
392 if (data
->value
& (IW_AUTH_CIPHER_WEP40
|
393 IW_AUTH_CIPHER_WEP104
| IW_AUTH_CIPHER_TKIP
))
394 sdata
->u
.mgd
.flags
|=
395 IEEE80211_STA_TKIP_WEP_USED
;
397 sdata
->u
.mgd
.flags
&=
398 ~IEEE80211_STA_TKIP_WEP_USED
;
401 case IW_AUTH_DROP_UNENCRYPTED
:
402 sdata
->drop_unencrypted
= !!data
->value
;
404 case IW_AUTH_PRIVACY_INVOKED
:
405 if (sdata
->vif
.type
!= NL80211_IFTYPE_STATION
)
408 sdata
->u
.mgd
.flags
&= ~IEEE80211_STA_PRIVACY_INVOKED
;
410 * Privacy invoked by wpa_supplicant, store the
411 * value and allow associating to a protected
412 * network without having a key up front.
415 sdata
->u
.mgd
.flags
|=
416 IEEE80211_STA_PRIVACY_INVOKED
;
419 case IW_AUTH_80211_AUTH_ALG
:
420 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
)
421 sdata
->u
.mgd
.auth_algs
= data
->value
;
426 if (!(sdata
->local
->hw
.flags
& IEEE80211_HW_MFP_CAPABLE
)) {
430 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
) {
431 switch (data
->value
) {
432 case IW_AUTH_MFP_DISABLED
:
433 sdata
->u
.mgd
.mfp
= IEEE80211_MFP_DISABLED
;
435 case IW_AUTH_MFP_OPTIONAL
:
436 sdata
->u
.mgd
.mfp
= IEEE80211_MFP_OPTIONAL
;
438 case IW_AUTH_MFP_REQUIRED
:
439 sdata
->u
.mgd
.mfp
= IEEE80211_MFP_REQUIRED
;
454 /* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
455 static struct iw_statistics
*ieee80211_get_wireless_stats(struct net_device
*dev
)
457 struct ieee80211_local
*local
= wdev_priv(dev
->ieee80211_ptr
);
458 struct iw_statistics
*wstats
= &local
->wstats
;
459 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
460 struct sta_info
*sta
= NULL
;
464 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
)
465 sta
= sta_info_get(local
, sdata
->u
.mgd
.bssid
);
468 wstats
->discard
.fragment
= 0;
469 wstats
->discard
.misc
= 0;
470 wstats
->qual
.qual
= 0;
471 wstats
->qual
.level
= 0;
472 wstats
->qual
.noise
= 0;
473 wstats
->qual
.updated
= IW_QUAL_ALL_INVALID
;
475 wstats
->qual
.updated
= 0;
477 * mirror what cfg80211 does for iwrange/scan results,
478 * otherwise userspace gets confused.
480 if (local
->hw
.flags
& (IEEE80211_HW_SIGNAL_UNSPEC
|
481 IEEE80211_HW_SIGNAL_DBM
)) {
482 wstats
->qual
.updated
|= IW_QUAL_LEVEL_UPDATED
;
483 wstats
->qual
.updated
|= IW_QUAL_QUAL_UPDATED
;
485 wstats
->qual
.updated
|= IW_QUAL_LEVEL_INVALID
;
486 wstats
->qual
.updated
|= IW_QUAL_QUAL_INVALID
;
489 if (local
->hw
.flags
& IEEE80211_HW_SIGNAL_UNSPEC
) {
490 wstats
->qual
.level
= sta
->last_signal
;
491 wstats
->qual
.qual
= sta
->last_signal
;
492 } else if (local
->hw
.flags
& IEEE80211_HW_SIGNAL_DBM
) {
493 int sig
= sta
->last_signal
;
495 wstats
->qual
.updated
|= IW_QUAL_DBM
;
496 wstats
->qual
.level
= sig
;
501 wstats
->qual
.qual
= sig
+ 110;
504 if (local
->hw
.flags
& IEEE80211_HW_NOISE_DBM
) {
506 * This assumes that if driver reports noise, it also
507 * reports signal in dBm.
509 wstats
->qual
.noise
= sta
->last_noise
;
510 wstats
->qual
.updated
|= IW_QUAL_NOISE_UPDATED
;
512 wstats
->qual
.updated
|= IW_QUAL_NOISE_INVALID
;
521 static int ieee80211_ioctl_giwauth(struct net_device
*dev
,
522 struct iw_request_info
*info
,
523 struct iw_param
*data
, char *extra
)
525 struct ieee80211_sub_if_data
*sdata
= IEEE80211_DEV_TO_SUB_IF(dev
);
528 switch (data
->flags
& IW_AUTH_INDEX
) {
529 case IW_AUTH_80211_AUTH_ALG
:
530 if (sdata
->vif
.type
== NL80211_IFTYPE_STATION
)
531 data
->value
= sdata
->u
.mgd
.auth_algs
;
543 /* Structures to export the Wireless Handlers */
545 static const iw_handler ieee80211_handler
[] =
547 (iw_handler
) NULL
, /* SIOCSIWCOMMIT */
548 (iw_handler
) cfg80211_wext_giwname
, /* SIOCGIWNAME */
549 (iw_handler
) NULL
, /* SIOCSIWNWID */
550 (iw_handler
) NULL
, /* SIOCGIWNWID */
551 (iw_handler
) ieee80211_ioctl_siwfreq
, /* SIOCSIWFREQ */
552 (iw_handler
) ieee80211_ioctl_giwfreq
, /* SIOCGIWFREQ */
553 (iw_handler
) cfg80211_wext_siwmode
, /* SIOCSIWMODE */
554 (iw_handler
) cfg80211_wext_giwmode
, /* SIOCGIWMODE */
555 (iw_handler
) NULL
, /* SIOCSIWSENS */
556 (iw_handler
) NULL
, /* SIOCGIWSENS */
557 (iw_handler
) NULL
/* not used */, /* SIOCSIWRANGE */
558 (iw_handler
) cfg80211_wext_giwrange
, /* SIOCGIWRANGE */
559 (iw_handler
) NULL
/* not used */, /* SIOCSIWPRIV */
560 (iw_handler
) NULL
/* kernel code */, /* SIOCGIWPRIV */
561 (iw_handler
) NULL
/* not used */, /* SIOCSIWSTATS */
562 (iw_handler
) NULL
/* kernel code */, /* SIOCGIWSTATS */
563 (iw_handler
) NULL
, /* SIOCSIWSPY */
564 (iw_handler
) NULL
, /* SIOCGIWSPY */
565 (iw_handler
) NULL
, /* SIOCSIWTHRSPY */
566 (iw_handler
) NULL
, /* SIOCGIWTHRSPY */
567 (iw_handler
) ieee80211_ioctl_siwap
, /* SIOCSIWAP */
568 (iw_handler
) ieee80211_ioctl_giwap
, /* SIOCGIWAP */
569 (iw_handler
) cfg80211_wext_siwmlme
, /* SIOCSIWMLME */
570 (iw_handler
) NULL
, /* SIOCGIWAPLIST */
571 (iw_handler
) cfg80211_wext_siwscan
, /* SIOCSIWSCAN */
572 (iw_handler
) cfg80211_wext_giwscan
, /* SIOCGIWSCAN */
573 (iw_handler
) ieee80211_ioctl_siwessid
, /* SIOCSIWESSID */
574 (iw_handler
) ieee80211_ioctl_giwessid
, /* SIOCGIWESSID */
575 (iw_handler
) NULL
, /* SIOCSIWNICKN */
576 (iw_handler
) NULL
, /* SIOCGIWNICKN */
577 (iw_handler
) NULL
, /* -- hole -- */
578 (iw_handler
) NULL
, /* -- hole -- */
579 (iw_handler
) ieee80211_ioctl_siwrate
, /* SIOCSIWRATE */
580 (iw_handler
) ieee80211_ioctl_giwrate
, /* SIOCGIWRATE */
581 (iw_handler
) cfg80211_wext_siwrts
, /* SIOCSIWRTS */
582 (iw_handler
) cfg80211_wext_giwrts
, /* SIOCGIWRTS */
583 (iw_handler
) cfg80211_wext_siwfrag
, /* SIOCSIWFRAG */
584 (iw_handler
) cfg80211_wext_giwfrag
, /* SIOCGIWFRAG */
585 (iw_handler
) cfg80211_wext_siwtxpower
, /* SIOCSIWTXPOW */
586 (iw_handler
) cfg80211_wext_giwtxpower
, /* SIOCGIWTXPOW */
587 (iw_handler
) cfg80211_wext_siwretry
, /* SIOCSIWRETRY */
588 (iw_handler
) cfg80211_wext_giwretry
, /* SIOCGIWRETRY */
589 (iw_handler
) cfg80211_wext_siwencode
, /* SIOCSIWENCODE */
590 (iw_handler
) cfg80211_wext_giwencode
, /* SIOCGIWENCODE */
591 (iw_handler
) ieee80211_ioctl_siwpower
, /* SIOCSIWPOWER */
592 (iw_handler
) ieee80211_ioctl_giwpower
, /* SIOCGIWPOWER */
593 (iw_handler
) NULL
, /* -- hole -- */
594 (iw_handler
) NULL
, /* -- hole -- */
595 (iw_handler
) ieee80211_ioctl_siwgenie
, /* SIOCSIWGENIE */
596 (iw_handler
) NULL
, /* SIOCGIWGENIE */
597 (iw_handler
) ieee80211_ioctl_siwauth
, /* SIOCSIWAUTH */
598 (iw_handler
) ieee80211_ioctl_giwauth
, /* SIOCGIWAUTH */
599 (iw_handler
) cfg80211_wext_siwencodeext
, /* SIOCSIWENCODEEXT */
600 (iw_handler
) NULL
, /* SIOCGIWENCODEEXT */
601 (iw_handler
) NULL
, /* SIOCSIWPMKSA */
602 (iw_handler
) NULL
, /* -- hole -- */
605 const struct iw_handler_def ieee80211_iw_handler_def
=
607 .num_standard
= ARRAY_SIZE(ieee80211_handler
),
608 .standard
= (iw_handler
*) ieee80211_handler
,
609 .get_wireless_stats
= ieee80211_get_wireless_stats
,