4 #include <linux/config.h>
5 #include <linux/module.h>
6 #include <linux/init.h>
7 #include <linux/if_arp.h>
8 #include <asm/uaccess.h>
9 #include <linux/wireless.h>
11 #include <net/iw_handler.h>
16 static struct net_device
*dev
;
17 char buf
[WLC_IOCTL_MAXLEN
];
19 /* The frequency of each channel in MHz */
20 const long channel_frequency
[] = {
21 2412, 2417, 2422, 2427, 2432, 2437, 2442,
22 2447, 2452, 2457, 2462, 2467, 2472, 2484
24 #define NUM_CHANNELS ( sizeof(channel_frequency) / sizeof(channel_frequency[0]) )
26 static int wl_ioctl(struct net_device
*dev
, int cmd
, void *buf
, int len
)
28 mm_segment_t old_fs
= get_fs();
35 strncpy(ifr
.ifr_name
, dev
->name
, IFNAMSIZ
);
36 ifr
.ifr_data
= (caddr_t
) &ioc
;
38 ret
= dev
->do_ioctl(dev
,&ifr
,SIOCDEVPRIVATE
);
43 static int wlcompat_ioctl_getiwrange(struct net_device
*dev
,
47 struct iw_range
*range
;
49 range
= (struct iw_range
*) extra
;
51 range
->we_version_compiled
= WIRELESS_EXT
;
52 range
->we_version_source
= WIRELESS_EXT
;
54 range
->min_nwid
= range
->max_nwid
= 0;
56 range
->num_channels
= NUM_CHANNELS
;
58 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
59 range
->freq
[k
].i
= i
+ 1;
60 range
->freq
[k
].m
= channel_frequency
[i
] * 100000;
63 if (k
>= IW_MAX_FREQUENCIES
)
66 range
->num_frequency
= k
;
67 range
->sensitivity
= 3;
69 /* nbd: don't know what this means, but other drivers set it this way */
70 range
->pmp_flags
= IW_POWER_PERIOD
;
71 range
->pmt_flags
= IW_POWER_TIMEOUT
;
72 range
->pm_capa
= IW_POWER_PERIOD
| IW_POWER_TIMEOUT
| IW_POWER_UNICAST_R
;
75 range
->max_pmp
= 65535000;
77 range
->max_pmt
= 65535 * 1000;
80 if (wl_ioctl(dev
, WLC_GET_RTS
, &range
->max_rts
, sizeof(int)) < 0)
81 range
->max_rts
= 2347;
83 range
->min_frag
= 256;
85 if (wl_ioctl(dev
, WLC_GET_FRAG
, &range
->max_frag
, sizeof(int)) < 0)
86 range
->max_frag
= 2346;
88 range
->txpower_capa
= IW_TXPOW_MWATT
;
94 static int wlcompat_set_scan(struct net_device
*dev
,
95 struct iw_request_info
*info
,
96 union iwreq_data
*wrqu
,
99 int ap
= 0, oldap
= 0;
100 wl_scan_params_t params
;
102 memset(¶ms
, 0, sizeof(params
));
104 /* use defaults (same parameters as wl scan) */
105 memset(¶ms
.bssid
, 0xff, sizeof(params
.bssid
));
106 params
.bss_type
= DOT11_BSSTYPE_ANY
;
107 params
.scan_type
= -1;
109 params
.active_time
= -1;
110 params
.passive_time
= -1;
111 params
.home_time
= -1;
113 /* can only scan in STA mode */
114 wl_ioctl(dev
, WLC_GET_AP
, &oldap
, sizeof(oldap
));
116 wl_ioctl(dev
, WLC_SET_AP
, &ap
, sizeof(ap
));
118 if (wl_ioctl(dev
, WLC_SCAN
, ¶ms
, 64) < 0)
122 wl_ioctl(dev
, WLC_SET_AP
, &oldap
, sizeof(oldap
));
128 static int wlcompat_get_scan(struct net_device
*dev
,
129 struct iw_request_info
*info
,
130 union iwreq_data
*wrqu
,
133 wl_scan_results_t
*results
= (wl_scan_results_t
*) buf
;
134 wl_bss_info_t
*bss_info
;
136 char *current_ev
= extra
;
138 char *end_buf
= extra
+ IW_SCAN_MAX_DATA
;
142 if (wl_ioctl(dev
, WLC_SCAN_RESULTS
, buf
, WLC_IOCTL_MAXLEN
) < 0)
145 bss_info
= &(results
->bss_info
[0]);
146 info_ptr
= (char *) bss_info
;
147 for (i
= 0; i
< results
->count
; i
++) {
149 /* send the cell address (must be sent first) */
151 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
152 memcpy(&iwe
.u
.ap_addr
.sa_data
, &bss_info
->BSSID
, sizeof(bss_info
->BSSID
));
153 current_ev
= iwe_stream_add_event(current_ev
, end_buf
, &iwe
, IW_EV_ADDR_LEN
);
156 iwe
.cmd
= SIOCGIWESSID
;
157 iwe
.u
.data
.length
= bss_info
->SSID_len
;
158 if (iwe
.u
.data
.length
> IW_ESSID_MAX_SIZE
)
159 iwe
.u
.data
.length
= IW_ESSID_MAX_SIZE
;
160 iwe
.u
.data
.flags
= 1;
161 current_ev
= iwe_stream_add_point(current_ev
, end_buf
, &iwe
, bss_info
->SSID
);
163 /* send frequency/channel info */
164 iwe
.cmd
= SIOCGIWFREQ
;
166 iwe
.u
.freq
.m
= bss_info
->channel
;
167 current_ev
= iwe_stream_add_event(current_ev
, end_buf
, &iwe
, IW_EV_FREQ_LEN
);
169 /* add quality statistics */
171 iwe
.u
.qual
.level
= bss_info
->RSSI
;
172 iwe
.u
.qual
.noise
= bss_info
->phy_noise
;
174 current_ev
= iwe_stream_add_event(current_ev
, end_buf
, &iwe
, IW_EV_QUAL_LEN
);
176 /* send rate information */
177 iwe
.cmd
= SIOCGIWRATE
;
178 current_val
= current_ev
+ IW_EV_LCP_LEN
;
179 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
= 0;
181 for(i
= 0 ; i
< bss_info
->rateset
.count
; i
++) {
182 iwe
.u
.bitrate
.value
= ((bss_info
->rateset
.rates
[i
] & 0x7f) * 500000);
183 current_val
= iwe_stream_add_value(current_ev
, current_val
, end_buf
, &iwe
, IW_EV_PARAM_LEN
);
185 if((current_val
- current_ev
) > IW_EV_LCP_LEN
)
186 current_ev
= current_val
;
188 info_ptr
+= sizeof(wl_bss_info_t
);
189 if (bss_info
->ie_length
% 4)
190 info_ptr
+= bss_info
->ie_length
+ 4 - (bss_info
->ie_length
% 4);
192 info_ptr
+= bss_info
->ie_length
;
193 bss_info
= (wl_bss_info_t
*) info_ptr
;
196 wrqu
->data
.length
= (current_ev
- extra
);
197 wrqu
->data
.flags
= 0;
202 static int wlcompat_ioctl(struct net_device
*dev
,
203 struct iw_request_info
*info
,
204 union iwreq_data
*wrqu
,
209 strcpy(wrqu
->name
, "IEEE 802.11-DS");
215 if (wl_ioctl(dev
,WLC_GET_CHANNEL
, &ci
, sizeof(ci
)) < 0)
218 wrqu
->freq
.m
= ci
.target_channel
;
224 if (wrqu
->freq
.e
== 1) {
226 int f
= wrqu
->freq
.m
/ 100000;
227 while ((channel
< NUM_CHANNELS
+ 1) && (f
!= channel_frequency
[channel
]))
230 if (channel
== NUM_CHANNELS
) // channel not found
234 wrqu
->freq
.m
= channel
+ 1;
236 if ((wrqu
->freq
.e
== 0) && (wrqu
->freq
.m
< 1000)) {
237 if (wl_ioctl(dev
, WLC_SET_CHANNEL
, &wrqu
->freq
.m
, sizeof(int)) < 0)
246 wrqu
->ap_addr
.sa_family
= ARPHRD_ETHER
;
247 if (wl_ioctl(dev
,WLC_GET_BSSID
,wrqu
->ap_addr
.sa_data
,6) < 0)
255 if (wl_ioctl(dev
,WLC_GET_SSID
, &ssid
, sizeof(wlc_ssid_t
)) < 0)
258 wrqu
->essid
.flags
= wrqu
->data
.flags
= 1;
259 wrqu
->essid
.length
= wrqu
->data
.length
= ssid
.SSID_len
+ 1;
260 memcpy(extra
,ssid
.SSID
,ssid
.SSID_len
+ 1);
266 memset(&ssid
, 0, sizeof(ssid
));
267 ssid
.SSID_len
= strlen(extra
);
268 if (ssid
.SSID_len
> WLC_ESSID_MAX_SIZE
)
269 ssid
.SSID_len
= WLC_ESSID_MAX_SIZE
;
270 memcpy(ssid
.SSID
, extra
, ssid
.SSID_len
);
271 if (wl_ioctl(dev
, WLC_SET_SSID
, &ssid
, sizeof(ssid
)) < 0)
277 if (wl_ioctl(dev
,WLC_GET_RTS
,&(wrqu
->rts
.value
),sizeof(int)) < 0)
283 if (wl_ioctl(dev
,WLC_SET_RTS
,&(wrqu
->rts
.value
),sizeof(int)) < 0)
289 if (wl_ioctl(dev
,WLC_GET_FRAG
,&(wrqu
->frag
.value
),sizeof(int)) < 0)
295 if (wl_ioctl(dev
,WLC_SET_FRAG
,&(wrqu
->frag
.value
),sizeof(int)) < 0)
301 wrqu
->txpower
.value
= 0;
302 if (wl_ioctl(dev
,WLC_GET_TXPWR
, &(wrqu
->txpower
.value
), sizeof(int)) < 0)
304 wrqu
->txpower
.fixed
= 0;
305 wrqu
->txpower
.disabled
= 0;
306 wrqu
->txpower
.flags
= IW_TXPOW_MWATT
;
311 if (wrqu
->txpower
.flags
!= IW_TXPOW_MWATT
)
314 if (wl_ioctl(dev
, WLC_SET_TXPWR
, &wrqu
->txpower
.value
, sizeof(int)) < 0)
319 wrqu
->data
.flags
= IW_ENCODE_DISABLED
;
324 return wlcompat_ioctl_getiwrange(dev
, extra
);
329 int ap
= -1, infra
= -1, passive
= 0, wet
= 0;
331 switch (wrqu
->mode
) {
332 case IW_MODE_MONITOR
:
356 if (wl_ioctl(dev
, WLC_SET_PASSIVE
, &passive
, sizeof(passive
)) < 0)
358 if (wl_ioctl(dev
, WLC_SET_MONITOR
, &passive
, sizeof(passive
)) < 0)
360 if (wl_ioctl(dev
, WLC_SET_WET
, &wet
, sizeof(wet
)) < 0)
363 if (wl_ioctl(dev
, WLC_SET_AP
, &ap
, sizeof(ap
)) < 0)
366 if (wl_ioctl(dev
, WLC_SET_INFRA
, &infra
, sizeof(infra
)) < 0)
374 int ap
, infra
, wet
, passive
;
376 if (wl_ioctl(dev
, WLC_GET_AP
, &ap
, sizeof(ap
)) < 0)
378 if (wl_ioctl(dev
, WLC_GET_INFRA
, &infra
, sizeof(infra
)) < 0)
380 if (wl_ioctl(dev
, WLC_GET_PASSIVE
, &passive
, sizeof(passive
)) < 0)
382 if (wl_ioctl(dev
, WLC_GET_WET
, &wet
, sizeof(wet
)) < 0)
386 wrqu
->mode
= IW_MODE_MONITOR
;
388 wrqu
->mode
= IW_MODE_ADHOC
;
391 wrqu
->mode
= IW_MODE_MASTER
;
394 wrqu
->mode
= IW_MODE_REPEAT
;
396 wrqu
->mode
= IW_MODE_INFRA
;
411 static const iw_handler wlcompat_handler
[] = {
412 NULL
, /* SIOCSIWCOMMIT */
413 wlcompat_ioctl
, /* SIOCGIWNAME */
414 NULL
, /* SIOCSIWNWID */
415 NULL
, /* SIOCGIWNWID */
416 wlcompat_ioctl
, /* SIOCSIWFREQ */
417 wlcompat_ioctl
, /* SIOCGIWFREQ */
418 wlcompat_ioctl
, /* SIOCSIWMODE */
419 wlcompat_ioctl
, /* SIOCGIWMODE */
420 NULL
, /* SIOCSIWSENS */
421 NULL
, /* SIOCGIWSENS */
422 NULL
, /* SIOCSIWRANGE, unused */
423 wlcompat_ioctl
, /* SIOCGIWRANGE */
424 NULL
, /* SIOCSIWPRIV */
425 NULL
, /* SIOCGIWPRIV */
426 NULL
, /* SIOCSIWSTATS */
427 NULL
, /* SIOCGIWSTATS */
428 iw_handler_set_spy
, /* SIOCSIWSPY */
429 iw_handler_get_spy
, /* SIOCGIWSPY */
430 iw_handler_set_thrspy
, /* SIOCSIWTHRSPY */
431 iw_handler_get_thrspy
, /* SIOCGIWTHRSPY */
432 NULL
, /* SIOCSIWAP */
433 wlcompat_ioctl
, /* SIOCGIWAP */
434 NULL
, /* -- hole -- */
435 NULL
, /* SIOCGIWAPLIST */
436 wlcompat_set_scan
, /* SIOCSIWSCAN */
437 wlcompat_get_scan
, /* SIOCGIWSCAN */
438 wlcompat_ioctl
, /* SIOCSIWESSID */
439 wlcompat_ioctl
, /* SIOCGIWESSID */
440 NULL
, /* SIOCSIWNICKN */
441 NULL
, /* SIOCGIWNICKN */
442 NULL
, /* -- hole -- */
443 NULL
, /* -- hole -- */
444 NULL
, /* SIOCSIWRATE */
445 NULL
, /* SIOCGIWRATE */
446 wlcompat_ioctl
, /* SIOCSIWRTS */
447 wlcompat_ioctl
, /* SIOCGIWRTS */
448 wlcompat_ioctl
, /* SIOCSIWFRAG */
449 wlcompat_ioctl
, /* SIOCGIWFRAG */
450 wlcompat_ioctl
, /* SIOCSIWTXPOW */
451 wlcompat_ioctl
, /* SIOCGIWTXPOW */
452 NULL
, /* SIOCSIWRETRY */
453 NULL
, /* SIOCGIWRETRY */
454 NULL
, /* SIOCSIWENCODE */
455 wlcompat_ioctl
, /* SIOCGIWENCODE */
458 static const struct iw_handler_def wlcompat_handler_def
=
460 .standard
= (iw_handler
*) wlcompat_handler
,
461 .num_standard
= sizeof(wlcompat_handler
)/sizeof(iw_handler
),
464 .private_args
= NULL
,
465 .num_private_args
= 0,
469 static int (*old_ioctl
)(struct net_device
*dev
, struct ifreq
*ifr
, int cmd
);
470 static int new_ioctl(struct net_device
*dev
, struct ifreq
*ifr
, int cmd
) {
471 int ret
= old_ioctl(dev
,ifr
,cmd
);
472 printk("dev: %s ioctl: 0x%04x\n",dev
->name
,cmd
);
473 if (cmd
==SIOCDEVPRIVATE
) {
475 wl_ioctl_t
*ioc
= (wl_ioctl_t
*)ifr
->ifr_data
;
476 unsigned char *buf
= ioc
->buf
;
477 printk(" cmd: %d buf: 0x%08x len: %d\n",ioc
->cmd
,&(ioc
->buf
),ioc
->len
);
479 for (x
=0;x
<ioc
->len
&& x
<128 ;x
++) {
480 printk("%02X",buf
[x
]);
488 static int __init
wlcompat_init()
490 dev
= dev_get_by_name("eth1");
492 old_ioctl
= dev
->do_ioctl
;
493 dev
->do_ioctl
= new_ioctl
;
495 dev
->wireless_handlers
= (struct iw_handler_def
*)&wlcompat_handler_def
;
499 static void __exit
wlcompat_exit()
501 dev
->wireless_handlers
= NULL
;
503 dev
->do_ioctl
= old_ioctl
;
509 MODULE_AUTHOR("openwrt.org");
510 MODULE_LICENSE("GPL");
512 module_init(wlcompat_init
);
513 module_exit(wlcompat_exit
);