diff options
Diffstat (limited to 'net/core/wireless.c')
| -rw-r--r-- | net/core/wireless.c | 79 |
1 files changed, 58 insertions, 21 deletions
diff --git a/net/core/wireless.c b/net/core/wireless.c index d2bc72d318f7..ffff0da46c6e 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
| @@ -68,11 +68,18 @@ | |||
| 68 | * | 68 | * |
| 69 | * v8 - 17.02.06 - Jean II | 69 | * v8 - 17.02.06 - Jean II |
| 70 | * o RtNetlink requests support (SET/GET) | 70 | * o RtNetlink requests support (SET/GET) |
| 71 | * | ||
| 72 | * v8b - 03.08.06 - Herbert Xu | ||
| 73 | * o Fix Wireless Event locking issues. | ||
| 74 | * | ||
| 75 | * v9 - 14.3.06 - Jean II | ||
| 76 | * o Change length in ESSID and NICK to strlen() instead of strlen()+1 | ||
| 77 | * o Make standard_ioctl_num and standard_event_num unsigned | ||
| 78 | * o Remove (struct net_device *)->get_wireless_stats() | ||
| 71 | */ | 79 | */ |
| 72 | 80 | ||
| 73 | /***************************** INCLUDES *****************************/ | 81 | /***************************** INCLUDES *****************************/ |
| 74 | 82 | ||
| 75 | #include <linux/config.h> /* Not needed ??? */ | ||
| 76 | #include <linux/module.h> | 83 | #include <linux/module.h> |
| 77 | #include <linux/types.h> /* off_t */ | 84 | #include <linux/types.h> /* off_t */ |
| 78 | #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ | 85 | #include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ |
| @@ -82,9 +89,11 @@ | |||
| 82 | #include <linux/init.h> /* for __init */ | 89 | #include <linux/init.h> /* for __init */ |
| 83 | #include <linux/if_arp.h> /* ARPHRD_ETHER */ | 90 | #include <linux/if_arp.h> /* ARPHRD_ETHER */ |
| 84 | #include <linux/etherdevice.h> /* compare_ether_addr */ | 91 | #include <linux/etherdevice.h> /* compare_ether_addr */ |
| 92 | #include <linux/interrupt.h> | ||
| 85 | 93 | ||
| 86 | #include <linux/wireless.h> /* Pretty obvious */ | 94 | #include <linux/wireless.h> /* Pretty obvious */ |
| 87 | #include <net/iw_handler.h> /* New driver API */ | 95 | #include <net/iw_handler.h> /* New driver API */ |
| 96 | #include <net/netlink.h> | ||
| 88 | 97 | ||
| 89 | #include <asm/uaccess.h> /* copy_to_user() */ | 98 | #include <asm/uaccess.h> /* copy_to_user() */ |
| 90 | 99 | ||
| @@ -233,24 +242,24 @@ static const struct iw_ioctl_description standard_ioctl[] = { | |||
| 233 | [SIOCSIWESSID - SIOCIWFIRST] = { | 242 | [SIOCSIWESSID - SIOCIWFIRST] = { |
| 234 | .header_type = IW_HEADER_TYPE_POINT, | 243 | .header_type = IW_HEADER_TYPE_POINT, |
| 235 | .token_size = 1, | 244 | .token_size = 1, |
| 236 | .max_tokens = IW_ESSID_MAX_SIZE + 1, | 245 | .max_tokens = IW_ESSID_MAX_SIZE, |
| 237 | .flags = IW_DESCR_FLAG_EVENT, | 246 | .flags = IW_DESCR_FLAG_EVENT, |
| 238 | }, | 247 | }, |
| 239 | [SIOCGIWESSID - SIOCIWFIRST] = { | 248 | [SIOCGIWESSID - SIOCIWFIRST] = { |
| 240 | .header_type = IW_HEADER_TYPE_POINT, | 249 | .header_type = IW_HEADER_TYPE_POINT, |
| 241 | .token_size = 1, | 250 | .token_size = 1, |
| 242 | .max_tokens = IW_ESSID_MAX_SIZE + 1, | 251 | .max_tokens = IW_ESSID_MAX_SIZE, |
| 243 | .flags = IW_DESCR_FLAG_DUMP, | 252 | .flags = IW_DESCR_FLAG_DUMP, |
| 244 | }, | 253 | }, |
| 245 | [SIOCSIWNICKN - SIOCIWFIRST] = { | 254 | [SIOCSIWNICKN - SIOCIWFIRST] = { |
| 246 | .header_type = IW_HEADER_TYPE_POINT, | 255 | .header_type = IW_HEADER_TYPE_POINT, |
| 247 | .token_size = 1, | 256 | .token_size = 1, |
| 248 | .max_tokens = IW_ESSID_MAX_SIZE + 1, | 257 | .max_tokens = IW_ESSID_MAX_SIZE, |
| 249 | }, | 258 | }, |
| 250 | [SIOCGIWNICKN - SIOCIWFIRST] = { | 259 | [SIOCGIWNICKN - SIOCIWFIRST] = { |
| 251 | .header_type = IW_HEADER_TYPE_POINT, | 260 | .header_type = IW_HEADER_TYPE_POINT, |
| 252 | .token_size = 1, | 261 | .token_size = 1, |
| 253 | .max_tokens = IW_ESSID_MAX_SIZE + 1, | 262 | .max_tokens = IW_ESSID_MAX_SIZE, |
| 254 | }, | 263 | }, |
| 255 | [SIOCSIWRATE - SIOCIWFIRST] = { | 264 | [SIOCSIWRATE - SIOCIWFIRST] = { |
| 256 | .header_type = IW_HEADER_TYPE_PARAM, | 265 | .header_type = IW_HEADER_TYPE_PARAM, |
| @@ -337,8 +346,8 @@ static const struct iw_ioctl_description standard_ioctl[] = { | |||
| 337 | .max_tokens = sizeof(struct iw_pmksa), | 346 | .max_tokens = sizeof(struct iw_pmksa), |
| 338 | }, | 347 | }, |
| 339 | }; | 348 | }; |
| 340 | static const int standard_ioctl_num = (sizeof(standard_ioctl) / | 349 | static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) / |
| 341 | sizeof(struct iw_ioctl_description)); | 350 | sizeof(struct iw_ioctl_description)); |
| 342 | 351 | ||
| 343 | /* | 352 | /* |
| 344 | * Meta-data about all the additional standard Wireless Extension events | 353 | * Meta-data about all the additional standard Wireless Extension events |
| @@ -388,8 +397,8 @@ static const struct iw_ioctl_description standard_event[] = { | |||
| 388 | .max_tokens = sizeof(struct iw_pmkid_cand), | 397 | .max_tokens = sizeof(struct iw_pmkid_cand), |
| 389 | }, | 398 | }, |
| 390 | }; | 399 | }; |
| 391 | static const int standard_event_num = (sizeof(standard_event) / | 400 | static const unsigned standard_event_num = (sizeof(standard_event) / |
| 392 | sizeof(struct iw_ioctl_description)); | 401 | sizeof(struct iw_ioctl_description)); |
| 393 | 402 | ||
| 394 | /* Size (in bytes) of the various private data types */ | 403 | /* Size (in bytes) of the various private data types */ |
| 395 | static const char iw_priv_type_size[] = { | 404 | static const char iw_priv_type_size[] = { |
| @@ -464,17 +473,6 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) | |||
| 464 | (dev->wireless_handlers->get_wireless_stats != NULL)) | 473 | (dev->wireless_handlers->get_wireless_stats != NULL)) |
| 465 | return dev->wireless_handlers->get_wireless_stats(dev); | 474 | return dev->wireless_handlers->get_wireless_stats(dev); |
| 466 | 475 | ||
| 467 | /* Old location, field to be removed in next WE */ | ||
| 468 | if(dev->get_wireless_stats) { | ||
| 469 | static int printed_message; | ||
| 470 | |||
| 471 | if (!printed_message++) | ||
| 472 | printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", | ||
| 473 | dev->name); | ||
| 474 | |||
| 475 | return dev->get_wireless_stats(dev); | ||
| 476 | } | ||
| 477 | |||
| 478 | /* Not found */ | 476 | /* Not found */ |
| 479 | return (struct iw_statistics *) NULL; | 477 | return (struct iw_statistics *) NULL; |
| 480 | } | 478 | } |
| @@ -1844,6 +1842,43 @@ int wireless_rtnetlink_set(struct net_device * dev, | |||
| 1844 | #ifdef WE_EVENT_RTNETLINK | 1842 | #ifdef WE_EVENT_RTNETLINK |
| 1845 | /* ---------------------------------------------------------------- */ | 1843 | /* ---------------------------------------------------------------- */ |
| 1846 | /* | 1844 | /* |
| 1845 | * Locking... | ||
| 1846 | * ---------- | ||
| 1847 | * | ||
| 1848 | * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing | ||
| 1849 | * the locking issue in here and implementing this code ! | ||
| 1850 | * | ||
| 1851 | * The issue : wireless_send_event() is often called in interrupt context, | ||
| 1852 | * while the Netlink layer can never be called in interrupt context. | ||
| 1853 | * The fully formed RtNetlink events are queued, and then a tasklet is run | ||
| 1854 | * to feed those to Netlink. | ||
| 1855 | * The skb_queue is interrupt safe, and its lock is not held while calling | ||
| 1856 | * Netlink, so there is no possibility of dealock. | ||
| 1857 | * Jean II | ||
| 1858 | */ | ||
| 1859 | |||
| 1860 | static struct sk_buff_head wireless_nlevent_queue; | ||
| 1861 | |||
| 1862 | static int __init wireless_nlevent_init(void) | ||
| 1863 | { | ||
| 1864 | skb_queue_head_init(&wireless_nlevent_queue); | ||
| 1865 | return 0; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | subsys_initcall(wireless_nlevent_init); | ||
| 1869 | |||
| 1870 | static void wireless_nlevent_process(unsigned long data) | ||
| 1871 | { | ||
| 1872 | struct sk_buff *skb; | ||
| 1873 | |||
| 1874 | while ((skb = skb_dequeue(&wireless_nlevent_queue))) | ||
| 1875 | rtnl_notify(skb, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); | ||
| 1879 | |||
| 1880 | /* ---------------------------------------------------------------- */ | ||
| 1881 | /* | ||
| 1847 | * Fill a rtnetlink message with our event data. | 1882 | * Fill a rtnetlink message with our event data. |
| 1848 | * Note that we propage only the specified event and don't dump the | 1883 | * Note that we propage only the specified event and don't dump the |
| 1849 | * current wireless config. Dumping the wireless config is far too | 1884 | * current wireless config. Dumping the wireless config is far too |
| @@ -1904,8 +1939,10 @@ static inline void rtmsg_iwinfo(struct net_device * dev, | |||
| 1904 | return; | 1939 | return; |
| 1905 | } | 1940 | } |
| 1906 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; | 1941 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; |
| 1907 | netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); | 1942 | skb_queue_tail(&wireless_nlevent_queue, skb); |
| 1943 | tasklet_schedule(&wireless_nlevent_tasklet); | ||
| 1908 | } | 1944 | } |
| 1945 | |||
| 1909 | #endif /* WE_EVENT_RTNETLINK */ | 1946 | #endif /* WE_EVENT_RTNETLINK */ |
| 1910 | 1947 | ||
| 1911 | /* ---------------------------------------------------------------- */ | 1948 | /* ---------------------------------------------------------------- */ |
