2 * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * $Id: ieee80211_linux.c 3744 2008-06-22 05:32:29Z mentor $
34 * IEEE 802.11 support (Linux-specific code)
36 #ifndef AUTOCONF_INCLUDED
37 #include <linux/config.h>
39 #include <linux/version.h>
40 #include <linux/module.h>
41 #include <linux/kmod.h>
42 #include <linux/init.h>
43 #include <linux/skbuff.h>
44 #include <linux/sysctl.h>
45 #include <linux/netdevice.h>
46 #include <linux/etherdevice.h>
47 #include <linux/if_vlan.h>
48 #include <linux/vmalloc.h>
49 #include <linux/proc_fs.h>
51 #include <net/iw_handler.h>
52 #include <linux/wireless.h>
53 #include <linux/if_arp.h> /* XXX for ARPHRD_* */
55 #include <asm/uaccess.h>
58 #include "if_ethersubr.h"
60 #include <net80211/ieee80211_var.h>
61 #include <net80211/ieee80211_monitor.h>
63 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
64 #include <linux/device.h>
66 /* madwifi_name_type - device name type:
67 * values: 0: automatically assigned
68 * 1: administratively assigned
71 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
72 static ssize_t
show_madwifi_name_type(struct device
*dev
,
73 struct device_attribute
*attr
, char *buf
)
75 static ssize_t
show_madwifi_name_type(struct class_device
*cdev
,
81 len
= snprintf(buf
, PAGE_SIZE
, "1");
86 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
87 static DEVICE_ATTR(madwifi_name_type
, S_IRUGO
, show_madwifi_name_type
, NULL
);
89 static CLASS_DEVICE_ATTR(madwifi_name_type
, S_IRUGO
, show_madwifi_name_type
, NULL
);
92 static struct attribute
*ieee80211_sysfs_attrs
[] = {
93 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
94 &dev_attr_madwifi_name_type
.attr
,
96 &class_device_attr_madwifi_name_type
.attr
,
101 static struct attribute_group ieee80211_attr_grp
= {
102 .name
= NULL
, /* No seperate (sub-)directory */
103 .attrs
= ieee80211_sysfs_attrs
105 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
107 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
108 #define proc_net init_net.proc_net
112 * Print a console message with the device name prepended.
115 if_printf(struct net_device
*dev
, const char *fmt
, ...)
118 char buf
[512]; /* XXX */
121 vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
124 printk("%s: %s", dev
->name
, buf
);
128 * Allocate and setup a management frame of the specified
129 * size. We return the sk_buff and a pointer to the start
130 * of the contiguous data area that's been reserved based
131 * on the packet length. The data area is forced to 32-bit
132 * alignment and the buffer length to a multiple of 4 bytes.
133 * This is done mainly so beacon frames (that require this)
134 * can use this interface too.
137 #ifdef IEEE80211_DEBUG_REFCNT
138 ieee80211_getmgtframe_debug(u_int8_t
**frm
, u_int pktlen
,
139 const char *func
, int line
)
141 ieee80211_getmgtframe(u_int8_t
**frm
, u_int pktlen
)
144 const u_int align
= sizeof(u_int32_t
);
148 len
= roundup(sizeof(struct ieee80211_frame
) + pktlen
, 4);
149 #ifdef IEEE80211_DEBUG_REFCNT
150 skb
= ieee80211_dev_alloc_skb_debug(len
+ align
- 1, func
, line
);
152 skb
= ieee80211_dev_alloc_skb(len
+ align
- 1);
155 u_int off
= ((unsigned long) skb
->data
) % align
;
157 skb_reserve(skb
, align
- off
);
160 SKB_CB(skb
)->flags
= 0;
162 skb_reserve(skb
, sizeof(struct ieee80211_frame
));
163 *frm
= skb_put(skb
, pktlen
);
167 #ifdef IEEE80211_DEBUG_REFCNT
168 EXPORT_SYMBOL(ieee80211_getmgtframe_debug
);
170 EXPORT_SYMBOL(ieee80211_getmgtframe
);
173 #if IEEE80211_VLAN_TAG_USED
179 * Register a vlan group.
182 ieee80211_vlan_register(struct net_device
*dev
, struct vlan_group
*grp
)
184 struct ieee80211vap
*vap
= dev
->priv
;
190 * Add an rx vlan identifier
193 ieee80211_vlan_add_vid(struct net_device
*dev
, unsigned short vid
)
195 struct ieee80211vap
*vap
= dev
->priv
;
197 if (vap
->iv_vlgrp
!= NULL
)
198 vap
->iv_bss
->ni_vlan
= vid
;
202 * Kill (i.e. delete) a vlan identifier.
205 ieee80211_vlan_kill_vid(struct net_device
*dev
, unsigned short vid
)
207 struct ieee80211vap
*vap
= dev
->priv
;
209 if (vap
->iv_vlgrp
!= NULL
)
210 vlan_group_set_device(vap
->iv_vlgrp
, vid
, NULL
);
212 #endif /* IEEE80211_VLAN_TAG_USED */
215 ieee80211_vlan_vattach(struct ieee80211vap
*vap
)
217 #if IEEE80211_VLAN_TAG_USED
218 struct net_device
*dev
= vap
->iv_dev
;
220 dev
->features
|= NETIF_F_HW_VLAN_TX
| NETIF_F_HW_VLAN_RX
|
221 NETIF_F_HW_VLAN_FILTER
;
222 dev
->vlan_rx_register
= ieee80211_vlan_register
;
223 dev
->vlan_rx_add_vid
= ieee80211_vlan_add_vid
;
224 dev
->vlan_rx_kill_vid
= ieee80211_vlan_kill_vid
;
225 #endif /* IEEE80211_VLAN_TAG_USED */
229 ieee80211_vlan_vdetach(struct ieee80211vap
*vap
)
234 ieee80211_notify_node_join(struct ieee80211_node
*ni
, int newassoc
)
236 struct ieee80211vap
*vap
= ni
->ni_vap
;
237 struct net_device
*dev
= vap
->iv_dev
;
238 union iwreq_data wreq
;
240 if (ni
== vap
->iv_bss
) {
242 netif_carrier_on(dev
);
243 memset(&wreq
, 0, sizeof(wreq
));
244 IEEE80211_ADDR_COPY(wreq
.addr
.sa_data
, vap
->iv_bssid
);
245 wreq
.addr
.sa_family
= ARPHRD_ETHER
;
247 if (vap
->iv_xrvap
&& vap
->iv_flags
& IEEE80211_F_XR
)
248 dev
= vap
->iv_xrvap
->iv_dev
;
250 wireless_send_event(dev
, SIOCGIWAP
, &wreq
, NULL
);
252 memset(&wreq
, 0, sizeof(wreq
));
253 IEEE80211_ADDR_COPY(wreq
.addr
.sa_data
, ni
->ni_macaddr
);
254 wreq
.addr
.sa_family
= ARPHRD_ETHER
;
256 if (vap
->iv_xrvap
&& vap
->iv_flags
& IEEE80211_F_XR
)
257 dev
= vap
->iv_xrvap
->iv_dev
;
259 wireless_send_event(dev
, IWEVREGISTERED
, &wreq
, NULL
);
264 ieee80211_notify_node_leave(struct ieee80211_node
*ni
)
266 struct ieee80211vap
*vap
= ni
->ni_vap
;
267 struct net_device
*dev
= vap
->iv_dev
;
268 union iwreq_data wreq
;
270 if (ni
== vap
->iv_bss
) {
271 netif_carrier_off(dev
);
272 memset(wreq
.ap_addr
.sa_data
, 0, ETHER_ADDR_LEN
);
273 wreq
.ap_addr
.sa_family
= ARPHRD_ETHER
;
274 wireless_send_event(dev
, SIOCGIWAP
, &wreq
, NULL
);
276 /* fire off wireless event station leaving */
277 memset(&wreq
, 0, sizeof(wreq
));
278 IEEE80211_ADDR_COPY(wreq
.addr
.sa_data
, ni
->ni_macaddr
);
279 wreq
.addr
.sa_family
= ARPHRD_ETHER
;
280 wireless_send_event(dev
, IWEVEXPIRED
, &wreq
, NULL
);
285 ieee80211_notify_sta_stats(struct ieee80211_node
*ni
)
287 struct ieee80211vap
*vap
= ni
->ni_vap
;
288 static const char *tag
= "STA-TRAFFIC-STAT";
289 struct net_device
*dev
= vap
->iv_dev
;
290 union iwreq_data wreq
;
293 snprintf(buf
, sizeof(buf
), "%s\nmac=" MAC_FMT
"\nrx_packets=%u\nrx_bytes=%llu\n"
294 "tx_packets=%u\ntx_bytes=%llu\n", tag
,
295 MAC_ADDR(ni
->ni_macaddr
), ni
->ni_stats
.ns_rx_data
,
296 (unsigned long long)ni
->ni_stats
.ns_rx_bytes
,
297 ni
->ni_stats
.ns_tx_data
,
298 (unsigned long long)ni
->ni_stats
.ns_tx_bytes
);
299 memset(&wreq
, 0, sizeof(wreq
));
300 wreq
.data
.length
= strlen(buf
);
301 wireless_send_event(dev
, IWEVCUSTOM
, &wreq
, buf
);
305 ieee80211_notify_scan_done(struct ieee80211vap
*vap
)
307 struct net_device
*dev
= vap
->iv_dev
;
308 union iwreq_data wreq
;
310 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_SCAN
, "%s\n", "notify scan done");
312 /* dispatch wireless event indicating scan completed */
313 wreq
.data
.length
= 0;
315 wireless_send_event(dev
, SIOCGIWSCAN
, &wreq
, NULL
);
319 ieee80211_notify_replay_failure(struct ieee80211vap
*vap
,
320 const struct ieee80211_frame
*wh
, const struct ieee80211_key
*k
,
323 static const char *tag
= "MLME-REPLAYFAILURE.indication";
324 struct net_device
*dev
= vap
->iv_dev
;
325 union iwreq_data wrqu
;
326 char buf
[128]; /* XXX */
328 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_CRYPTO
, wh
->i_addr2
,
329 "%s replay detected <keyix %d, rsc %llu >",
330 k
->wk_cipher
->ic_name
, k
->wk_keyix
,
331 (unsigned long long)rsc
);
333 /* TODO: needed parameters: count, keyid, key type, src address, TSC */
334 snprintf(buf
, sizeof(buf
), "%s(keyid=%d %scast addr=" MAC_FMT
")", tag
,
336 IEEE80211_IS_MULTICAST(wh
->i_addr2
) ? "broad" : "uni",
337 MAC_ADDR(wh
->i_addr2
));
338 memset(&wrqu
, 0, sizeof(wrqu
));
339 wrqu
.data
.length
= strlen(buf
);
340 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
342 EXPORT_SYMBOL(ieee80211_notify_replay_failure
);
345 ieee80211_notify_michael_failure(struct ieee80211vap
*vap
,
346 const struct ieee80211_frame
*wh
, ieee80211_keyix_t keyix
)
348 static const char *tag
= "MLME-MICHAELMICFAILURE.indication";
349 struct net_device
*dev
= vap
->iv_dev
;
350 union iwreq_data wrqu
;
351 char buf
[128]; /* XXX */
353 IEEE80211_NOTE_MAC(vap
, IEEE80211_MSG_CRYPTO
, wh
->i_addr2
,
354 "Michael MIC verification failed <keyix %d>", keyix
);
355 vap
->iv_stats
.is_rx_tkipmic
++;
357 /* TODO: needed parameters: count, keyid, key type, src address, TSC */
358 snprintf(buf
, sizeof(buf
), "%s(keyid=%d %scast addr=" MAC_FMT
")", tag
,
359 keyix
, IEEE80211_IS_MULTICAST(wh
->i_addr2
) ? "broad" : "uni",
360 MAC_ADDR(wh
->i_addr2
));
361 memset(&wrqu
, 0, sizeof(wrqu
));
362 wrqu
.data
.length
= strlen(buf
);
363 wireless_send_event(dev
, IWEVCUSTOM
, &wrqu
, buf
);
365 EXPORT_SYMBOL(ieee80211_notify_michael_failure
);
367 /* This function might sleep. Therefore:
370 * Note that a successful call to this function does not guarantee that
371 * the services provided by the requested module are available:
373 * "Note that a successful module load does not mean the module did not
374 * then unload and exit on an error of its own. Callers must check that
375 * the service they requested is now available not blindly invoke it."
376 * http://kernelnewbies.org/documents/kdoc/kernel-api/r7338.html
379 ieee80211_load_module(const char *modname
)
383 rv
= request_module("%s", modname
);
385 printk(KERN_ERR
"failed to automatically load module: %s; " \
386 "errno: %d\n", modname
, rv
);
388 #else /* CONFIG_KMOD */
389 printk(KERN_ERR
"Unable to load needed module: %s; no support for " \
390 "automatic module loading\n", modname
);
392 #endif /* CONFIG_KMOD */
396 static struct proc_dir_entry
*proc_madwifi
;
397 static int proc_madwifi_count
= 0;
400 proc_read_nodes(struct ieee80211vap
*vap
, char *buf
, int space
)
403 struct ieee80211_node
*ni
;
404 struct ieee80211_node_table
*nt
=
405 (struct ieee80211_node_table
*)&vap
->iv_ic
->ic_sta
;
407 IEEE80211_NODE_TABLE_LOCK_IRQ(nt
);
408 TAILQ_FOREACH(ni
, &nt
->nt_node
, ni_list
) {
411 /* Assume each node needs 500 bytes */
412 if (buf
+ space
< p
+ 500)
414 if ((ni
->ni_vap
== vap
) && (memcmp(vap
->iv_myaddr
,
415 ni
->ni_macaddr
, IEEE80211_ADDR_LEN
) != 0)) {
416 jiffies_to_timespec(jiffies
- ni
->ni_last_rx
, &t
);
417 p
+= sprintf(p
, "macaddr: <" MAC_FMT
">\n",
418 MAC_ADDR(ni
->ni_macaddr
));
419 p
+= sprintf(p
, " RSSI %d\n", ni
->ni_rssi
);
420 p
+= sprintf(p
, " last_rx %ld.%06ld\n",
421 t
.tv_sec
, t
.tv_nsec
/ 1000);
422 p
+= sprintf(p
, " ni_tstamp %10llu ni_rtsf %10llu\n",
423 le64_to_cpu(ni
->ni_tstamp
.tsf
), ni
->ni_rtsf
);
426 IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt
);
432 proc_ieee80211_read(struct file
*file
, char __user
*buf
, size_t len
, loff_t
*offset
)
434 loff_t pos
= *offset
;
435 struct proc_ieee80211_priv
*pv
=
436 (struct proc_ieee80211_priv
*)file
->private_data
;
444 if (len
> pv
->rlen
- pos
)
445 len
= pv
->rlen
- pos
;
446 if (copy_to_user(buf
, pv
->rbuf
+ pos
, len
))
453 proc_ieee80211_open(struct inode
*inode
, struct file
*file
)
455 struct proc_ieee80211_priv
*pv
= NULL
;
456 struct proc_dir_entry
*dp
= PDE(inode
);
457 struct ieee80211vap
*vap
= dp
->data
;
459 if (!(file
->private_data
= kzalloc(sizeof(struct proc_ieee80211_priv
),
462 /* initially allocate both read and write buffers */
463 pv
= (struct proc_ieee80211_priv
*)file
->private_data
;
464 pv
->rbuf
= vmalloc(MAX_PROC_IEEE80211_SIZE
);
469 pv
->wbuf
= vmalloc(MAX_PROC_IEEE80211_SIZE
);
475 memset(pv
->wbuf
, 0, MAX_PROC_IEEE80211_SIZE
);
476 memset(pv
->rbuf
, 0, MAX_PROC_IEEE80211_SIZE
);
477 pv
->max_wlen
= MAX_PROC_IEEE80211_SIZE
;
478 pv
->max_rlen
= MAX_PROC_IEEE80211_SIZE
;
479 /* now read the data into the buffer */
480 pv
->rlen
= proc_read_nodes(vap
, pv
->rbuf
, MAX_PROC_IEEE80211_SIZE
);
485 proc_ieee80211_write(struct file
*file
, const char __user
*buf
, size_t len
, loff_t
*offset
)
487 loff_t pos
= *offset
;
488 struct proc_ieee80211_priv
*pv
=
489 (struct proc_ieee80211_priv
*)file
->private_data
;
495 if (pos
>= pv
->max_wlen
)
497 if (len
> pv
->max_wlen
- pos
)
498 len
= pv
->max_wlen
- pos
;
499 if (copy_from_user(pv
->wbuf
+ pos
, buf
, len
))
501 if (pos
+ len
> pv
->wlen
)
502 pv
->wlen
= pos
+ len
;
509 proc_ieee80211_close(struct inode
*inode
, struct file
*file
)
511 struct proc_ieee80211_priv
*pv
=
512 (struct proc_ieee80211_priv
*)file
->private_data
;
521 static struct file_operations proc_ieee80211_ops
= {
522 .read
= proc_ieee80211_read
,
523 .write
= proc_ieee80211_write
,
524 .open
= proc_ieee80211_open
,
525 .release
= proc_ieee80211_close
,
528 #ifdef IEEE80211_DEBUG
530 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_debug
, ctl
, write
, filp
, buffer
,
533 struct ieee80211vap
*vap
= ctl
->extra1
;
538 ctl
->maxlen
= sizeof(val
);
540 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
543 vap
->iv_debug
= (val
& ~IEEE80211_MSG_IC
);
544 vap
->iv_ic
->ic_debug
= (val
& IEEE80211_MSG_IC
);
545 printk(KERN_INFO
"%s debug flags changed to 0x%08x.\n",
546 vap
->iv_dev
->name
, val
);
549 /* VAP specific and 'global' debug flags */
550 val
= vap
->iv_debug
| vap
->iv_ic
->ic_debug
;
551 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
556 #endif /* IEEE80211_DEBUG */
559 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_dev_type
, ctl
, write
, filp
, buffer
,
562 struct ieee80211vap
*vap
= ctl
->extra1
;
567 ctl
->maxlen
= sizeof(val
);
569 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
571 if (ret
== 0 && vap
->iv_opmode
== IEEE80211_M_MONITOR
) {
572 if (val
== ARPHRD_IEEE80211_RADIOTAP
||
573 val
== ARPHRD_IEEE80211
||
574 val
== ARPHRD_IEEE80211_PRISM
||
575 val
== ARPHRD_IEEE80211_ATHDESC
) {
576 vap
->iv_dev
->type
= val
;
580 val
= vap
->iv_dev
->type
;
581 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
588 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_nods_only
, ctl
, write
, filp
, buffer
,
591 struct ieee80211vap
*vap
= ctl
->extra1
;
596 ctl
->maxlen
= sizeof(val
);
598 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
601 vap
->iv_monitor_nods_only
= val
;
603 val
= vap
->iv_monitor_nods_only
;
604 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
611 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_txf_len
, ctl
, write
, filp
, buffer
,
614 struct ieee80211vap
*vap
= ctl
->extra1
;
619 ctl
->maxlen
= sizeof(val
);
621 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
624 vap
->iv_monitor_txf_len
= val
;
626 val
= vap
->iv_monitor_txf_len
;
627 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
634 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_phy_errors
, ctl
, write
, filp
, buffer
,
637 struct ieee80211vap
*vap
= ctl
->extra1
;
642 ctl
->maxlen
= sizeof(val
);
644 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
647 vap
->iv_monitor_phy_errors
= val
;
649 val
= vap
->iv_monitor_phy_errors
;
650 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
657 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_crc_errors
, ctl
, write
, filp
, buffer
,
660 struct ieee80211vap
*vap
= ctl
->extra1
;
665 ctl
->maxlen
= sizeof(val
);
667 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
670 vap
->iv_monitor_crc_errors
= val
;
672 val
= vap
->iv_monitor_crc_errors
;
673 ret
= IEEE80211_SYSCTL_PROC_DOINTVEC(ctl
, write
, filp
, buffer
,
679 static const ctl_table ieee80211_sysctl_template
[] = {
680 #ifdef IEEE80211_DEBUG
681 { .ctl_name
= CTL_AUTO
,
684 .proc_handler
= ieee80211_sysctl_debug
687 { .ctl_name
= CTL_AUTO
,
688 .procname
= "dev_type",
690 .proc_handler
= ieee80211_sysctl_dev_type
692 { .ctl_name
= CTL_AUTO
,
693 .procname
= "monitor_nods_only",
695 .proc_handler
= ieee80211_sysctl_monitor_nods_only
697 { .ctl_name
= CTL_AUTO
,
698 .procname
= "monitor_txf_len",
700 .proc_handler
= ieee80211_sysctl_monitor_txf_len
702 { .ctl_name
= CTL_AUTO
,
703 .procname
= "monitor_phy_errors",
705 .proc_handler
= ieee80211_sysctl_monitor_phy_errors
707 { .ctl_name
= CTL_AUTO
,
708 .procname
= "monitor_crc_errors",
710 .proc_handler
= ieee80211_sysctl_monitor_crc_errors
712 /* NB: must be last entry before NULL */
713 { .ctl_name
= CTL_AUTO
,
714 .procname
= "%parent",
717 .proc_handler
= proc_dostring
723 ieee80211_virtfs_latevattach(struct ieee80211vap
*vap
)
726 char *devname
= NULL
;
727 struct ieee80211_proc_entry
*tmp
= NULL
;
728 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
731 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
732 ret
= sysfs_create_group(&vap
->iv_dev
->dev
.kobj
, &ieee80211_attr_grp
);
734 ret
= sysfs_create_group(&vap
->iv_dev
->class_dev
.kobj
, &ieee80211_attr_grp
);
737 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
738 sysfs_remove_group(&vap
->iv_dev
->dev
.kobj
, &ieee80211_attr_grp
);
740 sysfs_remove_group(&vap
->iv_dev
->class_dev
.kobj
, &ieee80211_attr_grp
);
742 printk("%s: %s - unable to create sysfs attribute group\n",
743 __func__
, vap
->iv_dev
->name
);
746 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
748 space
= 5 * sizeof(struct ctl_table
) + sizeof(ieee80211_sysctl_template
);
749 vap
->iv_sysctls
= kzalloc(space
, GFP_KERNEL
);
750 if (vap
->iv_sysctls
== NULL
) {
751 printk("%s: no memory for sysctl table!\n", __func__
);
756 * Reserve space for the device name outside the net_device structure
757 * so that if the name changes we know what it used to be.
759 devname
= kmalloc((strlen(vap
->iv_dev
->name
) + 1) * sizeof(char), GFP_KERNEL
);
760 if (devname
== NULL
) {
761 printk("%s: no memory for VAP name!\n", __func__
);
764 strncpy(devname
, vap
->iv_dev
->name
, strlen(vap
->iv_dev
->name
) + 1);
766 /* setup the table */
767 vap
->iv_sysctls
[0].ctl_name
= CTL_NET
;
768 vap
->iv_sysctls
[0].procname
= "net";
769 vap
->iv_sysctls
[0].mode
= 0555;
770 vap
->iv_sysctls
[0].child
= &vap
->iv_sysctls
[2];
771 /* [1] is NULL terminator */
772 vap
->iv_sysctls
[2].ctl_name
= CTL_AUTO
;
773 vap
->iv_sysctls
[2].procname
= devname
; /* XXX bad idea? */
774 vap
->iv_sysctls
[2].mode
= 0555;
775 vap
->iv_sysctls
[2].child
= &vap
->iv_sysctls
[4];
776 /* [3] is NULL terminator */
777 /* copy in pre-defined data */
778 memcpy(&vap
->iv_sysctls
[4], ieee80211_sysctl_template
,
779 sizeof(ieee80211_sysctl_template
));
781 /* add in dynamic data references */
782 for (i
= 4; vap
->iv_sysctls
[i
].procname
; i
++)
783 if (vap
->iv_sysctls
[i
].extra1
== NULL
)
784 vap
->iv_sysctls
[i
].extra1
= vap
;
786 /* tack on back-pointer to parent device */
787 vap
->iv_sysctls
[i
-1].data
= vap
->iv_ic
->ic_dev
->name
; /* XXX? */
789 /* and register everything */
790 vap
->iv_sysctl_header
= ATH_REGISTER_SYSCTL_TABLE(vap
->iv_sysctls
);
791 if (!vap
->iv_sysctl_header
) {
792 printk("%s: failed to register sysctls!\n", vap
->iv_dev
->name
);
794 kfree(vap
->iv_sysctls
);
795 vap
->iv_sysctls
= NULL
;
798 /* Ensure the base madwifi directory exists */
799 if (!proc_madwifi
&& proc_net
!= NULL
) {
800 proc_madwifi
= proc_mkdir("madwifi", proc_net
);
802 printk(KERN_WARNING
"Failed to mkdir /proc/net/madwifi\n");
805 /* Create a proc directory named after the VAP */
807 proc_madwifi_count
++;
808 vap
->iv_proc
= proc_mkdir(vap
->iv_dev
->name
, proc_madwifi
);
811 /* Create a proc entry listing the associated stations */
812 ieee80211_proc_vcreate(vap
, &proc_ieee80211_ops
, "associated_sta");
814 /* Recreate any other proc entries that have been registered */
816 tmp
= vap
->iv_proc_entries
;
819 tmp
->entry
= create_proc_entry(tmp
->name
,
820 PROC_IEEE80211_PERM
, vap
->iv_proc
);
821 tmp
->entry
->data
= vap
;
822 tmp
->entry
->proc_fops
= tmp
->fileops
;
829 /* Frees all memory used for the list of proc entries */
831 ieee80211_proc_cleanup(struct ieee80211vap
*vap
)
833 struct ieee80211_proc_entry
*tmp
= vap
->iv_proc_entries
;
834 struct ieee80211_proc_entry
*next
= NULL
;
842 /* Called by other modules to register a proc entry under the vap directory */
844 ieee80211_proc_vcreate(struct ieee80211vap
*vap
,
845 struct file_operations
*fileops
, char *name
)
847 struct ieee80211_proc_entry
*entry
;
848 struct ieee80211_proc_entry
*tmp
= NULL
;
850 /* Ignore if already in the list */
851 if (vap
->iv_proc_entries
) {
852 tmp
= vap
->iv_proc_entries
;
854 if (strcmp(tmp
->name
, name
)==0)
856 /* Check for end of list */
859 /* Otherwise move on */
864 /* Create an item in our list for the new entry */
865 entry
= kmalloc(sizeof(struct ieee80211_proc_entry
), GFP_KERNEL
);
867 printk("%s: no memory for new proc entry (%s)!\n", __func__
,
872 /* Replace null fileops pointers with our standard functions */
874 fileops
->open
= proc_ieee80211_open
;
875 if (!fileops
->release
)
876 fileops
->release
= proc_ieee80211_close
;
878 fileops
->read
= proc_ieee80211_read
;
880 fileops
->write
= proc_ieee80211_write
;
882 /* Create the entry record */
884 entry
->fileops
= fileops
;
888 /* Create the actual proc entry */
890 entry
->entry
= create_proc_entry(entry
->name
,
891 PROC_IEEE80211_PERM
, vap
->iv_proc
);
892 entry
->entry
->data
= vap
;
893 entry
->entry
->proc_fops
= entry
->fileops
;
896 /* Add it to the list */
898 /* Add to the start */
899 vap
->iv_proc_entries
= entry
;
907 EXPORT_SYMBOL(ieee80211_proc_vcreate
);
910 ieee80211_virtfs_vdetach(struct ieee80211vap
*vap
)
912 struct ieee80211_proc_entry
*tmp
=NULL
;
914 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
915 sysfs_remove_group(&vap
->iv_dev
->dev
.kobj
, &ieee80211_attr_grp
);
916 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
917 sysfs_remove_group(&vap
->iv_dev
->class_dev
.kobj
, &ieee80211_attr_grp
);
920 if (vap
->iv_sysctl_header
) {
921 unregister_sysctl_table(vap
->iv_sysctl_header
);
922 vap
->iv_sysctl_header
= NULL
;
926 /* Remove child proc entries but leave them in the list */
927 tmp
= vap
->iv_proc_entries
;
930 remove_proc_entry(tmp
->name
, vap
->iv_proc
);
935 remove_proc_entry(vap
->iv_proc
->name
, proc_madwifi
);
936 if (proc_madwifi_count
== 1) {
937 remove_proc_entry("madwifi", proc_net
);
940 proc_madwifi_count
--;
943 if (vap
->iv_sysctls
&& vap
->iv_sysctls
[2].procname
) {
944 kfree(vap
->iv_sysctls
[2].procname
);
945 vap
->iv_sysctls
[2].procname
= NULL
;
948 if (vap
->iv_sysctls
) {
949 kfree(vap
->iv_sysctls
);
950 vap
->iv_sysctls
= NULL
;
954 /* Function to handle the device event notifications.
955 * If the event is a NETDEV_CHANGENAME, and is for an interface
956 * we are taking care of, then we want to remove its existing
957 * proc entries (which now have the wrong names) and add
958 * new, correct, entries.
961 ieee80211_rcv_dev_event(struct notifier_block
*this, unsigned long event
,
964 struct net_device
*dev
= (struct net_device
*)ptr
;
965 if (!dev
|| dev
->open
!= &ieee80211_open
)
969 case NETDEV_CHANGENAME
:
970 ieee80211_virtfs_vdetach(dev
->priv
);
971 ieee80211_virtfs_latevattach(dev
->priv
);
979 static struct notifier_block ieee80211_event_block
= {
980 .notifier_call
= ieee80211_rcv_dev_event
988 static char *version
= RELEASE_VERSION
;
989 static char *dev_info
= "wlan";
992 MODULE_AUTHOR("Errno Consulting, Sam Leffler");
993 MODULE_DESCRIPTION("802.11 wireless LAN protocol support");
994 #ifdef MODULE_VERSION
995 MODULE_VERSION(RELEASE_VERSION
);
997 #ifdef MODULE_LICENSE
998 MODULE_LICENSE("Dual BSD/GPL");
1001 extern void ieee80211_auth_setup(void);
1006 register_netdevice_notifier(&ieee80211_event_block
);
1009 module_init(init_wlan
);
1014 unregister_netdevice_notifier(&ieee80211_event_block
);
1016 module_exit(exit_wlan
);