update madwifi
[linux-2.6/zen-sources.git] / drivers / net / wireless / madwifi / net80211 / ieee80211_linux.c
blob3016c9bd61260d2b4d322ccb36072d2bb52945e4
1 /*-
2 * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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 $
29 #ifndef EXPORT_SYMTAB
30 #define EXPORT_SYMTAB
31 #endif
34 * IEEE 802.11 support (Linux-specific code)
36 #ifndef AUTOCONF_INCLUDED
37 #include <linux/config.h>
38 #endif
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>
57 #include "if_media.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
69 * else: reserved */
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)
74 #else
75 static ssize_t show_madwifi_name_type(struct class_device *cdev,
76 char *buf)
77 #endif
79 ssize_t len = 0;
81 len = snprintf(buf, PAGE_SIZE, "1");
83 return len;
86 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
87 static DEVICE_ATTR(madwifi_name_type, S_IRUGO, show_madwifi_name_type, NULL);
88 #else
89 static CLASS_DEVICE_ATTR(madwifi_name_type, S_IRUGO, show_madwifi_name_type, NULL);
90 #endif
92 static struct attribute *ieee80211_sysfs_attrs[] = {
93 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
94 &dev_attr_madwifi_name_type.attr,
95 #else
96 &class_device_attr_madwifi_name_type.attr,
97 #endif
98 NULL
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
109 #endif
112 * Print a console message with the device name prepended.
114 void
115 if_printf(struct net_device *dev, const char *fmt, ...)
117 va_list ap;
118 char buf[512]; /* XXX */
120 va_start(ap, fmt);
121 vsnprintf(buf, sizeof(buf), fmt, ap);
122 va_end(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.
136 struct sk_buff *
137 #ifdef IEEE80211_DEBUG_REFCNT
138 ieee80211_getmgtframe_debug(u_int8_t **frm, u_int pktlen,
139 const char *func, int line)
140 #else
141 ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen)
142 #endif
144 const u_int align = sizeof(u_int32_t);
145 struct sk_buff *skb;
146 u_int len;
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);
151 #else
152 skb = ieee80211_dev_alloc_skb(len + align - 1);
153 #endif
154 if (skb != NULL) {
155 u_int off = ((unsigned long) skb->data) % align;
156 if (off != 0)
157 skb_reserve(skb, align - off);
159 SKB_NI(skb) = NULL;
160 SKB_CB(skb)->flags = 0;
162 skb_reserve(skb, sizeof(struct ieee80211_frame));
163 *frm = skb_put(skb, pktlen);
165 return skb;
167 #ifdef IEEE80211_DEBUG_REFCNT
168 EXPORT_SYMBOL(ieee80211_getmgtframe_debug);
169 #else
170 EXPORT_SYMBOL(ieee80211_getmgtframe);
171 #endif
173 #if IEEE80211_VLAN_TAG_USED
175 * VLAN support.
179 * Register a vlan group.
181 static void
182 ieee80211_vlan_register(struct net_device *dev, struct vlan_group *grp)
184 struct ieee80211vap *vap = dev->priv;
186 vap->iv_vlgrp = grp;
190 * Add an rx vlan identifier
192 static void
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.
204 static void
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 */
214 void
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 */
228 void
229 ieee80211_vlan_vdetach(struct ieee80211vap *vap)
233 void
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) {
241 if (newassoc)
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;
246 #ifdef ATH_SUPERG_XR
247 if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
248 dev = vap->iv_xrvap->iv_dev;
249 #endif
250 wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
251 } else {
252 memset(&wreq, 0, sizeof(wreq));
253 IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
254 wreq.addr.sa_family = ARPHRD_ETHER;
255 #ifdef ATH_SUPERG_XR
256 if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
257 dev = vap->iv_xrvap->iv_dev;
258 #endif
259 wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
263 void
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);
275 } else {
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);
284 void
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;
291 char buf[1024];
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);
304 void
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;
314 wreq.data.flags = 0;
315 wireless_send_event(dev, SIOCGIWSCAN, &wreq, NULL);
318 void
319 ieee80211_notify_replay_failure(struct ieee80211vap *vap,
320 const struct ieee80211_frame *wh, const struct ieee80211_key *k,
321 u_int64_t rsc)
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,
335 k->wk_keyix,
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);
344 void
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:
368 * Context: process
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)
381 #ifdef CONFIG_KMOD
382 int rv;
383 rv = request_module("%s", modname);
384 if (rv < 0)
385 printk(KERN_ERR "failed to automatically load module: %s; " \
386 "errno: %d\n", modname, rv);
387 return rv;
388 #else /* CONFIG_KMOD */
389 printk(KERN_ERR "Unable to load needed module: %s; no support for " \
390 "automatic module loading\n", modname);
391 return -ENOSYS;
392 #endif /* CONFIG_KMOD */
396 static struct proc_dir_entry *proc_madwifi;
397 static int proc_madwifi_count = 0;
399 static int
400 proc_read_nodes(struct ieee80211vap *vap, char *buf, int space)
402 char *p = buf;
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) {
409 struct timespec t;
411 /* Assume each node needs 500 bytes */
412 if (buf + space < p + 500)
413 break;
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);
428 return (p - buf);
431 static ssize_t
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;
438 if (!pv->rbuf)
439 return -EINVAL;
440 if (pos < 0)
441 return -EINVAL;
442 if (pos > pv->rlen)
443 return -EFAULT;
444 if (len > pv->rlen - pos)
445 len = pv->rlen - pos;
446 if (copy_to_user(buf, pv->rbuf + pos, len))
447 return -EFAULT;
448 *offset = pos + len;
449 return len;
452 static int
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),
460 GFP_KERNEL)))
461 return -ENOMEM;
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);
465 if (!pv->rbuf) {
466 kfree(pv);
467 return -ENOMEM;
469 pv->wbuf = vmalloc(MAX_PROC_IEEE80211_SIZE);
470 if (!pv->wbuf) {
471 vfree(pv->rbuf);
472 kfree(pv);
473 return -ENOMEM;
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);
481 return 0;
484 static ssize_t
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;
491 if (!pv->wbuf)
492 return -EINVAL;
493 if (pos < 0)
494 return -EINVAL;
495 if (pos >= pv->max_wlen)
496 return 0;
497 if (len > pv->max_wlen - pos)
498 len = pv->max_wlen - pos;
499 if (copy_from_user(pv->wbuf + pos, buf, len))
500 return -EFAULT;
501 if (pos + len > pv->wlen)
502 pv->wlen = pos + len;
503 *offset = pos + len;
505 return len;
508 static int
509 proc_ieee80211_close(struct inode *inode, struct file *file)
511 struct proc_ieee80211_priv *pv =
512 (struct proc_ieee80211_priv *)file->private_data;
513 if (pv->rbuf)
514 vfree(pv->rbuf);
515 if (pv->wbuf)
516 vfree(pv->wbuf);
517 kfree(pv);
518 return 0;
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
529 static int
530 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_debug, ctl, write, filp, buffer,
531 lenp, ppos)
533 struct ieee80211vap *vap = ctl->extra1;
534 u_int val;
535 int ret;
537 ctl->data = &val;
538 ctl->maxlen = sizeof(val);
539 if (write) {
540 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
541 lenp, ppos);
542 if (ret == 0) {
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);
548 } else {
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,
552 lenp, ppos);
554 return ret;
556 #endif /* IEEE80211_DEBUG */
558 static int
559 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_dev_type, ctl, write, filp, buffer,
560 lenp, ppos)
562 struct ieee80211vap *vap = ctl->extra1;
563 u_int val;
564 int ret;
566 ctl->data = &val;
567 ctl->maxlen = sizeof(val);
568 if (write) {
569 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
570 lenp, ppos);
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;
579 } else {
580 val = vap->iv_dev->type;
581 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
582 lenp, ppos);
584 return ret;
587 static int
588 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_nods_only, ctl, write, filp, buffer,
589 lenp, ppos)
591 struct ieee80211vap *vap = ctl->extra1;
592 u_int val;
593 int ret;
595 ctl->data = &val;
596 ctl->maxlen = sizeof(val);
597 if (write) {
598 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
599 lenp, ppos);
600 if (ret == 0)
601 vap->iv_monitor_nods_only = val;
602 } else {
603 val = vap->iv_monitor_nods_only;
604 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
605 lenp, ppos);
607 return ret;
610 static int
611 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_txf_len, ctl, write, filp, buffer,
612 lenp, ppos)
614 struct ieee80211vap *vap = ctl->extra1;
615 u_int val;
616 int ret;
618 ctl->data = &val;
619 ctl->maxlen = sizeof(val);
620 if (write) {
621 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
622 lenp, ppos);
623 if (ret == 0)
624 vap->iv_monitor_txf_len = val;
625 } else {
626 val = vap->iv_monitor_txf_len;
627 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
628 lenp, ppos);
630 return ret;
633 static int
634 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_phy_errors, ctl, write, filp, buffer,
635 lenp, ppos)
637 struct ieee80211vap *vap = ctl->extra1;
638 u_int val;
639 int ret;
641 ctl->data = &val;
642 ctl->maxlen = sizeof(val);
643 if (write) {
644 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
645 lenp, ppos);
646 if (ret == 0)
647 vap->iv_monitor_phy_errors = val;
648 } else {
649 val = vap->iv_monitor_phy_errors;
650 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
651 lenp, ppos);
653 return ret;
656 static int
657 IEEE80211_SYSCTL_DECL(ieee80211_sysctl_monitor_crc_errors, ctl, write, filp, buffer,
658 lenp, ppos)
660 struct ieee80211vap *vap = ctl->extra1;
661 u_int val;
662 int ret;
664 ctl->data = &val;
665 ctl->maxlen = sizeof(val);
666 if (write) {
667 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
668 lenp, ppos);
669 if (ret == 0)
670 vap->iv_monitor_crc_errors = val;
671 } else {
672 val = vap->iv_monitor_crc_errors;
673 ret = IEEE80211_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer,
674 lenp, ppos);
676 return ret;
679 static const ctl_table ieee80211_sysctl_template[] = {
680 #ifdef IEEE80211_DEBUG
681 { .ctl_name = CTL_AUTO,
682 .procname = "debug",
683 .mode = 0644,
684 .proc_handler = ieee80211_sysctl_debug
686 #endif
687 { .ctl_name = CTL_AUTO,
688 .procname = "dev_type",
689 .mode = 0644,
690 .proc_handler = ieee80211_sysctl_dev_type
692 { .ctl_name = CTL_AUTO,
693 .procname = "monitor_nods_only",
694 .mode = 0644,
695 .proc_handler = ieee80211_sysctl_monitor_nods_only
697 { .ctl_name = CTL_AUTO,
698 .procname = "monitor_txf_len",
699 .mode = 0644,
700 .proc_handler = ieee80211_sysctl_monitor_txf_len
702 { .ctl_name = CTL_AUTO,
703 .procname = "monitor_phy_errors",
704 .mode = 0644,
705 .proc_handler = ieee80211_sysctl_monitor_phy_errors
707 { .ctl_name = CTL_AUTO,
708 .procname = "monitor_crc_errors",
709 .mode = 0644,
710 .proc_handler = ieee80211_sysctl_monitor_crc_errors
712 /* NB: must be last entry before NULL */
713 { .ctl_name = CTL_AUTO,
714 .procname = "%parent",
715 .maxlen = IFNAMSIZ,
716 .mode = 0444,
717 .proc_handler = proc_dostring
719 { 0 }
722 void
723 ieee80211_virtfs_latevattach(struct ieee80211vap *vap)
725 int i, space;
726 char *devname = NULL;
727 struct ieee80211_proc_entry *tmp = NULL;
728 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
729 int ret;
731 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
732 ret = sysfs_create_group(&vap->iv_dev->dev.kobj, &ieee80211_attr_grp);
733 #else
734 ret = sysfs_create_group(&vap->iv_dev->class_dev.kobj, &ieee80211_attr_grp);
735 #endif
736 if (ret) {
737 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
738 sysfs_remove_group(&vap->iv_dev->dev.kobj, &ieee80211_attr_grp);
739 #else
740 sysfs_remove_group(&vap->iv_dev->class_dev.kobj, &ieee80211_attr_grp);
741 #endif
742 printk("%s: %s - unable to create sysfs attribute group\n",
743 __func__, vap->iv_dev->name);
744 return;
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__);
752 return;
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__);
762 return;
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);
793 kfree(devname);
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);
801 if (!proc_madwifi)
802 printk(KERN_WARNING "Failed to mkdir /proc/net/madwifi\n");
805 /* Create a proc directory named after the VAP */
806 if (proc_madwifi) {
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 */
815 if (vap->iv_proc) {
816 tmp = vap->iv_proc_entries;
817 while (tmp) {
818 if (!tmp->entry) {
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;
824 tmp = tmp->next;
829 /* Frees all memory used for the list of proc entries */
830 void
831 ieee80211_proc_cleanup(struct ieee80211vap *vap)
833 struct ieee80211_proc_entry *tmp = vap->iv_proc_entries;
834 struct ieee80211_proc_entry *next = NULL;
835 while (tmp) {
836 next = tmp->next;
837 kfree(tmp);
838 tmp = next;
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;
853 do {
854 if (strcmp(tmp->name, name)==0)
855 return -1;
856 /* Check for end of list */
857 if (!tmp->next)
858 break;
859 /* Otherwise move on */
860 tmp = tmp->next;
861 } while (1);
864 /* Create an item in our list for the new entry */
865 entry = kmalloc(sizeof(struct ieee80211_proc_entry), GFP_KERNEL);
866 if (entry == NULL) {
867 printk("%s: no memory for new proc entry (%s)!\n", __func__,
868 name);
869 return -1;
872 /* Replace null fileops pointers with our standard functions */
873 if (!fileops->open)
874 fileops->open = proc_ieee80211_open;
875 if (!fileops->release)
876 fileops->release = proc_ieee80211_close;
877 if (!fileops->read)
878 fileops->read = proc_ieee80211_read;
879 if (!fileops->write)
880 fileops->write = proc_ieee80211_write;
882 /* Create the entry record */
883 entry->name = name;
884 entry->fileops = fileops;
885 entry->next = NULL;
886 entry->entry = NULL;
888 /* Create the actual proc entry */
889 if (vap->iv_proc) {
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 */
897 if (!tmp) {
898 /* Add to the start */
899 vap->iv_proc_entries = entry;
900 } else {
901 /* Add to the end */
902 tmp->next = entry;
905 return 0;
907 EXPORT_SYMBOL(ieee80211_proc_vcreate);
909 void
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);
918 #endif
920 if (vap->iv_sysctl_header) {
921 unregister_sysctl_table(vap->iv_sysctl_header);
922 vap->iv_sysctl_header = NULL;
925 if (vap->iv_proc) {
926 /* Remove child proc entries but leave them in the list */
927 tmp = vap->iv_proc_entries;
928 while (tmp) {
929 if (tmp->entry) {
930 remove_proc_entry(tmp->name, vap->iv_proc);
931 tmp->entry = NULL;
933 tmp = tmp->next;
935 remove_proc_entry(vap->iv_proc->name, proc_madwifi);
936 if (proc_madwifi_count == 1) {
937 remove_proc_entry("madwifi", proc_net);
938 proc_madwifi = NULL;
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.
960 static int
961 ieee80211_rcv_dev_event(struct notifier_block *this, unsigned long event,
962 void *ptr)
964 struct net_device *dev = (struct net_device *)ptr;
965 if (!dev || dev->open != &ieee80211_open)
966 return 0;
968 switch (event) {
969 case NETDEV_CHANGENAME:
970 ieee80211_virtfs_vdetach(dev->priv);
971 ieee80211_virtfs_latevattach(dev->priv);
972 return NOTIFY_DONE;
973 default:
974 break;
976 return 0;
979 static struct notifier_block ieee80211_event_block = {
980 .notifier_call = ieee80211_rcv_dev_event
984 * Module glue.
986 #include "release.h"
987 #if 0
988 static char *version = RELEASE_VERSION;
989 static char *dev_info = "wlan";
990 #endif
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);
996 #endif
997 #ifdef MODULE_LICENSE
998 MODULE_LICENSE("Dual BSD/GPL");
999 #endif
1001 extern void ieee80211_auth_setup(void);
1003 static int __init
1004 init_wlan(void)
1006 register_netdevice_notifier(&ieee80211_event_block);
1007 return 0;
1009 module_init(init_wlan);
1011 static void __exit
1012 exit_wlan(void)
1014 unregister_netdevice_notifier(&ieee80211_event_block);
1016 module_exit(exit_wlan);