aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/core/rtnetlink.c98
-rw-r--r--net/core/wireless.c911
-rw-r--r--net/ieee80211/Kconfig1
-rw-r--r--net/ieee80211/Makefile1
-rw-r--r--net/ieee80211/ieee80211_rx.c74
-rw-r--r--net/ieee80211/softmac/Kconfig10
-rw-r--r--net/ieee80211/softmac/Makefile9
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c396
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c364
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c159
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c474
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c457
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h230
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c244
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c412
15 files changed, 3751 insertions, 89 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ae10d3740faa..3fcfa9c59e1f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -51,6 +51,10 @@
51#include <net/sock.h> 51#include <net/sock.h>
52#include <net/pkt_sched.h> 52#include <net/pkt_sched.h>
53#include <net/netlink.h> 53#include <net/netlink.h>
54#ifdef CONFIG_NET_WIRELESS_RTNETLINK
55#include <linux/wireless.h>
56#include <net/iw_handler.h>
57#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
54 58
55static DEFINE_MUTEX(rtnl_mutex); 59static DEFINE_MUTEX(rtnl_mutex);
56 60
@@ -467,6 +471,17 @@ static int do_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
467 goto out; 471 goto out;
468 } 472 }
469 473
474#ifdef CONFIG_NET_WIRELESS_RTNETLINK
475 if (ida[IFLA_WIRELESS - 1]) {
476
477 /* Call Wireless Extensions.
478 * Various stuff checked in there... */
479 err = wireless_rtnetlink_set(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len);
480 if (err)
481 goto out;
482 }
483#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
484
470 err = 0; 485 err = 0;
471 486
472out: 487out:
@@ -477,6 +492,83 @@ out:
477 return err; 492 return err;
478} 493}
479 494
495#ifdef CONFIG_NET_WIRELESS_RTNETLINK
496static int do_getlink(struct sk_buff *in_skb, struct nlmsghdr* in_nlh, void *arg)
497{
498 struct ifinfomsg *ifm = NLMSG_DATA(in_nlh);
499 struct rtattr **ida = arg;
500 struct net_device *dev;
501 struct ifinfomsg *r;
502 struct nlmsghdr *nlh;
503 int err = -ENOBUFS;
504 struct sk_buff *skb;
505 unsigned char *b;
506 char *iw_buf = NULL;
507 int iw_buf_len = 0;
508
509 if (ifm->ifi_index >= 0)
510 dev = dev_get_by_index(ifm->ifi_index);
511 else
512 return -EINVAL;
513 if (!dev)
514 return -ENODEV;
515
516#ifdef CONFIG_NET_WIRELESS_RTNETLINK
517 if (ida[IFLA_WIRELESS - 1]) {
518
519 /* Call Wireless Extensions. We need to know the size before
520 * we can alloc. Various stuff checked in there... */
521 err = wireless_rtnetlink_get(dev, RTA_DATA(ida[IFLA_WIRELESS - 1]), ida[IFLA_WIRELESS - 1]->rta_len, &iw_buf, &iw_buf_len);
522 if (err)
523 goto out;
524 }
525#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
526
527 /* Create a skb big enough to include all the data.
528 * Some requests are way bigger than 4k... Jean II */
529 skb = alloc_skb((NLMSG_LENGTH(sizeof(*r))) + (RTA_SPACE(iw_buf_len)),
530 GFP_KERNEL);
531 if (!skb)
532 goto out;
533 b = skb->tail;
534
535 /* Put in the message the usual good stuff */
536 nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid, in_nlh->nlmsg_seq,
537 RTM_NEWLINK, sizeof(*r));
538 r = NLMSG_DATA(nlh);
539 r->ifi_family = AF_UNSPEC;
540 r->__ifi_pad = 0;
541 r->ifi_type = dev->type;
542 r->ifi_index = dev->ifindex;
543 r->ifi_flags = dev->flags;
544 r->ifi_change = 0;
545
546 /* Put the wireless payload if it exist */
547 if(iw_buf != NULL)
548 RTA_PUT(skb, IFLA_WIRELESS, iw_buf_len,
549 iw_buf + IW_EV_POINT_OFF);
550
551 nlh->nlmsg_len = skb->tail - b;
552
553 /* Needed ? */
554 NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
555
556 err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
557 if (err > 0)
558 err = 0;
559out:
560 if(iw_buf != NULL)
561 kfree(iw_buf);
562 dev_put(dev);
563 return err;
564
565rtattr_failure:
566nlmsg_failure:
567 kfree_skb(skb);
568 goto out;
569}
570#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
571
480static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb) 572static int rtnetlink_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
481{ 573{
482 int idx; 574 int idx;
@@ -642,7 +734,11 @@ static void rtnetlink_rcv(struct sock *sk, int len)
642 734
643static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] = 735static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =
644{ 736{
645 [RTM_GETLINK - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo }, 737 [RTM_GETLINK - RTM_BASE] = {
738#ifdef CONFIG_NET_WIRELESS_RTNETLINK
739 .doit = do_getlink,
740#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
741 .dumpit = rtnetlink_dump_ifinfo },
646 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink }, 742 [RTM_SETLINK - RTM_BASE] = { .doit = do_setlink },
647 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 743 [RTM_GETADDR - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
648 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all }, 744 [RTM_GETROUTE - RTM_BASE] = { .dumpit = rtnetlink_dump_all },
diff --git a/net/core/wireless.c b/net/core/wireless.c
index 2add7ed609e9..81d6995fcfdb 100644
--- a/net/core/wireless.c
+++ b/net/core/wireless.c
@@ -2,7 +2,7 @@
2 * This file implement the Wireless Extensions APIs. 2 * This file implement the Wireless Extensions APIs.
3 * 3 *
4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> 4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
5 * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved. 5 * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
6 * 6 *
7 * (As all part of the Linux kernel, this file is GPL) 7 * (As all part of the Linux kernel, this file is GPL)
8 */ 8 */
@@ -65,6 +65,9 @@
65 * o Start deprecating dev->get_wireless_stats, output a warning 65 * o Start deprecating dev->get_wireless_stats, output a warning
66 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless 66 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
67 * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) 67 * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats)
68 *
69 * v8 - 17.02.06 - Jean II
70 * o RtNetlink requests support (SET/GET)
68 */ 71 */
69 72
70/***************************** INCLUDES *****************************/ 73/***************************** INCLUDES *****************************/
@@ -89,11 +92,13 @@
89 92
90/* Debugging stuff */ 93/* Debugging stuff */
91#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ 94#undef WE_IOCTL_DEBUG /* Debug IOCTL API */
95#undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */
92#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ 96#undef WE_EVENT_DEBUG /* Debug Event dispatcher */
93#undef WE_SPY_DEBUG /* Debug enhanced spy support */ 97#undef WE_SPY_DEBUG /* Debug enhanced spy support */
94 98
95/* Options */ 99/* Options */
96#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ 100//CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */
101#define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */
97#define WE_SET_EVENT /* Generate an event on some set commands */ 102#define WE_SET_EVENT /* Generate an event on some set commands */
98 103
99/************************* GLOBAL VARIABLES *************************/ 104/************************* GLOBAL VARIABLES *************************/
@@ -156,13 +161,18 @@ static const struct iw_ioctl_description standard_ioctl[] = {
156 .header_type = IW_HEADER_TYPE_NULL, 161 .header_type = IW_HEADER_TYPE_NULL,
157 }, 162 },
158 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 163 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */
159 .header_type = IW_HEADER_TYPE_NULL, 164 .header_type = IW_HEADER_TYPE_POINT,
165 .token_size = sizeof(struct iw_priv_args),
166 .max_tokens = 16,
167 .flags = IW_DESCR_FLAG_NOMAX,
160 }, 168 },
161 [SIOCSIWSTATS - SIOCIWFIRST] = { 169 [SIOCSIWSTATS - SIOCIWFIRST] = {
162 .header_type = IW_HEADER_TYPE_NULL, 170 .header_type = IW_HEADER_TYPE_NULL,
163 }, 171 },
164 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 172 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */
165 .header_type = IW_HEADER_TYPE_NULL, 173 .header_type = IW_HEADER_TYPE_POINT,
174 .token_size = 1,
175 .max_tokens = sizeof(struct iw_statistics),
166 .flags = IW_DESCR_FLAG_DUMP, 176 .flags = IW_DESCR_FLAG_DUMP,
167 }, 177 },
168 [SIOCSIWSPY - SIOCIWFIRST] = { 178 [SIOCSIWSPY - SIOCIWFIRST] = {
@@ -529,6 +539,70 @@ static inline int adjust_priv_size(__u16 args,
529 return num * iw_priv_type_size[type]; 539 return num * iw_priv_type_size[type];
530} 540}
531 541
542/* ---------------------------------------------------------------- */
543/*
544 * Standard Wireless Handler : get wireless stats
545 * Allow programatic access to /proc/net/wireless even if /proc
546 * doesn't exist... Also more efficient...
547 */
548static int iw_handler_get_iwstats(struct net_device * dev,
549 struct iw_request_info * info,
550 union iwreq_data * wrqu,
551 char * extra)
552{
553 /* Get stats from the driver */
554 struct iw_statistics *stats;
555
556 stats = get_wireless_stats(dev);
557 if (stats != (struct iw_statistics *) NULL) {
558
559 /* Copy statistics to extra */
560 memcpy(extra, stats, sizeof(struct iw_statistics));
561 wrqu->data.length = sizeof(struct iw_statistics);
562
563 /* Check if we need to clear the updated flag */
564 if(wrqu->data.flags != 0)
565 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
566 return 0;
567 } else
568 return -EOPNOTSUPP;
569}
570
571/* ---------------------------------------------------------------- */
572/*
573 * Standard Wireless Handler : get iwpriv definitions
574 * Export the driver private handler definition
575 * They will be picked up by tools like iwpriv...
576 */
577static int iw_handler_get_private(struct net_device * dev,
578 struct iw_request_info * info,
579 union iwreq_data * wrqu,
580 char * extra)
581{
582 /* Check if the driver has something to export */
583 if((dev->wireless_handlers->num_private_args == 0) ||
584 (dev->wireless_handlers->private_args == NULL))
585 return -EOPNOTSUPP;
586
587 /* Check if there is enough buffer up there */
588 if(wrqu->data.length < dev->wireless_handlers->num_private_args) {
589 /* User space can't know in advance how large the buffer
590 * needs to be. Give it a hint, so that we can support
591 * any size buffer we want somewhat efficiently... */
592 wrqu->data.length = dev->wireless_handlers->num_private_args;
593 return -E2BIG;
594 }
595
596 /* Set the number of available ioctls. */
597 wrqu->data.length = dev->wireless_handlers->num_private_args;
598
599 /* Copy structure to the user buffer. */
600 memcpy(extra, dev->wireless_handlers->private_args,
601 sizeof(struct iw_priv_args) * wrqu->data.length);
602
603 return 0;
604}
605
532 606
533/******************** /proc/net/wireless SUPPORT ********************/ 607/******************** /proc/net/wireless SUPPORT ********************/
534/* 608/*
@@ -630,81 +704,14 @@ int __init wireless_proc_init(void)
630 704
631/* ---------------------------------------------------------------- */ 705/* ---------------------------------------------------------------- */
632/* 706/*
633 * Allow programatic access to /proc/net/wireless even if /proc
634 * doesn't exist... Also more efficient...
635 */
636static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
637{
638 /* Get stats from the driver */
639 struct iw_statistics *stats;
640
641 stats = get_wireless_stats(dev);
642 if (stats != (struct iw_statistics *) NULL) {
643 struct iwreq * wrq = (struct iwreq *)ifr;
644
645 /* Copy statistics to the user buffer */
646 if(copy_to_user(wrq->u.data.pointer, stats,
647 sizeof(struct iw_statistics)))
648 return -EFAULT;
649
650 /* Check if we need to clear the updated flag */
651 if(wrq->u.data.flags != 0)
652 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
653 return 0;
654 } else
655 return -EOPNOTSUPP;
656}
657
658/* ---------------------------------------------------------------- */
659/*
660 * Export the driver private handler definition
661 * They will be picked up by tools like iwpriv...
662 */
663static inline int ioctl_export_private(struct net_device * dev,
664 struct ifreq * ifr)
665{
666 struct iwreq * iwr = (struct iwreq *) ifr;
667
668 /* Check if the driver has something to export */
669 if((dev->wireless_handlers->num_private_args == 0) ||
670 (dev->wireless_handlers->private_args == NULL))
671 return -EOPNOTSUPP;
672
673 /* Check NULL pointer */
674 if(iwr->u.data.pointer == NULL)
675 return -EFAULT;
676
677 /* Check if there is enough buffer up there */
678 if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
679 /* User space can't know in advance how large the buffer
680 * needs to be. Give it a hint, so that we can support
681 * any size buffer we want somewhat efficiently... */
682 iwr->u.data.length = dev->wireless_handlers->num_private_args;
683 return -E2BIG;
684 }
685
686 /* Set the number of available ioctls. */
687 iwr->u.data.length = dev->wireless_handlers->num_private_args;
688
689 /* Copy structure to the user buffer. */
690 if (copy_to_user(iwr->u.data.pointer,
691 dev->wireless_handlers->private_args,
692 sizeof(struct iw_priv_args) * iwr->u.data.length))
693 return -EFAULT;
694
695 return 0;
696}
697
698/* ---------------------------------------------------------------- */
699/*
700 * Wrapper to call a standard Wireless Extension handler. 707 * Wrapper to call a standard Wireless Extension handler.
701 * We do various checks and also take care of moving data between 708 * We do various checks and also take care of moving data between
702 * user space and kernel space. 709 * user space and kernel space.
703 */ 710 */
704static inline int ioctl_standard_call(struct net_device * dev, 711static int ioctl_standard_call(struct net_device * dev,
705 struct ifreq * ifr, 712 struct ifreq * ifr,
706 unsigned int cmd, 713 unsigned int cmd,
707 iw_handler handler) 714 iw_handler handler)
708{ 715{
709 struct iwreq * iwr = (struct iwreq *) ifr; 716 struct iwreq * iwr = (struct iwreq *) ifr;
710 const struct iw_ioctl_description * descr; 717 const struct iw_ioctl_description * descr;
@@ -1048,14 +1055,20 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
1048 { 1055 {
1049 case SIOCGIWSTATS: 1056 case SIOCGIWSTATS:
1050 /* Get Wireless Stats */ 1057 /* Get Wireless Stats */
1051 return dev_iwstats(dev, ifr); 1058 return ioctl_standard_call(dev,
1059 ifr,
1060 cmd,
1061 &iw_handler_get_iwstats);
1052 1062
1053 case SIOCGIWPRIV: 1063 case SIOCGIWPRIV:
1054 /* Check if we have some wireless handlers defined */ 1064 /* Check if we have some wireless handlers defined */
1055 if(dev->wireless_handlers != NULL) { 1065 if(dev->wireless_handlers != NULL) {
1056 /* We export to user space the definition of 1066 /* We export to user space the definition of
1057 * the private handler ourselves */ 1067 * the private handler ourselves */
1058 return ioctl_export_private(dev, ifr); 1068 return ioctl_standard_call(dev,
1069 ifr,
1070 cmd,
1071 &iw_handler_get_private);
1059 } 1072 }
1060 // ## Fall-through for old API ## 1073 // ## Fall-through for old API ##
1061 default: 1074 default:
@@ -1088,16 +1101,739 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
1088 return -EINVAL; 1101 return -EINVAL;
1089} 1102}
1090 1103
1104/********************** RTNETLINK REQUEST API **********************/
1105/*
1106 * The alternate user space API to configure all those Wireless Extensions
1107 * is through RtNetlink.
1108 * This API support only the new driver API (iw_handler).
1109 *
1110 * This RtNetlink API use the same query/reply model as the ioctl API.
1111 * Maximum effort has been done to fit in the RtNetlink model, and
1112 * we support both RtNetlink Set and RtNelink Get operations.
1113 * On the other hand, we don't offer Dump operations because of the
1114 * following reasons :
1115 * o Large number of parameters, most optional
1116 * o Large size of some parameters (> 100 bytes)
1117 * o Each parameters need to be extracted from hardware
1118 * o Scan requests can take seconds and disable network activity.
1119 * Because of this high cost/overhead, we want to return only the
1120 * parameters the user application is really interested in.
1121 * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag.
1122 *
1123 * The API uses the standard RtNetlink socket. When the RtNetlink code
1124 * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request,
1125 * it calls here.
1126 */
1127
1128#ifdef CONFIG_NET_WIRELESS_RTNETLINK
1129/* ---------------------------------------------------------------- */
1130/*
1131 * Wrapper to call a standard Wireless Extension GET handler.
1132 * We do various checks and call the handler with the proper args.
1133 */
1134static int rtnetlink_standard_get(struct net_device * dev,
1135 struct iw_event * request,
1136 int request_len,
1137 iw_handler handler,
1138 char ** p_buf,
1139 int * p_len)
1140{
1141 const struct iw_ioctl_description * descr = NULL;
1142 unsigned int cmd;
1143 union iwreq_data * wrqu;
1144 int hdr_len;
1145 struct iw_request_info info;
1146 char * buffer = NULL;
1147 int buffer_size = 0;
1148 int ret = -EINVAL;
1149
1150 /* Get the description of the Request */
1151 cmd = request->cmd;
1152 if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
1153 return -EOPNOTSUPP;
1154 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
1155
1156#ifdef WE_RTNETLINK_DEBUG
1157 printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n",
1158 dev->name, cmd);
1159 printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
1160#endif /* WE_RTNETLINK_DEBUG */
1161
1162 /* Check if wrqu is complete */
1163 hdr_len = event_type_size[descr->header_type];
1164 if(request_len < hdr_len) {
1165#ifdef WE_RTNETLINK_DEBUG
1166 printk(KERN_DEBUG
1167 "%s (WE.r) : Wireless request too short (%d)\n",
1168 dev->name, request_len);
1169#endif /* WE_RTNETLINK_DEBUG */
1170 return -EINVAL;
1171 }
1172
1173 /* Prepare the call */
1174 info.cmd = cmd;
1175 info.flags = 0;
1176
1177 /* Check if we have extra data in the reply or not */
1178 if(descr->header_type != IW_HEADER_TYPE_POINT) {
1179
1180 /* Create the kernel buffer that we will return.
1181 * It's at an offset to match the TYPE_POINT case... */
1182 buffer_size = request_len + IW_EV_POINT_OFF;
1183 buffer = kmalloc(buffer_size, GFP_KERNEL);
1184 if (buffer == NULL) {
1185 return -ENOMEM;
1186 }
1187 /* Copy event data */
1188 memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
1189 /* Use our own copy of wrqu */
1190 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
1191 + IW_EV_LCP_LEN);
1192
1193 /* No extra arguments. Trivial to handle */
1194 ret = handler(dev, &info, wrqu, NULL);
1195
1196 } else {
1197 union iwreq_data wrqu_point;
1198 char * extra = NULL;
1199 int extra_size = 0;
1200
1201 /* Get a temp copy of wrqu (skip pointer) */
1202 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1203 ((char *) request) + IW_EV_LCP_LEN,
1204 IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1205
1206 /* Calculate space needed by arguments. Always allocate
1207 * for max space. Easier, and won't last long... */
1208 extra_size = descr->max_tokens * descr->token_size;
1209 /* Support for very large requests */
1210 if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
1211 (wrqu_point.data.length > descr->max_tokens))
1212 extra_size = (wrqu_point.data.length
1213 * descr->token_size);
1214 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
1215#ifdef WE_RTNETLINK_DEBUG
1216 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
1217 dev->name, extra_size, buffer_size);
1218#endif /* WE_RTNETLINK_DEBUG */
1219
1220 /* Create the kernel buffer that we will return */
1221 buffer = kmalloc(buffer_size, GFP_KERNEL);
1222 if (buffer == NULL) {
1223 return -ENOMEM;
1224 }
1225
1226 /* Put wrqu in the right place (just before extra).
1227 * Leave space for IWE header and dummy pointer...
1228 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
1229 */
1230 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
1231 ((char *) &wrqu_point) + IW_EV_POINT_OFF,
1232 IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1233 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
1234
1235 /* Extra comes logically after that. Offset +12 bytes. */
1236 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
1237
1238 /* Call the handler */
1239 ret = handler(dev, &info, wrqu, extra);
1240
1241 /* Calculate real returned length */
1242 extra_size = (wrqu->data.length * descr->token_size);
1243 /* Re-adjust reply size */
1244 request->len = extra_size + IW_EV_POINT_LEN;
1245
1246 /* Put the iwe header where it should, i.e. scrap the
1247 * dummy pointer. */
1248 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
1249
1250#ifdef WE_RTNETLINK_DEBUG
1251 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
1252#endif /* WE_RTNETLINK_DEBUG */
1253
1254 /* Check if there is enough buffer up there */
1255 if(wrqu_point.data.length < wrqu->data.length)
1256 ret = -E2BIG;
1257 }
1258
1259 /* Return the buffer to the caller */
1260 if (!ret) {
1261 *p_buf = buffer;
1262 *p_len = request->len;
1263 } else {
1264 /* Cleanup */
1265 if(buffer)
1266 kfree(buffer);
1267 }
1268
1269 return ret;
1270}
1271
1272/* ---------------------------------------------------------------- */
1273/*
1274 * Wrapper to call a standard Wireless Extension SET handler.
1275 * We do various checks and call the handler with the proper args.
1276 */
1277static inline int rtnetlink_standard_set(struct net_device * dev,
1278 struct iw_event * request,
1279 int request_len,
1280 iw_handler handler)
1281{
1282 const struct iw_ioctl_description * descr = NULL;
1283 unsigned int cmd;
1284 union iwreq_data * wrqu;
1285 union iwreq_data wrqu_point;
1286 int hdr_len;
1287 char * extra = NULL;
1288 int extra_size = 0;
1289 struct iw_request_info info;
1290 int ret = -EINVAL;
1291
1292 /* Get the description of the Request */
1293 cmd = request->cmd;
1294 if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
1295 return -EOPNOTSUPP;
1296 descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
1297
1298#ifdef WE_RTNETLINK_DEBUG
1299 printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n",
1300 dev->name, cmd);
1301 printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
1302#endif /* WE_RTNETLINK_DEBUG */
1303
1304 /* Extract fixed header from request. This is properly aligned. */
1305 wrqu = &request->u;
1306
1307 /* Check if wrqu is complete */
1308 hdr_len = event_type_size[descr->header_type];
1309 if(request_len < hdr_len) {
1310#ifdef WE_RTNETLINK_DEBUG
1311 printk(KERN_DEBUG
1312 "%s (WE.r) : Wireless request too short (%d)\n",
1313 dev->name, request_len);
1314#endif /* WE_RTNETLINK_DEBUG */
1315 return -EINVAL;
1316 }
1317
1318 /* Prepare the call */
1319 info.cmd = cmd;
1320 info.flags = 0;
1321
1322 /* Check if we have extra data in the request or not */
1323 if(descr->header_type != IW_HEADER_TYPE_POINT) {
1324
1325 /* No extra arguments. Trivial to handle */
1326 ret = handler(dev, &info, wrqu, NULL);
1327
1328 } else {
1329 int extra_len;
1330
1331 /* Put wrqu in the right place (skip pointer) */
1332 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1333 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1334 /* Don't forget about the event code... */
1335 wrqu = &wrqu_point;
1336
1337 /* Check if number of token fits within bounds */
1338 if(wrqu_point.data.length > descr->max_tokens)
1339 return -E2BIG;
1340 if(wrqu_point.data.length < descr->min_tokens)
1341 return -EINVAL;
1342
1343 /* Real length of payload */
1344 extra_len = wrqu_point.data.length * descr->token_size;
1345
1346 /* Check if request is self consistent */
1347 if((request_len - hdr_len) < extra_len) {
1348#ifdef WE_RTNETLINK_DEBUG
1349 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
1350 dev->name, extra_size);
1351#endif /* WE_RTNETLINK_DEBUG */
1352 return -EINVAL;
1353 }
1354
1355#ifdef WE_RTNETLINK_DEBUG
1356 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
1357 dev->name, extra_size);
1358#endif /* WE_RTNETLINK_DEBUG */
1359
1360 /* Always allocate for max space. Easier, and won't last
1361 * long... */
1362 extra_size = descr->max_tokens * descr->token_size;
1363 extra = kmalloc(extra_size, GFP_KERNEL);
1364 if (extra == NULL)
1365 return -ENOMEM;
1366
1367 /* Copy extra in aligned buffer */
1368 memcpy(extra, ((char *) request) + hdr_len, extra_len);
1369
1370 /* Call the handler */
1371 ret = handler(dev, &info, &wrqu_point, extra);
1372 }
1373
1374#ifdef WE_SET_EVENT
1375 /* Generate an event to notify listeners of the change */
1376 if((descr->flags & IW_DESCR_FLAG_EVENT) &&
1377 ((ret == 0) || (ret == -EIWCOMMIT))) {
1378 if(descr->flags & IW_DESCR_FLAG_RESTRICT)
1379 /* If the event is restricted, don't
1380 * export the payload */
1381 wireless_send_event(dev, cmd, wrqu, NULL);
1382 else
1383 wireless_send_event(dev, cmd, wrqu, extra);
1384 }
1385#endif /* WE_SET_EVENT */
1386
1387 /* Cleanup - I told you it wasn't that long ;-) */
1388 if(extra)
1389 kfree(extra);
1390
1391 /* Call commit handler if needed and defined */
1392 if(ret == -EIWCOMMIT)
1393 ret = call_commit_handler(dev);
1394
1395 return ret;
1396}
1397
1398/* ---------------------------------------------------------------- */
1399/*
1400 * Wrapper to call a private Wireless Extension GET handler.
1401 * Same as above...
1402 * It's not as nice and slimline as the standard wrapper. The cause
1403 * is struct iw_priv_args, which was not really designed for the
1404 * job we are going here.
1405 *
1406 * IMPORTANT : This function prevent to set and get data on the same
1407 * IOCTL and enforce the SET/GET convention. Not doing it would be
1408 * far too hairy...
1409 * If you need to set and get data at the same time, please don't use
1410 * a iw_handler but process it in your ioctl handler (i.e. use the
1411 * old driver API).
1412 */
1413static inline int rtnetlink_private_get(struct net_device * dev,
1414 struct iw_event * request,
1415 int request_len,
1416 iw_handler handler,
1417 char ** p_buf,
1418 int * p_len)
1419{
1420 const struct iw_priv_args * descr = NULL;
1421 unsigned int cmd;
1422 union iwreq_data * wrqu;
1423 int hdr_len;
1424 struct iw_request_info info;
1425 int extra_size = 0;
1426 int i;
1427 char * buffer = NULL;
1428 int buffer_size = 0;
1429 int ret = -EINVAL;
1430
1431 /* Get the description of the Request */
1432 cmd = request->cmd;
1433 for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
1434 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
1435 descr = &(dev->wireless_handlers->private_args[i]);
1436 break;
1437 }
1438 if(descr == NULL)
1439 return -EOPNOTSUPP;
1440
1441#ifdef WE_RTNETLINK_DEBUG
1442 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
1443 dev->name, cmd);
1444 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
1445 dev->name, descr->name, descr->set_args, descr->get_args);
1446#endif /* WE_RTNETLINK_DEBUG */
1447
1448 /* Compute the max size of the get arguments */
1449 extra_size = get_priv_size(descr->get_args);
1450
1451 /* Does it fits in wrqu ? */
1452 if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
1453 (extra_size <= IFNAMSIZ)) {
1454 hdr_len = extra_size;
1455 extra_size = 0;
1456 } else {
1457 hdr_len = IW_EV_POINT_LEN;
1458 }
1459
1460 /* Check if wrqu is complete */
1461 if(request_len < hdr_len) {
1462#ifdef WE_RTNETLINK_DEBUG
1463 printk(KERN_DEBUG
1464 "%s (WE.r) : Wireless request too short (%d)\n",
1465 dev->name, request_len);
1466#endif /* WE_RTNETLINK_DEBUG */
1467 return -EINVAL;
1468 }
1469
1470 /* Prepare the call */
1471 info.cmd = cmd;
1472 info.flags = 0;
1473
1474 /* Check if we have a pointer to user space data or not. */
1475 if(extra_size == 0) {
1476
1477 /* Create the kernel buffer that we will return.
1478 * It's at an offset to match the TYPE_POINT case... */
1479 buffer_size = request_len + IW_EV_POINT_OFF;
1480 buffer = kmalloc(buffer_size, GFP_KERNEL);
1481 if (buffer == NULL) {
1482 return -ENOMEM;
1483 }
1484 /* Copy event data */
1485 memcpy(buffer + IW_EV_POINT_OFF, request, request_len);
1486 /* Use our own copy of wrqu */
1487 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF
1488 + IW_EV_LCP_LEN);
1489
1490 /* No extra arguments. Trivial to handle */
1491 ret = handler(dev, &info, wrqu, (char *) wrqu);
1492
1493 } else {
1494 char * extra;
1495
1496 /* Buffer for full reply */
1497 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF;
1498
1499#ifdef WE_RTNETLINK_DEBUG
1500 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n",
1501 dev->name, extra_size, buffer_size);
1502#endif /* WE_RTNETLINK_DEBUG */
1503
1504 /* Create the kernel buffer that we will return */
1505 buffer = kmalloc(buffer_size, GFP_KERNEL);
1506 if (buffer == NULL) {
1507 return -ENOMEM;
1508 }
1509
1510 /* Put wrqu in the right place (just before extra).
1511 * Leave space for IWE header and dummy pointer...
1512 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned...
1513 */
1514 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF,
1515 ((char *) request) + IW_EV_LCP_LEN,
1516 IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1517 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN);
1518
1519 /* Extra comes logically after that. Offset +12 bytes. */
1520 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN;
1521
1522 /* Call the handler */
1523 ret = handler(dev, &info, wrqu, extra);
1524
1525 /* Adjust for the actual length if it's variable,
1526 * avoid leaking kernel bits outside. */
1527 if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
1528 extra_size = adjust_priv_size(descr->get_args, wrqu);
1529 /* Re-adjust reply size */
1530 request->len = extra_size + IW_EV_POINT_LEN;
1531
1532 /* Put the iwe header where it should, i.e. scrap the
1533 * dummy pointer. */
1534 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN);
1535
1536#ifdef WE_RTNETLINK_DEBUG
1537 printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size);
1538#endif /* WE_RTNETLINK_DEBUG */
1539 }
1540
1541 /* Return the buffer to the caller */
1542 if (!ret) {
1543 *p_buf = buffer;
1544 *p_len = request->len;
1545 } else {
1546 /* Cleanup */
1547 if(buffer)
1548 kfree(buffer);
1549 }
1550
1551 return ret;
1552}
1553
1554/* ---------------------------------------------------------------- */
1555/*
1556 * Wrapper to call a private Wireless Extension SET handler.
1557 * Same as above...
1558 * It's not as nice and slimline as the standard wrapper. The cause
1559 * is struct iw_priv_args, which was not really designed for the
1560 * job we are going here.
1561 *
1562 * IMPORTANT : This function prevent to set and get data on the same
1563 * IOCTL and enforce the SET/GET convention. Not doing it would be
1564 * far too hairy...
1565 * If you need to set and get data at the same time, please don't use
1566 * a iw_handler but process it in your ioctl handler (i.e. use the
1567 * old driver API).
1568 */
1569static inline int rtnetlink_private_set(struct net_device * dev,
1570 struct iw_event * request,
1571 int request_len,
1572 iw_handler handler)
1573{
1574 const struct iw_priv_args * descr = NULL;
1575 unsigned int cmd;
1576 union iwreq_data * wrqu;
1577 union iwreq_data wrqu_point;
1578 int hdr_len;
1579 char * extra = NULL;
1580 int extra_size = 0;
1581 int offset = 0; /* For sub-ioctls */
1582 struct iw_request_info info;
1583 int i;
1584 int ret = -EINVAL;
1585
1586 /* Get the description of the Request */
1587 cmd = request->cmd;
1588 for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
1589 if(cmd == dev->wireless_handlers->private_args[i].cmd) {
1590 descr = &(dev->wireless_handlers->private_args[i]);
1591 break;
1592 }
1593 if(descr == NULL)
1594 return -EOPNOTSUPP;
1595
1596#ifdef WE_RTNETLINK_DEBUG
1597 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n",
1598 ifr->ifr_name, cmd);
1599 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n",
1600 dev->name, descr->name, descr->set_args, descr->get_args);
1601#endif /* WE_RTNETLINK_DEBUG */
1602
1603 /* Compute the size of the set arguments */
1604 /* Check for sub-ioctl handler */
1605 if(descr->name[0] == '\0')
1606 /* Reserve one int for sub-ioctl index */
1607 offset = sizeof(__u32);
1608
1609 /* Size of set arguments */
1610 extra_size = get_priv_size(descr->set_args);
1611
1612 /* Does it fits in wrqu ? */
1613 if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
1614 (extra_size <= IFNAMSIZ)) {
1615 hdr_len = IW_EV_LCP_LEN + extra_size;
1616 extra_size = 0;
1617 } else {
1618 hdr_len = IW_EV_POINT_LEN;
1619 }
1620
1621 /* Extract fixed header from request. This is properly aligned. */
1622 wrqu = &request->u;
1623
1624 /* Check if wrqu is complete */
1625 if(request_len < hdr_len) {
1626#ifdef WE_RTNETLINK_DEBUG
1627 printk(KERN_DEBUG
1628 "%s (WE.r) : Wireless request too short (%d)\n",
1629 dev->name, request_len);
1630#endif /* WE_RTNETLINK_DEBUG */
1631 return -EINVAL;
1632 }
1633
1634 /* Prepare the call */
1635 info.cmd = cmd;
1636 info.flags = 0;
1637
1638 /* Check if we have a pointer to user space data or not. */
1639 if(extra_size == 0) {
1640
1641 /* No extra arguments. Trivial to handle */
1642 ret = handler(dev, &info, wrqu, (char *) wrqu);
1643
1644 } else {
1645 int extra_len;
1646
1647 /* Put wrqu in the right place (skip pointer) */
1648 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF,
1649 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN);
1650
1651 /* Does it fits within bounds ? */
1652 if(wrqu_point.data.length > (descr->set_args &
1653 IW_PRIV_SIZE_MASK))
1654 return -E2BIG;
1655
1656 /* Real length of payload */
1657 extra_len = adjust_priv_size(descr->set_args, &wrqu_point);
1658
1659 /* Check if request is self consistent */
1660 if((request_len - hdr_len) < extra_len) {
1661#ifdef WE_RTNETLINK_DEBUG
1662 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n",
1663 dev->name, extra_size);
1664#endif /* WE_RTNETLINK_DEBUG */
1665 return -EINVAL;
1666 }
1667
1668#ifdef WE_RTNETLINK_DEBUG
1669 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n",
1670 dev->name, extra_size);
1671#endif /* WE_RTNETLINK_DEBUG */
1672
1673 /* Always allocate for max space. Easier, and won't last
1674 * long... */
1675 extra = kmalloc(extra_size, GFP_KERNEL);
1676 if (extra == NULL)
1677 return -ENOMEM;
1678
1679 /* Copy extra in aligned buffer */
1680 memcpy(extra, ((char *) request) + hdr_len, extra_len);
1681
1682 /* Call the handler */
1683 ret = handler(dev, &info, &wrqu_point, extra);
1684
1685 /* Cleanup - I told you it wasn't that long ;-) */
1686 kfree(extra);
1687 }
1688
1689 /* Call commit handler if needed and defined */
1690 if(ret == -EIWCOMMIT)
1691 ret = call_commit_handler(dev);
1692
1693 return ret;
1694}
1695
1696/* ---------------------------------------------------------------- */
1697/*
1698 * Main RtNetlink dispatcher. Called from the main networking code
1699 * (do_getlink() in net/core/rtnetlink.c).
1700 * Check the type of Request and call the appropriate wrapper...
1701 */
1702int wireless_rtnetlink_get(struct net_device * dev,
1703 char * data,
1704 int len,
1705 char ** p_buf,
1706 int * p_len)
1707{
1708 struct iw_event * request = (struct iw_event *) data;
1709 iw_handler handler;
1710
1711 /* Check length */
1712 if(len < IW_EV_LCP_LEN) {
1713 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1714 dev->name, len);
1715 return -EINVAL;
1716 }
1717
1718 /* ReCheck length (len may have padding) */
1719 if(request->len > len) {
1720 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1721 dev->name, request->len, len);
1722 return -EINVAL;
1723 }
1724
1725 /* Only accept GET requests in here */
1726 if(!IW_IS_GET(request->cmd))
1727 return -EOPNOTSUPP;
1728
1729 /* Special cases */
1730 if(request->cmd == SIOCGIWSTATS)
1731 /* Get Wireless Stats */
1732 return rtnetlink_standard_get(dev,
1733 request,
1734 request->len,
1735 &iw_handler_get_iwstats,
1736 p_buf, p_len);
1737 if(request->cmd == SIOCGIWPRIV) {
1738 /* Check if we have some wireless handlers defined */
1739 if(dev->wireless_handlers == NULL)
1740 return -EOPNOTSUPP;
1741 /* Get Wireless Stats */
1742 return rtnetlink_standard_get(dev,
1743 request,
1744 request->len,
1745 &iw_handler_get_private,
1746 p_buf, p_len);
1747 }
1748
1749 /* Basic check */
1750 if (!netif_device_present(dev))
1751 return -ENODEV;
1752
1753 /* Try to find the handler */
1754 handler = get_handler(dev, request->cmd);
1755 if(handler != NULL) {
1756 /* Standard and private are not the same */
1757 if(request->cmd < SIOCIWFIRSTPRIV)
1758 return rtnetlink_standard_get(dev,
1759 request,
1760 request->len,
1761 handler,
1762 p_buf, p_len);
1763 else
1764 return rtnetlink_private_get(dev,
1765 request,
1766 request->len,
1767 handler,
1768 p_buf, p_len);
1769 }
1770
1771 return -EOPNOTSUPP;
1772}
1773
1774/* ---------------------------------------------------------------- */
1775/*
1776 * Main RtNetlink dispatcher. Called from the main networking code
1777 * (do_setlink() in net/core/rtnetlink.c).
1778 * Check the type of Request and call the appropriate wrapper...
1779 */
1780int wireless_rtnetlink_set(struct net_device * dev,
1781 char * data,
1782 int len)
1783{
1784 struct iw_event * request = (struct iw_event *) data;
1785 iw_handler handler;
1786
1787 /* Check length */
1788 if(len < IW_EV_LCP_LEN) {
1789 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n",
1790 dev->name, len);
1791 return -EINVAL;
1792 }
1793
1794 /* ReCheck length (len may have padding) */
1795 if(request->len > len) {
1796 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n",
1797 dev->name, request->len, len);
1798 return -EINVAL;
1799 }
1800
1801 /* Only accept SET requests in here */
1802 if(!IW_IS_SET(request->cmd))
1803 return -EOPNOTSUPP;
1804
1805 /* Basic check */
1806 if (!netif_device_present(dev))
1807 return -ENODEV;
1808
1809 /* New driver API : try to find the handler */
1810 handler = get_handler(dev, request->cmd);
1811 if(handler != NULL) {
1812 /* Standard and private are not the same */
1813 if(request->cmd < SIOCIWFIRSTPRIV)
1814 return rtnetlink_standard_set(dev,
1815 request,
1816 request->len,
1817 handler);
1818 else
1819 return rtnetlink_private_set(dev,
1820 request,
1821 request->len,
1822 handler);
1823 }
1824
1825 return -EOPNOTSUPP;
1826}
1827#endif /* CONFIG_NET_WIRELESS_RTNETLINK */
1828
1829
1091/************************* EVENT PROCESSING *************************/ 1830/************************* EVENT PROCESSING *************************/
1092/* 1831/*
1093 * Process events generated by the wireless layer or the driver. 1832 * Process events generated by the wireless layer or the driver.
1094 * Most often, the event will be propagated through rtnetlink 1833 * Most often, the event will be propagated through rtnetlink
1095 */ 1834 */
1096 1835
1097#ifdef WE_EVENT_NETLINK 1836#ifdef WE_EVENT_RTNETLINK
1098/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
1099 * It is declared in <linux/rtnetlink.h> */
1100
1101/* ---------------------------------------------------------------- */ 1837/* ---------------------------------------------------------------- */
1102/* 1838/*
1103 * Fill a rtnetlink message with our event data. 1839 * Fill a rtnetlink message with our event data.
@@ -1121,12 +1857,11 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
1121 r->__ifi_pad = 0; 1857 r->__ifi_pad = 0;
1122 r->ifi_type = dev->type; 1858 r->ifi_type = dev->type;
1123 r->ifi_index = dev->ifindex; 1859 r->ifi_index = dev->ifindex;
1124 r->ifi_flags = dev->flags; 1860 r->ifi_flags = dev_get_flags(dev);
1125 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1861 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1126 1862
1127 /* Add the wireless events in the netlink packet */ 1863 /* Add the wireless events in the netlink packet */
1128 RTA_PUT(skb, IFLA_WIRELESS, 1864 RTA_PUT(skb, IFLA_WIRELESS, event_len, event);
1129 event_len, event);
1130 1865
1131 nlh->nlmsg_len = skb->tail - b; 1866 nlh->nlmsg_len = skb->tail - b;
1132 return skb->len; 1867 return skb->len;
@@ -1163,7 +1898,7 @@ static inline void rtmsg_iwinfo(struct net_device * dev,
1163 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1898 NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1164 netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); 1899 netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC);
1165} 1900}
1166#endif /* WE_EVENT_NETLINK */ 1901#endif /* WE_EVENT_RTNETLINK */
1167 1902
1168/* ---------------------------------------------------------------- */ 1903/* ---------------------------------------------------------------- */
1169/* 1904/*
@@ -1255,10 +1990,10 @@ void wireless_send_event(struct net_device * dev,
1255 if(extra != NULL) 1990 if(extra != NULL)
1256 memcpy(((char *) event) + hdr_len, extra, extra_len); 1991 memcpy(((char *) event) + hdr_len, extra, extra_len);
1257 1992
1258#ifdef WE_EVENT_NETLINK 1993#ifdef WE_EVENT_RTNETLINK
1259 /* rtnetlink event channel */ 1994 /* Send via the RtNetlink event channel */
1260 rtmsg_iwinfo(dev, (char *) event, event_len); 1995 rtmsg_iwinfo(dev, (char *) event, event_len);
1261#endif /* WE_EVENT_NETLINK */ 1996#endif /* WE_EVENT_RTNETLINK */
1262 1997
1263 /* Cleanup */ 1998 /* Cleanup */
1264 kfree(event); 1999 kfree(event);
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index d18ccba3ea9e..dbb08528ddf5 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -66,3 +66,4 @@ config IEEE80211_CRYPT_TKIP
66 This can be compiled as a modules and it will be called 66 This can be compiled as a modules and it will be called
67 "ieee80211_crypt_tkip". 67 "ieee80211_crypt_tkip".
68 68
69source "net/ieee80211/softmac/Kconfig"
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
index f988417121da..796a7c76ee48 100644
--- a/net/ieee80211/Makefile
+++ b/net/ieee80211/Makefile
@@ -10,3 +10,4 @@ ieee80211-objs := \
10 ieee80211_wx.o \ 10 ieee80211_wx.o \
11 ieee80211_geo.o 11 ieee80211_geo.o
12 12
13obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index a7f2a642a512..604b7b0097bc 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -780,6 +780,80 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
780 return 0; 780 return 0;
781} 781}
782 782
783/* Filter out unrelated packets, call ieee80211_rx[_mgt] */
784int ieee80211_rx_any(struct ieee80211_device *ieee,
785 struct sk_buff *skb, struct ieee80211_rx_stats *stats)
786{
787 struct ieee80211_hdr_4addr *hdr;
788 int is_packet_for_us;
789 u16 fc;
790
791 if (ieee->iw_mode == IW_MODE_MONITOR)
792 return ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL;
793
794 hdr = (struct ieee80211_hdr_4addr *)skb->data;
795 fc = le16_to_cpu(hdr->frame_ctl);
796
797 if ((fc & IEEE80211_FCTL_VERS) != 0)
798 return -EINVAL;
799
800 switch (fc & IEEE80211_FCTL_FTYPE) {
801 case IEEE80211_FTYPE_MGMT:
802 ieee80211_rx_mgt(ieee, hdr, stats);
803 return 0;
804 case IEEE80211_FTYPE_DATA:
805 break;
806 case IEEE80211_FTYPE_CTL:
807 return 0;
808 default:
809 return -EINVAL;
810 }
811
812 is_packet_for_us = 0;
813 switch (ieee->iw_mode) {
814 case IW_MODE_ADHOC:
815 /* our BSS and not from/to DS */
816 if (memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) == 0)
817 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
818 /* promisc: get all */
819 if (ieee->dev->flags & IFF_PROMISC)
820 is_packet_for_us = 1;
821 /* to us */
822 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
823 is_packet_for_us = 1;
824 /* mcast */
825 else if (is_multicast_ether_addr(hdr->addr1))
826 is_packet_for_us = 1;
827 }
828 break;
829 case IW_MODE_INFRA:
830 /* our BSS (== from our AP) and from DS */
831 if (memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) == 0)
832 if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
833 /* promisc: get all */
834 if (ieee->dev->flags & IFF_PROMISC)
835 is_packet_for_us = 1;
836 /* to us */
837 else if (memcmp(hdr->addr1, ieee->dev->dev_addr, ETH_ALEN) == 0)
838 is_packet_for_us = 1;
839 /* mcast */
840 else if (is_multicast_ether_addr(hdr->addr1)) {
841 /* not our own packet bcasted from AP */
842 if (memcmp(hdr->addr3, ieee->dev->dev_addr, ETH_ALEN))
843 is_packet_for_us = 1;
844 }
845 }
846 break;
847 default:
848 /* ? */
849 break;
850 }
851
852 if (is_packet_for_us)
853 return (ieee80211_rx(ieee, skb, stats) ? 0 : -EINVAL);
854 return 0;
855}
856
783#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 857#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
784 858
785static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 }; 859static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
new file mode 100644
index 000000000000..6cd9f3427be6
--- /dev/null
+++ b/net/ieee80211/softmac/Kconfig
@@ -0,0 +1,10 @@
1config IEEE80211_SOFTMAC
2 tristate "Software MAC add-on to the IEEE 802.11 networking stack"
3 depends on IEEE80211 && EXPERIMENTAL
4 ---help---
5 This option enables the hardware independent software MAC addon
6 for the IEEE 802.11 networking stack.
7
8config IEEE80211_SOFTMAC_DEBUG
9 bool "Enable full debugging output"
10 depends on IEEE80211_SOFTMAC
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile
new file mode 100644
index 000000000000..bfcb391bb2c7
--- /dev/null
+++ b/net/ieee80211/softmac/Makefile
@@ -0,0 +1,9 @@
1obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o
2ieee80211softmac-objs := \
3 ieee80211softmac_io.o \
4 ieee80211softmac_auth.o \
5 ieee80211softmac_module.o \
6 ieee80211softmac_scan.o \
7 ieee80211softmac_wx.o \
8 ieee80211softmac_assoc.o \
9 ieee80211softmac_event.o
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
new file mode 100644
index 000000000000..be61de78dfa4
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -0,0 +1,396 @@
1/*
2 * This file contains the softmac's association logic.
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#include "ieee80211softmac_priv.h"
28
29/*
30 * Overview
31 *
32 * Before you can associate, you have to authenticate.
33 *
34 */
35
36/* Sends out an association request to the desired AP */
37static void
38ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
39{
40 unsigned long flags;
41
42 /* Switch to correct channel for this network */
43 mac->set_channel(mac->dev, net->channel);
44
45 /* Send association request */
46 ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
47
48 dprintk(KERN_INFO PFX "sent association request!\n");
49
50 /* Change the state to associating */
51 spin_lock_irqsave(&mac->lock, flags);
52 mac->associnfo.associating = 1;
53 mac->associated = 0; /* just to make sure */
54 spin_unlock_irqrestore(&mac->lock, flags);
55
56 /* Set a timer for timeout */
57 /* FIXME: make timeout configurable */
58 schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ);
59}
60
61void
62ieee80211softmac_assoc_timeout(void *d)
63{
64 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
65 unsigned long flags;
66
67 spin_lock_irqsave(&mac->lock, flags);
68 /* we might race against ieee80211softmac_handle_assoc_response,
69 * so make sure only one of us does something */
70 if (!mac->associnfo.associating) {
71 spin_unlock_irqrestore(&mac->lock, flags);
72 return;
73 }
74 mac->associnfo.associating = 0;
75 mac->associnfo.bssvalid = 0;
76 mac->associated = 0;
77 spin_unlock_irqrestore(&mac->lock, flags);
78
79 dprintk(KERN_INFO PFX "assoc request timed out!\n");
80 /* FIXME: we need to know the network here. that requires a bit of restructuring */
81 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
82}
83
84/* Sends out a disassociation request to the desired AP */
85static void
86ieee80211softmac_disassoc(struct ieee80211softmac_device *mac, u16 reason)
87{
88 unsigned long flags;
89 struct ieee80211softmac_network *found;
90
91 if (mac->associnfo.bssvalid && mac->associated) {
92 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
93 if (found)
94 ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
95 } else if (mac->associnfo.associating) {
96 cancel_delayed_work(&mac->associnfo.timeout);
97 }
98
99 /* Change our state */
100 spin_lock_irqsave(&mac->lock, flags);
101 /* Do NOT clear bssvalid as that will break ieee80211softmac_assoc_work! */
102 mac->associated = 0;
103 mac->associnfo.associating = 0;
104 spin_unlock_irqrestore(&mac->lock, flags);
105}
106
107static inline int
108we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
109{
110 int idx, search, found;
111 u8 rate, search_rate;
112
113 for (idx = 0; idx < (from_len); idx++) {
114 rate = (from)[idx];
115 if (!(rate & IEEE80211_BASIC_RATE_MASK))
116 continue;
117 found = 0;
118 rate &= ~IEEE80211_BASIC_RATE_MASK;
119 for (search = 0; search < mac->ratesinfo.count; search++) {
120 search_rate = mac->ratesinfo.rates[search];
121 search_rate &= ~IEEE80211_BASIC_RATE_MASK;
122 if (rate == search_rate) {
123 found = 1;
124 break;
125 }
126 }
127 if (!found)
128 return 0;
129 }
130 return 1;
131}
132
133static int
134network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
135{
136 /* we cannot associate to networks whose name we don't know */
137 if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
138 return 0;
139 /* do not associate to a network whose BSSBasicRateSet we cannot support */
140 if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
141 return 0;
142 /* do we really need to check the ex rates? */
143 if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
144 return 0;
145
146 /* if 'ANY' network requested, take any that doesn't have privacy enabled */
147 if (mac->associnfo.req_essid.len == 0
148 && !(net->capability & WLAN_CAPABILITY_PRIVACY))
149 return 1;
150 if (net->ssid_len != mac->associnfo.req_essid.len)
151 return 0;
152 if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
153 return 1;
154 return 0;
155}
156
157static void
158ieee80211softmac_assoc_notify(struct net_device *dev, void *context)
159{
160 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
161 ieee80211softmac_assoc_work((void*)mac);
162}
163
164/* This function is called to handle userspace requests (asynchronously) */
165void
166ieee80211softmac_assoc_work(void *d)
167{
168 struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
169 struct ieee80211softmac_network *found = NULL;
170 struct ieee80211_network *net = NULL, *best = NULL;
171 unsigned long flags;
172
173 /* meh */
174 if (mac->associated)
175 ieee80211softmac_disassoc(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
176
177 /* try to find the requested network in our list, if we found one already */
178 if (mac->associnfo.bssvalid)
179 found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
180
181 /* Search the ieee80211 networks for this network if we didn't find it by bssid,
182 * but only if we've scanned at least once (to get a better list of networks to
183 * select from). If we have not scanned before, the !found logic below will be
184 * invoked and will scan. */
185 if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
186 {
187 s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning
188 because it cannot follow the best pointer logic. */
189 spin_lock_irqsave(&mac->ieee->lock, flags);
190 list_for_each_entry(net, &mac->ieee->network_list, list) {
191 /* we're supposed to find the network with
192 * the best signal here, as we're asked to join
193 * any network with a specific ESSID, and many
194 * different ones could have that.
195 *
196 * I'll for now just go with the reported rssi.
197 *
198 * We also should take into account the rateset
199 * here to find the best BSSID to try.
200 */
201 if (network_matches_request(mac, net)) {
202 if (!best) {
203 best = net;
204 rssi = best->stats.rssi;
205 continue;
206 }
207 /* we already had a matching network, so
208 * compare their properties to get the
209 * better of the two ... (see above)
210 */
211 if (rssi < net->stats.rssi) {
212 best = net;
213 rssi = best->stats.rssi;
214 }
215 }
216 }
217 /* if we unlock here, we might get interrupted and the `best'
218 * pointer could go stale */
219 if (best) {
220 found = ieee80211softmac_create_network(mac, best);
221 /* if found is still NULL, then we got -ENOMEM somewhere */
222 if (found)
223 ieee80211softmac_add_network(mac, found);
224 }
225 spin_unlock_irqrestore(&mac->ieee->lock, flags);
226 }
227
228 if (!found) {
229 if (mac->associnfo.scan_retry > 0) {
230 spin_lock_irqsave(&mac->lock, flags);
231 mac->associnfo.scan_retry--;
232 spin_unlock_irqrestore(&mac->lock, flags);
233
234 /* We know of no such network. Let's scan.
235 * NB: this also happens if we had no memory to copy the network info...
236 * Maybe we can hope to have more memory after scanning finishes ;)
237 */
238 dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
239 ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify, NULL);
240 if (ieee80211softmac_start_scan(mac))
241 dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
242 return;
243 }
244 else {
245 spin_lock_irqsave(&mac->lock, flags);
246 mac->associnfo.associating = 0;
247 mac->associated = 0;
248 spin_unlock_irqrestore(&mac->lock, flags);
249
250 dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
251 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
252 return;
253 }
254 }
255
256 mac->associnfo.bssvalid = 1;
257 memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
258 /* copy the ESSID for displaying it */
259 mac->associnfo.associate_essid.len = found->essid.len;
260 memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
261
262 /* we found a network! authenticate (if necessary) and associate to it. */
263 if (!found->authenticated) {
264 /* This relies on the fact that _auth_req only queues the work,
265 * otherwise adding the notification would be racy. */
266 if (!ieee80211softmac_auth_req(mac, found)) {
267 dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
268 ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify, NULL, GFP_KERNEL);
269 } else {
270 printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
271 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
272 }
273 return;
274 }
275 /* finally! now we can start associating */
276 ieee80211softmac_assoc(mac, found);
277}
278
279/* call this to do whatever is necessary when we're associated */
280static void
281ieee80211softmac_associated(struct ieee80211softmac_device *mac,
282 struct ieee80211_assoc_response * resp,
283 struct ieee80211softmac_network *net)
284{
285 mac->associnfo.associating = 0;
286 mac->associated = 1;
287 if (mac->set_bssid_filter)
288 mac->set_bssid_filter(mac->dev, net->bssid);
289 memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
290 netif_carrier_on(mac->dev);
291
292 mac->association_id = le16_to_cpup(&resp->aid);
293}
294
295/* received frame handling functions */
296int
297ieee80211softmac_handle_assoc_response(struct net_device * dev,
298 struct ieee80211_assoc_response * resp,
299 struct ieee80211_network * _ieee80211_network_do_not_use)
300{
301 /* NOTE: the network parameter has to be ignored by
302 * this code because it is the ieee80211's pointer
303 * to the struct, not ours (we made a copy)
304 */
305 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
306 u16 status = le16_to_cpup(&resp->status);
307 struct ieee80211softmac_network *network = NULL;
308 unsigned long flags;
309
310 spin_lock_irqsave(&mac->lock, flags);
311
312 if (!mac->associnfo.associating) {
313 /* we race against the timeout function, so make sure
314 * only one of us can do work */
315 spin_unlock_irqrestore(&mac->lock, flags);
316 return 0;
317 }
318 network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
319
320 /* someone sending us things without us knowing him? Ignore. */
321 if (!network) {
322 dprintk(KERN_INFO PFX "Received unrequested assocation response from " MAC_FMT "\n", MAC_ARG(resp->header.addr3));
323 spin_unlock_irqrestore(&mac->lock, flags);
324 return 0;
325 }
326
327 /* now that we know it was for us, we can cancel the timeout */
328 cancel_delayed_work(&mac->associnfo.timeout);
329
330 switch (status) {
331 case 0:
332 dprintk(KERN_INFO PFX "associated!\n");
333 ieee80211softmac_associated(mac, resp, network);
334 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
335 break;
336 case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
337 if (!network->auth_desynced_once) {
338 /* there seem to be a few rare cases where our view of
339 * the world is obscured, or buggy APs that don't DEAUTH
340 * us properly. So we handle that, but allow it only once.
341 */
342 printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
343 network->authenticated = 0;
344 /* we don't want to do this more than once ... */
345 network->auth_desynced_once = 1;
346 schedule_work(&mac->associnfo.work);
347 break;
348 }
349 default:
350 dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
351 mac->associnfo.associating = 0;
352 mac->associnfo.bssvalid = 0;
353 mac->associated = 0;
354 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
355 }
356
357 spin_unlock_irqrestore(&mac->lock, flags);
358 return 0;
359}
360
361int
362ieee80211softmac_handle_disassoc(struct net_device * dev,
363 struct ieee80211_disassoc *disassoc)
364{
365 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
366 unsigned long flags;
367 if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
368 return 0;
369 if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
370 return 0;
371 dprintk(KERN_INFO PFX "got disassoc frame\n");
372 netif_carrier_off(dev);
373 spin_lock_irqsave(&mac->lock, flags);
374 mac->associnfo.bssvalid = 0;
375 mac->associated = 0;
376 schedule_work(&mac->associnfo.work);
377 spin_unlock_irqrestore(&mac->lock, flags);
378
379 return 0;
380}
381
382int
383ieee80211softmac_handle_reassoc_req(struct net_device * dev,
384 struct ieee80211_reassoc_request * resp)
385{
386 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
387 struct ieee80211softmac_network *network;
388
389 network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
390 if (!network) {
391 dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
392 return 0;
393 }
394 ieee80211softmac_assoc(mac, network);
395 return 0;
396}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
new file mode 100644
index 000000000000..9a0eac6c61eb
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -0,0 +1,364 @@
1/*
2 * This file contains the softmac's authentication logic.
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#include "ieee80211softmac_priv.h"
28
29static void ieee80211softmac_auth_queue(void *data);
30
31/* Queues an auth request to the desired AP */
32int
33ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
34 struct ieee80211softmac_network *net)
35{
36 struct ieee80211softmac_auth_queue_item *auth;
37 unsigned long flags;
38
39 if (net->authenticating)
40 return 0;
41
42 /* Add the network if it's not already added */
43 ieee80211softmac_add_network(mac, net);
44
45 dprintk(KERN_NOTICE PFX "Queueing Authentication Request to "MAC_FMT"\n", MAC_ARG(net->bssid));
46 /* Queue the auth request */
47 auth = (struct ieee80211softmac_auth_queue_item *)
48 kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
49 if(auth == NULL)
50 return -ENOMEM;
51
52 auth->net = net;
53 auth->mac = mac;
54 auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
55 auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
56 INIT_WORK(&auth->work, &ieee80211softmac_auth_queue, (void *)auth);
57
58 /* Lock (for list) */
59 spin_lock_irqsave(&mac->lock, flags);
60
61 /* add to list */
62 list_add_tail(&auth->list, &mac->auth_queue);
63 schedule_work(&auth->work);
64 spin_unlock_irqrestore(&mac->lock, flags);
65
66 return 0;
67}
68
69
70/* Sends an auth request to the desired AP and handles timeouts */
71static void
72ieee80211softmac_auth_queue(void *data)
73{
74 struct ieee80211softmac_device *mac;
75 struct ieee80211softmac_auth_queue_item *auth;
76 struct ieee80211softmac_network *net;
77 unsigned long flags;
78
79 auth = (struct ieee80211softmac_auth_queue_item *)data;
80 net = auth->net;
81 mac = auth->mac;
82
83 if(auth->retry > 0) {
84 /* Switch to correct channel for this network */
85 mac->set_channel(mac->dev, net->channel);
86
87 /* Lock and set flags */
88 spin_lock_irqsave(&mac->lock, flags);
89 net->authenticated = 0;
90 net->authenticating = 1;
91 /* add a timeout call so we eventually give up waiting for an auth reply */
92 schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
93 auth->retry--;
94 spin_unlock_irqrestore(&mac->lock, flags);
95 if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
96 dprintk(KERN_NOTICE PFX "Sending Authentication Request to "MAC_FMT" failed (this shouldn't happen, wait for the timeout).\n", MAC_ARG(net->bssid));
97 else
98 dprintk(KERN_NOTICE PFX "Sent Authentication Request to "MAC_FMT".\n", MAC_ARG(net->bssid));
99 return;
100 }
101
102 printkl(KERN_WARNING PFX "Authentication timed out with "MAC_FMT"\n", MAC_ARG(net->bssid));
103 /* Remove this item from the queue */
104 spin_lock_irqsave(&mac->lock, flags);
105 ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
106 cancel_delayed_work(&auth->work); /* just to make sure... */
107 list_del(&auth->list);
108 spin_unlock_irqrestore(&mac->lock, flags);
109 /* Free it */
110 kfree(auth);
111}
112
113/* Handle the auth response from the AP
114 * This should be registered with ieee80211 as handle_auth
115 */
116int
117ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
118{
119
120 struct list_head *list_ptr;
121 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
122 struct ieee80211softmac_auth_queue_item *aq = NULL;
123 struct ieee80211softmac_network *net = NULL;
124 unsigned long flags;
125 u8 * data;
126
127 /* Find correct auth queue item */
128 spin_lock_irqsave(&mac->lock, flags);
129 list_for_each(list_ptr, &mac->auth_queue) {
130 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
131 net = aq->net;
132 if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
133 break;
134 else
135 aq = NULL;
136 }
137 spin_unlock_irqrestore(&mac->lock, flags);
138
139 /* Make sure that we've got an auth queue item for this request */
140 if(aq == NULL)
141 {
142 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but no queue item exists.\n", MAC_ARG(auth->header.addr2));
143 /* Error #? */
144 return -1;
145 }
146
147 /* Check for out of order authentication */
148 if(!net->authenticating)
149 {
150 printkl(KERN_DEBUG PFX "Authentication response received from "MAC_FMT" but did not request authentication.\n",MAC_ARG(auth->header.addr2));
151 return -1;
152 }
153
154 /* Parse the auth packet */
155 switch(auth->algorithm) {
156 case WLAN_AUTH_OPEN:
157 /* Check the status code of the response */
158
159 switch(auth->status) {
160 case WLAN_STATUS_SUCCESS:
161 /* Update the status to Authenticated */
162 spin_lock_irqsave(&mac->lock, flags);
163 net->authenticating = 0;
164 net->authenticated = 1;
165 spin_unlock_irqrestore(&mac->lock, flags);
166
167 /* Send event */
168 printkl(KERN_NOTICE PFX "Open Authentication completed with "MAC_FMT"\n", MAC_ARG(net->bssid));
169 ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
170 break;
171 default:
172 /* Lock and reset flags */
173 spin_lock_irqsave(&mac->lock, flags);
174 net->authenticated = 0;
175 net->authenticating = 0;
176 spin_unlock_irqrestore(&mac->lock, flags);
177
178 printkl(KERN_NOTICE PFX "Open Authentication with "MAC_FMT" failed, error code: %i\n",
179 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
180 /* Count the error? */
181 break;
182 }
183 goto free_aq;
184 break;
185 case WLAN_AUTH_SHARED_KEY:
186 /* Figure out where we are in the process */
187 switch(auth->transaction) {
188 case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
189 /* Check to make sure we have a challenge IE */
190 data = (u8 *)auth->info_element;
191 if(*data++ != MFIE_TYPE_CHALLENGE){
192 printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
193 break;
194 }
195 /* Save the challenge */
196 spin_lock_irqsave(&mac->lock, flags);
197 net->challenge_len = *data++;
198 if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
199 net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
200 if(net->challenge != NULL)
201 kfree(net->challenge);
202 net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
203 memcpy(net->challenge, data, net->challenge_len);
204 aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
205 spin_unlock_irqrestore(&mac->lock, flags);
206
207 /* Switch to correct channel for this network */
208 mac->set_channel(mac->dev, net->channel);
209
210 /* Send our response (How to encrypt?) */
211 ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
212 break;
213 case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
214 /* Check the status code of the response */
215 switch(auth->status) {
216 case WLAN_STATUS_SUCCESS:
217 /* Update the status to Authenticated */
218 spin_lock_irqsave(&mac->lock, flags);
219 net->authenticating = 0;
220 net->authenticated = 1;
221 spin_unlock_irqrestore(&mac->lock, flags);
222 printkl(KERN_NOTICE PFX "Shared Key Authentication completed with "MAC_FMT"\n",
223 MAC_ARG(net->bssid));
224 break;
225 default:
226 printkl(KERN_NOTICE PFX "Shared Key Authentication with "MAC_FMT" failed, error code: %i\n",
227 MAC_ARG(net->bssid), le16_to_cpup(&auth->status));
228 /* Lock and reset flags */
229 spin_lock_irqsave(&mac->lock, flags);
230 net->authenticating = 0;
231 net->authenticated = 0;
232 spin_unlock_irqrestore(&mac->lock, flags);
233 /* Count the error? */
234 break;
235 }
236 goto free_aq;
237 break;
238 default:
239 printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
240 break;
241 }
242 goto free_aq;
243 break;
244 default:
245 /* ERROR */
246 goto free_aq;
247 break;
248 }
249 return 0;
250free_aq:
251 /* Cancel the timeout */
252 spin_lock_irqsave(&mac->lock, flags);
253 cancel_delayed_work(&aq->work);
254 /* Remove this item from the queue */
255 list_del(&aq->list);
256 spin_unlock_irqrestore(&mac->lock, flags);
257
258 /* Free it */
259 kfree(aq);
260 return 0;
261}
262
263/*
264 * Handle deauthorization
265 */
266static void
267ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
268 struct ieee80211softmac_network *net)
269{
270 struct ieee80211softmac_auth_queue_item *aq = NULL;
271 struct list_head *list_ptr;
272 unsigned long flags;
273
274 /* Lock and reset status flags */
275 spin_lock_irqsave(&mac->lock, flags);
276 net->authenticating = 0;
277 net->authenticated = 0;
278
279 /* Find correct auth queue item, if it exists */
280 list_for_each(list_ptr, &mac->auth_queue) {
281 aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
282 if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
283 break;
284 else
285 aq = NULL;
286 }
287
288 /* Cancel pending work */
289 if(aq != NULL)
290 /* Not entirely safe? What about running work? */
291 cancel_delayed_work(&aq->work);
292
293 /* Free our network ref */
294 ieee80211softmac_del_network_locked(mac, net);
295 if(net->challenge != NULL)
296 kfree(net->challenge);
297 kfree(net);
298
299 /* can't transmit data right now... */
300 netif_carrier_off(mac->dev);
301 /* let's try to re-associate */
302 schedule_work(&mac->associnfo.work);
303 spin_unlock_irqrestore(&mac->lock, flags);
304}
305
306/*
307 * Sends a deauth request to the desired AP
308 */
309int
310ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
311 struct ieee80211softmac_network *net, int reason)
312{
313 int ret;
314
315 /* Make sure the network is authenticated */
316 if (!net->authenticated)
317 {
318 printkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
319 /* Error okay? */
320 return -EPERM;
321 }
322
323 /* Send the de-auth packet */
324 if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
325 return ret;
326
327 ieee80211softmac_deauth_from_net(mac, net);
328 return 0;
329}
330
331/*
332 * This should be registered with ieee80211 as handle_deauth
333 */
334int
335ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
336{
337
338 struct ieee80211softmac_network *net = NULL;
339 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340
341 if (!deauth) {
342 dprintk("deauth without deauth packet. eek!\n");
343 return 0;
344 }
345
346 net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
347
348 if (net == NULL) {
349 printkl(KERN_DEBUG PFX "Received deauthentication packet from "MAC_FMT", but that network is unknown.\n",
350 MAC_ARG(deauth->header.addr2));
351 return 0;
352 }
353
354 /* Make sure the network is authenticated */
355 if(!net->authenticated)
356 {
357 printkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
358 /* Error okay? */
359 return -EPERM;
360 }
361
362 ieee80211softmac_deauth_from_net(mac, net);
363 return 0;
364}
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
new file mode 100644
index 000000000000..0a52bbda1e4c
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_event.c
@@ -0,0 +1,159 @@
1/*
2 * Event system
3 * Also see comments in public header file and longer explanation below.
4 *
5 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
6 * Joseph Jezak <josejx@gentoo.org>
7 * Larry Finger <Larry.Finger@lwfinger.net>
8 * Danny van Dyk <kugelfang@gentoo.org>
9 * Michael Buesch <mbuesch@freenet.de>
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 * The full GNU General Public License is included in this distribution in the
25 * file called COPYING.
26 */
27
28#include "ieee80211softmac_priv.h"
29
30/*
31 * Each event has associated to it
32 * - an event type (see constants in public header)
33 * - an event context (see below)
34 * - the function to be called
35 * - a context (extra parameter to call the function with)
36 * - and the softmac struct
37 *
38 * The event context is private and can only be used from
39 * within this module. Its meaning varies with the event
40 * type:
41 * SCAN_FINISHED: no special meaning
42 * ASSOCIATED,
43 * ASSOCIATE_FAILED,
44 * ASSOCIATE_TIMEOUT,
45 * AUTHENTICATED,
46 * AUTH_FAILED,
47 * AUTH_TIMEOUT: a pointer to the network struct
48 * ...
49 * Code within this module can use the event context to be only
50 * called when the event is true for that specific context
51 * as per above table.
52 * If the event context is NULL, then the notification is always called,
53 * regardless of the event context. The event context is not passed to
54 * the callback, it is assumed that the context suffices.
55 *
56 * You can also use the event context only by setting the event type
57 * to -1 (private use only), in which case you'll be notified
58 * whenever the event context matches.
59 */
60
61static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
62 "scan finished",
63 "associated",
64 "associating failed",
65 "associating timed out",
66 "authenticated",
67 "authenticating failed",
68 "authenticating timed out",
69 "associating failed because no suitable network was found",
70};
71
72
73static void
74ieee80211softmac_notify_callback(void *d)
75{
76 struct ieee80211softmac_event event = *(struct ieee80211softmac_event*) d;
77 kfree(d);
78
79 event.fun(event.mac->dev, event.context);
80}
81
82int
83ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
84 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
85{
86 struct ieee80211softmac_event *eventptr;
87 unsigned long flags;
88
89 if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
90 return -ENOSYS;
91
92 if (!fun)
93 return -EINVAL;
94
95 eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
96 if (!eventptr)
97 return -ENOMEM;
98
99 eventptr->event_type = event;
100 INIT_WORK(&eventptr->work, ieee80211softmac_notify_callback, eventptr);
101 eventptr->fun = fun;
102 eventptr->context = context;
103 eventptr->mac = mac;
104 eventptr->event_context = event_context;
105
106 spin_lock_irqsave(&mac->lock, flags);
107 list_add(&eventptr->list, &mac->events);
108 spin_unlock_irqrestore(&mac->lock, flags);
109
110 return 0;
111}
112
113int
114ieee80211softmac_notify_gfp(struct net_device *dev,
115 int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
116{
117 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
118
119 if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
120 return -ENOSYS;
121
122 return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
123}
124EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
125
126/* private -- calling all callbacks that were specified */
127void
128ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
129{
130 struct ieee80211softmac_event *eventptr, *tmp;
131 union iwreq_data wrqu;
132 char *msg;
133
134 if (event >= 0) {
135 msg = event_descriptions[event];
136 wrqu.data.length = strlen(msg);
137 wireless_send_event(mac->dev, IWEVCUSTOM, &wrqu, msg);
138 }
139
140 if (!list_empty(&mac->events))
141 list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
142 if ((eventptr->event_type == event || eventptr->event_type == -1)
143 && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
144 list_del(&eventptr->list);
145 schedule_work(&eventptr->work);
146 }
147 }
148}
149
150void
151ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
152{
153 unsigned long flags;
154
155 spin_lock_irqsave(&mac->lock, flags);
156 ieee80211softmac_call_events_locked(mac, event, event_ctx);
157
158 spin_unlock_irqrestore(&mac->lock, flags);
159}
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
new file mode 100644
index 000000000000..febc51dbb412
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -0,0 +1,474 @@
1/*
2 * Some parts based on code from net80211
3 * Copyright (c) 2001 Atsushi Onoe
4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35#include "ieee80211softmac_priv.h"
36
37/* Helper functions for inserting data into the frames */
38
39/*
40 * Adds an ESSID element to the frame
41 *
42 */
43static u8 *
44ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
45{
46 if (essid) {
47 *dst++ = MFIE_TYPE_SSID;
48 *dst++ = essid->len;
49 memcpy(dst, essid->data, essid->len);
50 return dst+essid->len;
51 } else {
52 *dst++ = MFIE_TYPE_SSID;
53 *dst++ = 0;
54 return dst;
55 }
56}
57
58/* Adds Supported Rates and if required Extended Rates Information Element
59 * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
60static u8 *
61ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
62{
63 int cck_len, ofdm_len;
64 *dst++ = MFIE_TYPE_RATES;
65
66 for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
67
68 if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
69 cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
70 *dst++ = cck_len;
71 memcpy(dst, r->rates, cck_len);
72 dst += cck_len;
73
74 if(cck_len < r->count){
75 for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
76 if (ofdm_len > 0) {
77 if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
78 ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
79 *dst++ = MFIE_TYPE_RATES_EX;
80 *dst++ = ofdm_len;
81 memcpy(dst, r->rates + cck_len, ofdm_len);
82 dst += ofdm_len;
83 }
84 }
85 return dst;
86}
87
88/* Allocate a management frame */
89static u8 *
90ieee80211softmac_alloc_mgt(u32 size)
91{
92 u8 * data;
93
94 /* Add the header and FCS to the size */
95 size = size + IEEE80211_3ADDR_LEN;
96 if(size > IEEE80211_DATA_LEN)
97 return NULL;
98 /* Allocate the frame */
99 data = kmalloc(size, GFP_ATOMIC);
100 memset(data, 0, size);
101 return data;
102}
103
104/*
105 * Add a 2 Address Header
106 */
107static void
108ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
109 struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
110{
111 /* Fill in the frame control flags */
112 header->frame_ctl = cpu_to_le16(type);
113 /* Control packets always have WEP turned off */
114 if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
115 header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
116
117 /* Fill in the duration */
118 header->duration_id = 0;
119 /* FIXME: How do I find this?
120 * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
121
122 /* Fill in the Destination Address */
123 if(dest == NULL)
124 memset(header->addr1, 0xFF, ETH_ALEN);
125 else
126 memcpy(header->addr1, dest, ETH_ALEN);
127 /* Fill in the Source Address */
128 memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
129
130}
131
132
133/* Add a 3 Address Header */
134static void
135ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
136 struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
137{
138 /* This is common with 2addr, so use that instead */
139 ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
140
141 /* Fill in the BSS ID */
142 if(bssid == NULL)
143 memset(header->addr3, 0xFF, ETH_ALEN);
144 else
145 memcpy(header->addr3, bssid, ETH_ALEN);
146
147 /* Fill in the sequence # */
148 /* FIXME: I need to add this to the softmac struct
149 * shouldn't the sequence number be in ieee80211? */
150}
151
152
153/*****************************************************************************
154 * Create Management packets
155 *****************************************************************************/
156
157/* Creates an association request packet */
158static u32
159ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
160 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
161{
162 u8 *data;
163 (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
164 2 + /* Capability Info */
165 2 + /* Listen Interval */
166 /* SSID IE */
167 1 + 1 + IW_ESSID_MAX_SIZE +
168 /* Rates IE */
169 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
170 /* Extended Rates IE */
171 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
172 /* WPA IE if present */
173 mac->wpa.IElen
174 /* Other IE's? Optional?
175 * Yeah, probably need an extra IE parameter -- lots of vendors like to
176 * fill in their own IEs */
177 );
178 if (unlikely((*pkt) == NULL))
179 return 0;
180 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
181
182 /* Fill in capability Info */
183 (*pkt)->capability = (mac->ieee->iw_mode == IW_MODE_MASTER) || (mac->ieee->iw_mode == IW_MODE_INFRA) ?
184 cpu_to_le16(WLAN_CAPABILITY_ESS) :
185 cpu_to_le16(WLAN_CAPABILITY_IBSS);
186 /* Need to add this
187 (*pkt)->capability |= mac->ieee->short_slot ?
188 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
189 */
190 (*pkt)->capability |= mac->ieee->sec.level ? cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
191 /* Fill in Listen Interval (?) */
192 (*pkt)->listen_interval = cpu_to_le16(10);
193
194 data = (u8 *)(*pkt)->info_element;
195 /* Add SSID */
196 data = ieee80211softmac_add_essid(data, &net->essid);
197 /* Add Rates */
198 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
199 /* Add WPA IE */
200 if (mac->wpa.IElen && mac->wpa.IE) {
201 memcpy(data, mac->wpa.IE, mac->wpa.IElen);
202 data += mac->wpa.IElen;
203 }
204 /* Return the number of used bytes */
205 return (data - (u8*)(*pkt));
206}
207
208/* Create a reassociation request packet */
209static u32
210ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
211 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
212{
213 u8 *data;
214 (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
215 2 + /* Capability Info */
216 2 + /* Listen Interval */
217 ETH_ALEN + /* AP MAC */
218 /* SSID IE */
219 1 + 1 + IW_ESSID_MAX_SIZE +
220 /* Rates IE */
221 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
222 /* Extended Rates IE */
223 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
224 /* Other IE's? */
225 );
226 if (unlikely((*pkt) == NULL))
227 return 0;
228 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
229
230 /* Fill in capability Info */
231 (*pkt)->capability = mac->ieee->iw_mode == IW_MODE_MASTER ?
232 cpu_to_le16(WLAN_CAPABILITY_ESS) :
233 cpu_to_le16(WLAN_CAPABILITY_IBSS);
234 /*
235 (*pkt)->capability |= mac->ieee->short_slot ?
236 cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME) : 0;
237 */
238 (*pkt)->capability |= mac->ieee->sec.level ?
239 cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
240
241 /* Fill in Listen Interval (?) */
242 (*pkt)->listen_interval = cpu_to_le16(10);
243 /* Fill in the current AP MAC */
244 memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
245
246 data = (u8 *)(*pkt)->info_element;
247 /* Add SSID */
248 data = ieee80211softmac_add_essid(data, &net->essid);
249 /* Add Rates */
250 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
251 /* Return packet size */
252 return (data - (u8 *)(*pkt));
253}
254
255/* Create an authentication packet */
256static u32
257ieee80211softmac_auth(struct ieee80211_auth **pkt,
258 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
259 u16 transaction, u16 status)
260{
261 u8 *data;
262 /* Allocate Packet */
263 (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
264 2 + /* Auth Algorithm */
265 2 + /* Auth Transaction Seq */
266 2 + /* Status Code */
267 /* Challenge Text IE */
268 mac->ieee->open_wep ? 0 :
269 1 + 1 + WLAN_AUTH_CHALLENGE_LEN
270 );
271 if (unlikely((*pkt) == NULL))
272 return 0;
273 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
274
275 /* Algorithm */
276 (*pkt)->algorithm = mac->ieee->open_wep ?
277 cpu_to_le16(WLAN_AUTH_OPEN) :
278 cpu_to_le16(WLAN_AUTH_SHARED_KEY);
279 /* Transaction */
280 (*pkt)->transaction = cpu_to_le16(transaction);
281 /* Status */
282 (*pkt)->status = cpu_to_le16(status);
283
284 data = (u8 *)(*pkt)->info_element;
285 /* Challenge Text */
286 if(!mac->ieee->open_wep){
287 *data = MFIE_TYPE_CHALLENGE;
288 data++;
289
290 /* Copy the challenge in */
291 // *data = challenge length
292 // data += sizeof(u16);
293 // memcpy(data, challenge, challenge length);
294 // data += challenge length;
295
296 /* Add the full size to the packet length */
297 }
298
299 /* Return the packet size */
300 return (data - (u8 *)(*pkt));
301}
302
303/* Create a disassocation or deauthentication packet */
304static u32
305ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
306 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
307 u16 type, u16 reason)
308{
309 /* Allocate Packet */
310 (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
311 if (unlikely((*pkt) == NULL))
312 return 0;
313 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
314 /* Reason */
315 (*pkt)->reason = cpu_to_le16(reason);
316 /* Return the packet size */
317 return (2 + IEEE80211_3ADDR_LEN);
318}
319
320/* Create a probe request packet */
321static u32
322ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
323 struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
324{
325 u8 *data;
326 /* Allocate Packet */
327 (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
328 /* SSID of requested network */
329 1 + 1 + IW_ESSID_MAX_SIZE +
330 /* Rates IE */
331 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
332 /* Extended Rates IE */
333 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
334 );
335 if (unlikely((*pkt) == NULL))
336 return 0;
337 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
338
339 data = (u8 *)(*pkt)->info_element;
340 /* Add ESSID (can be NULL) */
341 data = ieee80211softmac_add_essid(data, essid);
342 /* Add Rates */
343 data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
344 /* Return packet size */
345 return (data - (u8 *)(*pkt));
346}
347
348/* Create a probe response packet */
349/* FIXME: Not complete */
350static u32
351ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
352 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
353{
354 u8 *data;
355 /* Allocate Packet */
356 (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
357 8 + /* Timestamp */
358 2 + /* Beacon Interval */
359 2 + /* Capability Info */
360 /* SSID IE */
361 1 + 1 + IW_ESSID_MAX_SIZE +
362 7 + /* FH Parameter Set */
363 2 + /* DS Parameter Set */
364 8 + /* CF Parameter Set */
365 4 /* IBSS Parameter Set */
366 );
367 if (unlikely((*pkt) == NULL))
368 return 0;
369 ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
370 data = (u8 *)(*pkt)->info_element;
371
372 /* Return the packet size */
373 return (data - (u8 *)(*pkt));
374}
375
376
377/* Sends a manangement packet
378 * FIXME: document the use of the arg parameter
379 * for _AUTH: (transaction #) | (status << 16)
380 */
381int
382ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
383 void *ptrarg, u32 type, u32 arg)
384{
385 void *pkt = NULL;
386 u32 pkt_size = 0;
387
388 switch(type) {
389 case IEEE80211_STYPE_ASSOC_REQ:
390 pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
391 break;
392 case IEEE80211_STYPE_REASSOC_REQ:
393 pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
394 break;
395 case IEEE80211_STYPE_AUTH:
396 pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16));
397 break;
398 case IEEE80211_STYPE_DISASSOC:
399 case IEEE80211_STYPE_DEAUTH:
400 pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
401 break;
402 case IEEE80211_STYPE_PROBE_REQ:
403 pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
404 break;
405 case IEEE80211_STYPE_PROBE_RESP:
406 pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
407 break;
408 default:
409 printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
410 return -EINVAL;
411 };
412
413 if(pkt_size == 0 || pkt == NULL) {
414 printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
415 return -ENOMEM;
416 }
417
418 /* Send the packet to the ieee80211 layer for tx */
419 /* we defined softmac->mgmt_xmit for this. Should we keep it
420 * as it is (that means we'd need to wrap this into a txb),
421 * modify the prototype (so it matches this function),
422 * or get rid of it alltogether?
423 * Does this work for you now?
424 */
425 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, pkt_size);
426
427 kfree(pkt);
428 return 0;
429}
430
431
432/* Create an rts/cts frame */
433static u32
434ieee80211softmac_rts_cts(struct ieee80211_hdr_2addr **pkt,
435 struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
436 u32 type)
437{
438 /* Allocate Packet */
439 (*pkt) = kmalloc(IEEE80211_2ADDR_LEN, GFP_ATOMIC);
440 memset(*pkt, 0, IEEE80211_2ADDR_LEN);
441 if((*pkt) == NULL)
442 return 0;
443 ieee80211softmac_hdr_2addr(mac, (*pkt), type, net->bssid);
444 return IEEE80211_2ADDR_LEN;
445}
446
447
448/* Sends a control packet */
449static int
450ieee80211softmac_send_ctl_frame(struct ieee80211softmac_device *mac,
451 struct ieee80211softmac_network *net, u32 type, u32 arg)
452{
453 void *pkt = NULL;
454 u32 pkt_size = 0;
455
456 switch(type) {
457 case IEEE80211_STYPE_RTS:
458 case IEEE80211_STYPE_CTS:
459 pkt_size = ieee80211softmac_rts_cts((struct ieee80211_hdr_2addr **)(&pkt), mac, net, type);
460 break;
461 default:
462 printkl(KERN_DEBUG PFX "Unsupported Control Frame type: %i\n", type);
463 return -EINVAL;
464 }
465
466 if(pkt_size == 0)
467 return -ENOMEM;
468
469 /* Send the packet to the ieee80211 layer for tx */
470 ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *) pkt, pkt_size);
471
472 kfree(pkt);
473 return 0;
474}
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
new file mode 100644
index 000000000000..6f99f781bff8
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -0,0 +1,457 @@
1/*
2 * Contains some basic softmac functions along with module registration code etc.
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#include "ieee80211softmac_priv.h"
28#include <linux/sort.h>
29
30struct net_device *alloc_ieee80211softmac(int sizeof_priv)
31{
32 struct ieee80211softmac_device *softmac;
33 struct net_device *dev;
34
35 dev = alloc_ieee80211(sizeof(struct ieee80211softmac_device) + sizeof_priv);
36 softmac = ieee80211_priv(dev);
37 softmac->dev = dev;
38 softmac->ieee = netdev_priv(dev);
39 spin_lock_init(&softmac->lock);
40
41 softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
42 softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
43 softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
44 softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
45 softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
46 softmac->scaninfo = NULL;
47
48 /* TODO: initialise all the other callbacks in the ieee struct
49 * (once they're written)
50 */
51
52 INIT_LIST_HEAD(&softmac->auth_queue);
53 INIT_LIST_HEAD(&softmac->network_list);
54 INIT_LIST_HEAD(&softmac->events);
55
56 INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
57 INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
58 softmac->start_scan = ieee80211softmac_start_scan_implementation;
59 softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
60 softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
61
62 //TODO: The mcast rate has to be assigned dynamically somewhere (in scanning, association. Not sure...)
63 // It has to be set to the highest rate all stations in the current network can handle.
64 softmac->txrates.mcast_rate = IEEE80211_CCK_RATE_1MB;
65 softmac->txrates.mcast_fallback = IEEE80211_CCK_RATE_1MB;
66 /* This is reassigned in ieee80211softmac_start to sane values. */
67 softmac->txrates.default_rate = IEEE80211_CCK_RATE_1MB;
68 softmac->txrates.default_fallback = IEEE80211_CCK_RATE_1MB;
69
70 /* to start with, we can't send anything ... */
71 netif_carrier_off(dev);
72
73 return dev;
74}
75EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
76
77/* Clears the pending work queue items, stops all scans, etc. */
78void
79ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
80{
81 unsigned long flags;
82 struct ieee80211softmac_event *eventptr, *eventtmp;
83 struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
84 struct ieee80211softmac_network *netptr, *nettmp;
85
86 ieee80211softmac_stop_scan(sm);
87 ieee80211softmac_wait_for_scan(sm);
88
89 spin_lock_irqsave(&sm->lock, flags);
90 /* Free all pending assoc work items */
91 cancel_delayed_work(&sm->associnfo.work);
92
93 /* Free all pending scan work items */
94 if(sm->scaninfo != NULL)
95 cancel_delayed_work(&sm->scaninfo->softmac_scan);
96
97 /* Free all pending auth work items */
98 list_for_each_entry(authptr, &sm->auth_queue, list)
99 cancel_delayed_work(&authptr->work);
100
101 /* delete all pending event calls and work items */
102 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
103 cancel_delayed_work(&eventptr->work);
104
105 spin_unlock_irqrestore(&sm->lock, flags);
106 flush_scheduled_work();
107
108 /* now we should be save and no longer need locking... */
109 spin_lock_irqsave(&sm->lock, flags);
110 /* Free all pending auth work items */
111 list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
112 list_del(&authptr->list);
113 kfree(authptr);
114 }
115
116 /* delete all pending event calls and work items */
117 list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
118 list_del(&eventptr->list);
119 kfree(eventptr);
120 }
121
122 /* Free all networks */
123 list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
124 ieee80211softmac_del_network_locked(sm, netptr);
125 if(netptr->challenge != NULL)
126 kfree(netptr->challenge);
127 kfree(netptr);
128 }
129
130 spin_unlock_irqrestore(&sm->lock, flags);
131}
132EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
133
134void free_ieee80211softmac(struct net_device *dev)
135{
136 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
137 ieee80211softmac_clear_pending_work(sm);
138 kfree(sm->scaninfo);
139 kfree(sm->wpa.IE);
140 free_ieee80211(dev);
141}
142EXPORT_SYMBOL_GPL(free_ieee80211softmac);
143
144static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
145{
146 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
147 /* I took out the sorting check, we're seperating by modulation now. */
148 if (ri->count)
149 return;
150 /* otherwise assume we hav'em all! */
151 if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
152 ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
153 ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
154 ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
155 ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
156 }
157 if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
158 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
159 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
160 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
161 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
162 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
163 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
164 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
165 ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
166 }
167}
168
169void ieee80211softmac_start(struct net_device *dev)
170{
171 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
172 struct ieee80211_device *ieee = mac->ieee;
173 u32 change = 0;
174 struct ieee80211softmac_txrates oldrates;
175
176 ieee80211softmac_start_check_rates(mac);
177
178 /* TODO: We need some kind of state machine to lower the default rates
179 * if we loose too many packets.
180 */
181 /* Change the default txrate to the highest possible value.
182 * The txrate machine will lower it, if it is too high.
183 */
184 if (mac->txrates_change)
185 oldrates = mac->txrates;
186 if (ieee->modulation & IEEE80211_OFDM_MODULATION) {
187 mac->txrates.default_rate = IEEE80211_OFDM_RATE_54MB;
188 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
189 mac->txrates.default_fallback = IEEE80211_OFDM_RATE_24MB;
190 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
191 } else if (ieee->modulation & IEEE80211_CCK_MODULATION) {
192 mac->txrates.default_rate = IEEE80211_CCK_RATE_11MB;
193 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
194 mac->txrates.default_fallback = IEEE80211_CCK_RATE_5MB;
195 change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
196 } else
197 assert(0);
198 if (mac->txrates_change)
199 mac->txrates_change(dev, change, &oldrates);
200}
201EXPORT_SYMBOL_GPL(ieee80211softmac_start);
202
203void ieee80211softmac_stop(struct net_device *dev)
204{
205 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
206
207 ieee80211softmac_clear_pending_work(mac);
208}
209EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
210
211void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
212{
213 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
214 unsigned long flags;
215
216 spin_lock_irqsave(&mac->lock, flags);
217 memcpy(mac->ratesinfo.rates, rates, count);
218 mac->ratesinfo.count = count;
219 spin_unlock_irqrestore(&mac->lock, flags);
220}
221EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
222
223static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
224{
225 int i;
226 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
227
228 for (i=0; i<ri->count-1; i++) {
229 if (ri->rates[i] == rate)
230 return ri->rates[i+1];
231 }
232 /* I guess we can't go any higher... */
233 return ri->rates[ri->count];
234}
235
236u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
237{
238 int i;
239 struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
240
241 for (i=delta; i<ri->count; i++) {
242 if (ri->rates[i] == rate)
243 return ri->rates[i-delta];
244 }
245 /* I guess we can't go any lower... */
246 return ri->rates[0];
247}
248
249static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
250 int amount)
251{
252 struct ieee80211softmac_txrates oldrates;
253 u8 default_rate = mac->txrates.default_rate;
254 u8 default_fallback = mac->txrates.default_fallback;
255 u32 changes = 0;
256
257 //TODO: This is highly experimental code.
258 // Maybe the dynamic rate selection does not work
259 // and it has to be removed again.
260
261printk("badness %d\n", mac->txrate_badness);
262 mac->txrate_badness += amount;
263 if (mac->txrate_badness <= -1000) {
264 /* Very small badness. Try a faster bitrate. */
265 if (mac->txrates_change)
266 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
267 default_rate = raise_rate(mac, default_rate);
268 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
269 default_fallback = get_fallback_rate(mac, default_rate);
270 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
271 mac->txrate_badness = 0;
272printk("Bitrate raised to %u\n", default_rate);
273 } else if (mac->txrate_badness >= 10000) {
274 /* Very high badness. Try a slower bitrate. */
275 if (mac->txrates_change)
276 memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
277 default_rate = lower_rate(mac, default_rate);
278 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
279 default_fallback = get_fallback_rate(mac, default_rate);
280 changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
281 mac->txrate_badness = 0;
282printk("Bitrate lowered to %u\n", default_rate);
283 }
284
285 mac->txrates.default_rate = default_rate;
286 mac->txrates.default_fallback = default_fallback;
287
288 if (changes && mac->txrates_change)
289 mac->txrates_change(mac->dev, changes, &oldrates);
290}
291
292void ieee80211softmac_fragment_lost(struct net_device *dev,
293 u16 wl_seq)
294{
295 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
296 unsigned long flags;
297
298 spin_lock_irqsave(&mac->lock, flags);
299 ieee80211softmac_add_txrates_badness(mac, 1000);
300 //TODO
301
302 spin_unlock_irqrestore(&mac->lock, flags);
303}
304EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
305
306static int rate_cmp(const void *a_, const void *b_) {
307 u8 *a, *b;
308 a = (u8*)a_;
309 b = (u8*)b_;
310 return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
311}
312
313/* Allocate a softmac network struct and fill it from a network */
314struct ieee80211softmac_network *
315ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
316 struct ieee80211_network *net)
317{
318 struct ieee80211softmac_network *softnet;
319 softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
320 if(softnet == NULL)
321 return NULL;
322 memcpy(softnet->bssid, net->bssid, ETH_ALEN);
323 softnet->channel = net->channel;
324 softnet->essid.len = net->ssid_len;
325 memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
326
327 /* copy rates over */
328 softnet->supported_rates.count = net->rates_len;
329 memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
330 memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
331 softnet->supported_rates.count += net->rates_ex_len;
332 sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
333
334 softnet->capabilities = net->capability;
335 return softnet;
336}
337
338
339/* Add a network to the list, while locked */
340void
341ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
342 struct ieee80211softmac_network *add_net)
343{
344 struct list_head *list_ptr;
345 struct ieee80211softmac_network *softmac_net = NULL;
346
347 list_for_each(list_ptr, &mac->network_list) {
348 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
349 if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
350 break;
351 else
352 softmac_net = NULL;
353 }
354 if(softmac_net == NULL)
355 list_add(&(add_net->list), &mac->network_list);
356}
357
358/* Add a network to the list, with locking */
359void
360ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
361 struct ieee80211softmac_network *add_net)
362{
363 unsigned long flags;
364 spin_lock_irqsave(&mac->lock, flags);
365 ieee80211softmac_add_network_locked(mac, add_net);
366 spin_unlock_irqrestore(&mac->lock, flags);
367}
368
369
370/* Delete a network from the list, while locked*/
371void
372ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
373 struct ieee80211softmac_network *del_net)
374{
375 list_del(&(del_net->list));
376}
377
378/* Delete a network from the list with locking */
379void
380ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
381 struct ieee80211softmac_network *del_net)
382{
383 unsigned long flags;
384 spin_lock_irqsave(&mac->lock, flags);
385 ieee80211softmac_del_network_locked(mac, del_net);
386 spin_unlock_irqrestore(&mac->lock, flags);
387}
388
389/* Get a network from the list by MAC while locked */
390struct ieee80211softmac_network *
391ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
392 u8 *bssid)
393{
394 struct list_head *list_ptr;
395 struct ieee80211softmac_network *softmac_net = NULL;
396 list_for_each(list_ptr, &mac->network_list) {
397 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
398 if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
399 break;
400 else
401 softmac_net = NULL;
402 }
403 return softmac_net;
404}
405
406/* Get a network from the list by BSSID with locking */
407struct ieee80211softmac_network *
408ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
409 u8 *bssid)
410{
411 unsigned long flags;
412 struct ieee80211softmac_network *softmac_net;
413
414 spin_lock_irqsave(&mac->lock, flags);
415 softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
416 spin_unlock_irqrestore(&mac->lock, flags);
417 return softmac_net;
418}
419
420/* Get a network from the list by ESSID while locked */
421struct ieee80211softmac_network *
422ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
423 struct ieee80211softmac_essid *essid)
424{
425 struct list_head *list_ptr;
426 struct ieee80211softmac_network *softmac_net = NULL;
427
428 list_for_each(list_ptr, &mac->network_list) {
429 softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
430 if (softmac_net->essid.len == essid->len &&
431 !memcmp(softmac_net->essid.data, essid->data, essid->len))
432 return softmac_net;
433 }
434 return NULL;
435}
436
437/* Get a network from the list by ESSID with locking */
438struct ieee80211softmac_network *
439ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
440 struct ieee80211softmac_essid *essid)
441{
442 unsigned long flags;
443 struct ieee80211softmac_network *softmac_net = NULL;
444
445 spin_lock_irqsave(&mac->lock, flags);
446 softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
447 spin_unlock_irqrestore(&mac->lock, flags);
448 return softmac_net;
449}
450
451MODULE_LICENSE("GPL");
452MODULE_AUTHOR("Johannes Berg");
453MODULE_AUTHOR("Joseph Jezak");
454MODULE_AUTHOR("Larry Finger");
455MODULE_AUTHOR("Danny van Dyk");
456MODULE_AUTHOR("Michael Buesch");
457MODULE_DESCRIPTION("802.11 software MAC");
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
new file mode 100644
index 000000000000..9ba7dbd161eb
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -0,0 +1,230 @@
1/*
2 * Internal softmac API definitions.
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#ifndef IEEE80211SOFTMAC_PRIV_H_
28#define IEEE80211SOFTMAC_PRIV_H_
29
30#include <net/ieee80211softmac.h>
31#include <net/ieee80211softmac_wx.h>
32#include <linux/kernel.h>
33#include <linux/stringify.h>
34
35
36#define PFX "SoftMAC: "
37
38#ifdef assert
39# undef assert
40#endif
41#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
42#define assert(expr) \
43 do { \
44 if (unlikely(!(expr))) { \
45 printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \
46 __FILE__, __LINE__, __FUNCTION__); \
47 } \
48 } while (0)
49#else
50#define assert(expr) do {} while (0)
51#endif
52
53/* rate limited printk(). */
54#ifdef printkl
55# undef printkl
56#endif
57#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0)
58/* rate limited printk() for debugging */
59#ifdef dprintkl
60# undef dprintkl
61#endif
62#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
63# define dprintkl printkl
64#else
65# define dprintkl(f, x...) do { /* nothing */ } while (0)
66#endif
67
68/* debugging printk() */
69#ifdef dprintk
70# undef dprintk
71#endif
72#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
73# define dprintk(f, x...) do { printk(f ,##x); } while (0)
74#else
75# define dprintk(f, x...) do { /* nothing */ } while (0)
76#endif
77
78/* private definitions and prototypes */
79
80/*** prototypes from _scan.c */
81void ieee80211softmac_scan(void *sm);
82/* for internal use if scanning is needed */
83int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
84void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
85void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
86
87/* for use by _module.c to assign to the callbacks */
88int ieee80211softmac_start_scan_implementation(struct net_device *dev);
89void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
90void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
91
92/*** Network prototypes from _module.c */
93struct ieee80211softmac_network * ieee80211softmac_create_network(
94 struct ieee80211softmac_device *mac, struct ieee80211_network *net);
95void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
96 struct ieee80211softmac_network *net);
97void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
98 struct ieee80211softmac_network *net);
99void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
100 struct ieee80211softmac_network *net);
101void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
102 struct ieee80211softmac_network *net);
103struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
104 struct ieee80211softmac_device *mac, u8 *ea);
105struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
106 struct ieee80211softmac_device *mac, u8 *ea);
107struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
108 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
109struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
110 struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
111struct ieee80211softmac_network *
112ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
113 struct ieee80211softmac_essid *essid);
114struct ieee80211softmac_network *
115ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
116 struct ieee80211softmac_essid *essid);
117
118/* Rates related */
119u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
120static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
121 return ieee80211softmac_lower_rate_delta(mac, rate, 1);
122}
123
124static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
125{
126 return ieee80211softmac_lower_rate_delta(mac, rate, 2);
127}
128
129
130/*** prototypes from _io.c */
131int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
132 void* ptrarg, u32 type, u32 arg);
133
134/*** prototypes from _auth.c */
135/* do these have to go into the public header? */
136int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
137int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
138
139/* for use by _module.c to assign to the callbacks */
140int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
141int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
142
143/*** prototypes from _assoc.c */
144void ieee80211softmac_assoc_work(void *d);
145int ieee80211softmac_handle_assoc_response(struct net_device * dev,
146 struct ieee80211_assoc_response * resp,
147 struct ieee80211_network * network);
148int ieee80211softmac_handle_disassoc(struct net_device * dev,
149 struct ieee80211_disassoc * disassoc);
150int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
151 struct ieee80211_reassoc_request * reassoc);
152void ieee80211softmac_assoc_timeout(void *d);
153
154/* some helper functions */
155static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
156{
157 return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
158 (sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
159 (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
160}
161
162static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
163{
164 return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
165 (sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
166 (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
167 ) || ieee80211softmac_scan_handlers_check_self(sm);
168}
169
170#define IEEE80211SOFTMAC_PROBE_DELAY HZ/2
171#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ)
172
173struct ieee80211softmac_network {
174 struct list_head list; /* List */
175 /* Network information copied from ieee80211_network */
176 u8 bssid[ETH_ALEN];
177 u8 channel;
178 struct ieee80211softmac_essid essid;
179
180 struct ieee80211softmac_ratesinfo supported_rates;
181
182 /* SoftMAC specific */
183 u16 authenticating:1, /* Status Flags */
184 authenticated:1,
185 auth_desynced_once:1;
186
187 u16 capabilities; /* Capabilities bitfield */
188 u8 challenge_len; /* Auth Challenge length */
189 char *challenge; /* Challenge Text */
190};
191
192/* structure used to keep track of networks we're auth'ing to */
193struct ieee80211softmac_auth_queue_item {
194 struct list_head list; /* List head */
195 struct ieee80211softmac_network *net; /* Network to auth */
196 struct ieee80211softmac_device *mac; /* SoftMAC device */
197 u8 retry; /* Retry limit */
198 u8 state; /* Auth State */
199 struct work_struct work; /* Work queue */
200};
201
202/* scanning information */
203struct ieee80211softmac_scaninfo {
204 u8 current_channel_idx,
205 number_channels;
206 struct ieee80211_channel *channels;
207 u8 started:1,
208 stop:1;
209 u8 skip_flags;
210 struct completion finished;
211 struct work_struct softmac_scan;
212};
213
214/* private event struct */
215struct ieee80211softmac_event {
216 struct list_head list;
217 int event_type;
218 void *event_context;
219 struct work_struct work;
220 notify_function_ptr fun;
221 void *context;
222 struct ieee80211softmac_device *mac;
223};
224
225void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
226void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
227int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
228 int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
229
230#endif /* IEEE80211SOFTMAC_PRIV_H_ */
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c
new file mode 100644
index 000000000000..bb9ab8b45d09
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_scan.c
@@ -0,0 +1,244 @@
1/*
2 * Scanning routines.
3 *
4 * These are not exported because they're assigned to the function pointers.
5 *
6 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
7 * Joseph Jezak <josejx@gentoo.org>
8 * Larry Finger <Larry.Finger@lwfinger.net>
9 * Danny van Dyk <kugelfang@gentoo.org>
10 * Michael Buesch <mbuesch@freenet.de>
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of version 2 of the GNU General Public License as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 * more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 * The full GNU General Public License is included in this distribution in the
26 * file called COPYING.
27 */
28
29#include <linux/completion.h>
30#include "ieee80211softmac_priv.h"
31
32/* internal, use to trigger scanning if needed.
33 * Returns -EBUSY if already scanning,
34 * result of start_scan otherwise */
35int
36ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
37{
38 unsigned long flags;
39 int ret;
40
41 spin_lock_irqsave(&sm->lock, flags);
42 if (sm->scanning)
43 {
44 spin_unlock_irqrestore(&sm->lock, flags);
45 return -EINPROGRESS;
46 }
47 sm->scanning = 1;
48 spin_unlock_irqrestore(&sm->lock, flags);
49
50 ret = sm->start_scan(sm->dev);
51 if (ret) {
52 spin_lock_irqsave(&sm->lock, flags);
53 sm->scanning = 0;
54 spin_unlock_irqrestore(&sm->lock, flags);
55 }
56 return ret;
57}
58
59void
60ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
61{
62 unsigned long flags;
63
64 spin_lock_irqsave(&sm->lock, flags);
65
66 if (!sm->scanning) {
67 spin_unlock_irqrestore(&sm->lock, flags);
68 return;
69 }
70
71 spin_unlock_irqrestore(&sm->lock, flags);
72 sm->stop_scan(sm->dev);
73}
74
75void
76ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
77{
78 unsigned long flags;
79
80 spin_lock_irqsave(&sm->lock, flags);
81
82 if (!sm->scanning) {
83 spin_unlock_irqrestore(&sm->lock, flags);
84 return;
85 }
86
87 spin_unlock_irqrestore(&sm->lock, flags);
88 sm->wait_for_scan(sm->dev);
89}
90
91
92/* internal scanning implementation follows */
93void ieee80211softmac_scan(void *d)
94{
95 int invalid_channel;
96 u8 current_channel_idx;
97 struct ieee80211softmac_device *sm = (struct ieee80211softmac_device *)d;
98 struct ieee80211softmac_scaninfo *si = sm->scaninfo;
99 unsigned long flags;
100
101 while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
102 current_channel_idx = si->current_channel_idx;
103 si->current_channel_idx++; /* go to the next channel */
104
105 invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
106
107 if (!invalid_channel) {
108 sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
109 // FIXME make this user configurable (active/passive)
110 if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
111 printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
112
113 /* also send directed management frame for the network we're looking for */
114 // TODO: is this if correct, or should we do this only if scanning from assoc request?
115 if (sm->associnfo.req_essid.len)
116 ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
117 schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
118 return;
119 } else {
120 dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
121 }
122 }
123
124 spin_lock_irqsave(&sm->lock, flags);
125 cancel_delayed_work(&si->softmac_scan);
126 si->started = 0;
127 spin_unlock_irqrestore(&sm->lock, flags);
128
129 dprintk(PFX "Scanning finished\n");
130 ieee80211softmac_scan_finished(sm);
131 complete_all(&sm->scaninfo->finished);
132}
133
134static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
135{
136 /* ugh. can we call this without having the spinlock held? */
137 struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
138 if (unlikely(!info))
139 return NULL;
140 INIT_WORK(&info->softmac_scan, ieee80211softmac_scan, mac);
141 init_completion(&info->finished);
142 return info;
143}
144
145int ieee80211softmac_start_scan_implementation(struct net_device *dev)
146{
147 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
148 unsigned long flags;
149
150 if (!(dev->flags & IFF_UP))
151 return -ENODEV;
152
153 assert(ieee80211softmac_scan_handlers_check_self(sm));
154 if (!ieee80211softmac_scan_handlers_check_self(sm))
155 return -EINVAL;
156
157 spin_lock_irqsave(&sm->lock, flags);
158 /* it looks like we need to hold the lock here
159 * to make sure we don't allocate two of these... */
160 if (unlikely(!sm->scaninfo))
161 sm->scaninfo = allocate_scaninfo(sm);
162 if (unlikely(!sm->scaninfo)) {
163 spin_unlock_irqrestore(&sm->lock, flags);
164 return -ENOMEM;
165 }
166
167 sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
168 if (0 /* not scanning in IEEE802.11b */)//TODO
169 sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
170 if (0 /* IEEE802.11a */) {//TODO
171 sm->scaninfo->channels = sm->ieee->geo.a;
172 sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
173 } else {
174 sm->scaninfo->channels = sm->ieee->geo.bg;
175 sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
176 }
177 dprintk(PFX "Start scanning with channel: %d\n", sm->scaninfo->channels[0].channel);
178 dprintk(PFX "Scanning %d channels\n", sm->scaninfo->number_channels);
179 sm->scaninfo->current_channel_idx = 0;
180 sm->scaninfo->started = 1;
181 sm->scaninfo->stop = 0;
182 INIT_COMPLETION(sm->scaninfo->finished);
183 schedule_work(&sm->scaninfo->softmac_scan);
184 spin_unlock_irqrestore(&sm->lock, flags);
185 return 0;
186}
187
188void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
189{
190 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
191 unsigned long flags;
192
193 assert(ieee80211softmac_scan_handlers_check_self(sm));
194 if (!ieee80211softmac_scan_handlers_check_self(sm))
195 return;
196
197 spin_lock_irqsave(&sm->lock, flags);
198 assert(sm->scaninfo != NULL);
199 if (sm->scaninfo) {
200 if (sm->scaninfo->started)
201 sm->scaninfo->stop = 1;
202 else
203 complete_all(&sm->scaninfo->finished);
204 }
205 spin_unlock_irqrestore(&sm->lock, flags);
206}
207
208void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
209{
210 struct ieee80211softmac_device *sm = ieee80211_priv(dev);
211 unsigned long flags;
212
213 assert(ieee80211softmac_scan_handlers_check_self(sm));
214 if (!ieee80211softmac_scan_handlers_check_self(sm))
215 return;
216
217 spin_lock_irqsave(&sm->lock, flags);
218 if (!sm->scaninfo->started) {
219 spin_unlock_irqrestore(&sm->lock, flags);
220 return;
221 }
222 spin_unlock_irqrestore(&sm->lock, flags);
223 wait_for_completion(&sm->scaninfo->finished);
224}
225
226/* this is what drivers (that do scanning) call when they're done */
227void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
228{
229 unsigned long flags;
230
231 spin_lock_irqsave(&sm->lock, flags);
232 sm->scanning = 0;
233 spin_unlock_irqrestore(&sm->lock, flags);
234
235 if (sm->associnfo.bssvalid) {
236 struct ieee80211softmac_network *net;
237
238 net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
239 if (net)
240 sm->set_channel(sm->dev, net->channel);
241 }
242 ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
243}
244EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
new file mode 100644
index 000000000000..e1a9bc6d36ff
--- /dev/null
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -0,0 +1,412 @@
1/*
2 * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
3 *
4 * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
5 * Joseph Jezak <josejx@gentoo.org>
6 * Larry Finger <Larry.Finger@lwfinger.net>
7 * Danny van Dyk <kugelfang@gentoo.org>
8 * Michael Buesch <mbuesch@freenet.de>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 * The full GNU General Public License is included in this distribution in the
24 * file called COPYING.
25 */
26
27#include "ieee80211softmac_priv.h"
28
29#include <net/iw_handler.h>
30
31
32int
33ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
34 struct iw_request_info *info,
35 union iwreq_data *data,
36 char *extra)
37{
38 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
39 return ieee80211softmac_start_scan(sm);
40}
41EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
42
43
44int
45ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
46 struct iw_request_info *info,
47 union iwreq_data *data,
48 char *extra)
49{
50 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
51 return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
52}
53EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
54
55int
56ieee80211softmac_wx_set_essid(struct net_device *net_dev,
57 struct iw_request_info *info,
58 union iwreq_data *data,
59 char *extra)
60{
61 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
62 int length = 0;
63 unsigned long flags;
64
65 spin_lock_irqsave(&sm->lock, flags);
66
67 sm->associnfo.static_essid = 0;
68
69 if (data->essid.flags && data->essid.length && extra /*required?*/) {
70 length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
71 if (length) {
72 memcpy(sm->associnfo.req_essid.data, extra, length);
73 sm->associnfo.static_essid = 1;
74 }
75 }
76 sm->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
77
78 /* set our requested ESSID length.
79 * If applicable, we have already copied the data in */
80 sm->associnfo.req_essid.len = length;
81
82 /* queue lower level code to do work (if necessary) */
83 schedule_work(&sm->associnfo.work);
84
85 spin_unlock_irqrestore(&sm->lock, flags);
86 return 0;
87}
88EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
89
90int
91ieee80211softmac_wx_get_essid(struct net_device *net_dev,
92 struct iw_request_info *info,
93 union iwreq_data *data,
94 char *extra)
95{
96 struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
97 unsigned long flags;
98
99 /* avoid getting inconsistent information */
100 spin_lock_irqsave(&sm->lock, flags);
101 /* If all fails, return ANY (empty) */
102 data->essid.length = 0;
103 data->essid.flags = 0; /* active */
104
105 /* If we have a statically configured ESSID then return it */
106 if (sm->associnfo.static_essid) {
107 data->essid.length = sm->associnfo.req_essid.len;
108 data->essid.flags = 1; /* active */
109 memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
110 }
111
112 /* If we're associating/associated, return that */
113 if (sm->associated || sm->associnfo.associating) {
114 data->essid.length = sm->associnfo.associate_essid.len;
115 data->essid.flags = 1; /* active */
116 memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
117 }
118 spin_unlock_irqrestore(&sm->lock, flags);
119 return 0;
120}
121EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
122
123int
124ieee80211softmac_wx_set_rate(struct net_device *net_dev,
125 struct iw_request_info *info,
126 union iwreq_data *data,
127 char *extra)
128{
129 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
130 struct ieee80211_device *ieee = mac->ieee;
131 unsigned long flags;
132 s32 in_rate = data->bitrate.value;
133 u8 rate;
134 int is_ofdm = 0;
135 int err = -EINVAL;
136
137 if (in_rate == -1) {
138 /* automatic detect */
139 if (ieee->modulation & IEEE80211_OFDM_MODULATION)
140 in_rate = 54000000;
141 else
142 in_rate = 11000000;
143 }
144
145 switch (in_rate) {
146 case 1000000:
147 rate = IEEE80211_CCK_RATE_1MB;
148 break;
149 case 2000000:
150 rate = IEEE80211_CCK_RATE_2MB;
151 break;
152 case 5500000:
153 rate = IEEE80211_CCK_RATE_5MB;
154 break;
155 case 11000000:
156 rate = IEEE80211_CCK_RATE_11MB;
157 break;
158 case 6000000:
159 rate = IEEE80211_OFDM_RATE_6MB;
160 is_ofdm = 1;
161 break;
162 case 9000000:
163 rate = IEEE80211_OFDM_RATE_9MB;
164 is_ofdm = 1;
165 break;
166 case 12000000:
167 rate = IEEE80211_OFDM_RATE_12MB;
168 is_ofdm = 1;
169 break;
170 case 18000000:
171 rate = IEEE80211_OFDM_RATE_18MB;
172 is_ofdm = 1;
173 break;
174 case 24000000:
175 rate = IEEE80211_OFDM_RATE_24MB;
176 is_ofdm = 1;
177 break;
178 case 36000000:
179 rate = IEEE80211_OFDM_RATE_36MB;
180 is_ofdm = 1;
181 break;
182 case 48000000:
183 rate = IEEE80211_OFDM_RATE_48MB;
184 is_ofdm = 1;
185 break;
186 case 54000000:
187 rate = IEEE80211_OFDM_RATE_54MB;
188 is_ofdm = 1;
189 break;
190 default:
191 goto out;
192 }
193
194 spin_lock_irqsave(&mac->lock, flags);
195
196 /* Check if correct modulation for this PHY. */
197 if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
198 goto out_unlock;
199
200 mac->txrates.default_rate = rate;
201 mac->txrates.default_fallback = lower_rate(mac, rate);
202 err = 0;
203
204out_unlock:
205 spin_unlock_irqrestore(&mac->lock, flags);
206out:
207 return err;
208}
209EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
210
211int
212ieee80211softmac_wx_get_rate(struct net_device *net_dev,
213 struct iw_request_info *info,
214 union iwreq_data *data,
215 char *extra)
216{
217 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
218 unsigned long flags;
219 int err = -EINVAL;
220
221 spin_lock_irqsave(&mac->lock, flags);
222 switch (mac->txrates.default_rate) {
223 case IEEE80211_CCK_RATE_1MB:
224 data->bitrate.value = 1000000;
225 break;
226 case IEEE80211_CCK_RATE_2MB:
227 data->bitrate.value = 2000000;
228 break;
229 case IEEE80211_CCK_RATE_5MB:
230 data->bitrate.value = 5500000;
231 break;
232 case IEEE80211_CCK_RATE_11MB:
233 data->bitrate.value = 11000000;
234 break;
235 case IEEE80211_OFDM_RATE_6MB:
236 data->bitrate.value = 6000000;
237 break;
238 case IEEE80211_OFDM_RATE_9MB:
239 data->bitrate.value = 9000000;
240 break;
241 case IEEE80211_OFDM_RATE_12MB:
242 data->bitrate.value = 12000000;
243 break;
244 case IEEE80211_OFDM_RATE_18MB:
245 data->bitrate.value = 18000000;
246 break;
247 case IEEE80211_OFDM_RATE_24MB:
248 data->bitrate.value = 24000000;
249 break;
250 case IEEE80211_OFDM_RATE_36MB:
251 data->bitrate.value = 36000000;
252 break;
253 case IEEE80211_OFDM_RATE_48MB:
254 data->bitrate.value = 48000000;
255 break;
256 case IEEE80211_OFDM_RATE_54MB:
257 data->bitrate.value = 54000000;
258 break;
259 default:
260 assert(0);
261 goto out_unlock;
262 }
263 err = 0;
264out_unlock:
265 spin_unlock_irqrestore(&mac->lock, flags);
266
267 return err;
268}
269EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
270
271int
272ieee80211softmac_wx_get_wap(struct net_device *net_dev,
273 struct iw_request_info *info,
274 union iwreq_data *data,
275 char *extra)
276{
277 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
278 int err = 0;
279 unsigned long flags;
280
281 spin_lock_irqsave(&mac->lock, flags);
282 if (mac->associnfo.bssvalid)
283 memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
284 else
285 memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
286 data->ap_addr.sa_family = ARPHRD_ETHER;
287 spin_unlock_irqrestore(&mac->lock, flags);
288 return err;
289}
290EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
291
292int
293ieee80211softmac_wx_set_wap(struct net_device *net_dev,
294 struct iw_request_info *info,
295 union iwreq_data *data,
296 char *extra)
297{
298 struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
299 static const unsigned char any[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
300 static const unsigned char off[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
301 unsigned long flags;
302
303 /* sanity check */
304 if (data->ap_addr.sa_family != ARPHRD_ETHER) {
305 return -EINVAL;
306 }
307
308 spin_lock_irqsave(&mac->lock, flags);
309 if (!memcmp(any, data->ap_addr.sa_data, ETH_ALEN) ||
310 !memcmp(off, data->ap_addr.sa_data, ETH_ALEN)) {
311 schedule_work(&mac->associnfo.work);
312 goto out;
313 } else {
314 if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
315 if (mac->associnfo.associating || mac->associated) {
316 /* bssid unchanged and associated or associating - just return */
317 goto out;
318 }
319 } else {
320 /* copy new value in data->ap_addr.sa_data to bssid */
321 memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
322 }
323 /* queue associate if new bssid or (old one again and not associated) */
324 schedule_work(&mac->associnfo.work);
325 }
326
327out:
328 spin_unlock_irqrestore(&mac->lock, flags);
329 return 0;
330}
331EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
332
333int
334ieee80211softmac_wx_set_genie(struct net_device *dev,
335 struct iw_request_info *info,
336 union iwreq_data *wrqu,
337 char *extra)
338{
339 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
340 unsigned long flags;
341 int err = 0;
342 char *buf;
343 int i;
344
345 spin_lock_irqsave(&mac->lock, flags);
346 /* bleh. shouldn't be locked for that kmalloc... */
347
348 if (wrqu->data.length) {
349 if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
350 /* this is an IE, so the length must be
351 * correct. Is it possible though that
352 * more than one IE is passed in?
353 */
354 err = -EINVAL;
355 goto out;
356 }
357 if (mac->wpa.IEbuflen <= wrqu->data.length) {
358 buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
359 if (!buf) {
360 err = -ENOMEM;
361 goto out;
362 }
363 kfree(mac->wpa.IE);
364 mac->wpa.IE = buf;
365 mac->wpa.IEbuflen = wrqu->data.length;
366 }
367 memcpy(mac->wpa.IE, extra, wrqu->data.length);
368 dprintk(KERN_INFO PFX "generic IE set to ");
369 for (i=0;i<wrqu->data.length;i++)
370 dprintk("%.2x", mac->wpa.IE[i]);
371 dprintk("\n");
372 mac->wpa.IElen = wrqu->data.length;
373 } else {
374 kfree(mac->wpa.IE);
375 mac->wpa.IE = NULL;
376 mac->wpa.IElen = 0;
377 mac->wpa.IEbuflen = 0;
378 }
379
380 out:
381 spin_unlock_irqrestore(&mac->lock, flags);
382 return err;
383}
384EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
385
386int
387ieee80211softmac_wx_get_genie(struct net_device *dev,
388 struct iw_request_info *info,
389 union iwreq_data *wrqu,
390 char *extra)
391{
392 struct ieee80211softmac_device *mac = ieee80211_priv(dev);
393 unsigned long flags;
394 int err = 0;
395 int space = wrqu->data.length;
396
397 spin_lock_irqsave(&mac->lock, flags);
398
399 wrqu->data.length = 0;
400
401 if (mac->wpa.IE && mac->wpa.IElen) {
402 wrqu->data.length = mac->wpa.IElen;
403 if (mac->wpa.IElen <= space)
404 memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
405 else
406 err = -E2BIG;
407 }
408 spin_unlock_irqrestore(&mac->lock, flags);
409 return err;
410}
411EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
412