0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/netdevice.h>
0012 #include <linux/rtnetlink.h>
0013 #include <linux/slab.h>
0014 #include <linux/wireless.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/export.h>
0017 #include <net/cfg80211.h>
0018 #include <net/iw_handler.h>
0019 #include <net/netlink.h>
0020 #include <net/wext.h>
0021 #include <net/net_namespace.h>
0022
0023 typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
0024 unsigned int, struct iw_request_info *,
0025 iw_handler);
0026
0027
0028
0029
0030
0031
0032 static const struct iw_ioctl_description standard_ioctl[] = {
0033 [IW_IOCTL_IDX(SIOCSIWCOMMIT)] = {
0034 .header_type = IW_HEADER_TYPE_NULL,
0035 },
0036 [IW_IOCTL_IDX(SIOCGIWNAME)] = {
0037 .header_type = IW_HEADER_TYPE_CHAR,
0038 .flags = IW_DESCR_FLAG_DUMP,
0039 },
0040 [IW_IOCTL_IDX(SIOCSIWNWID)] = {
0041 .header_type = IW_HEADER_TYPE_PARAM,
0042 .flags = IW_DESCR_FLAG_EVENT,
0043 },
0044 [IW_IOCTL_IDX(SIOCGIWNWID)] = {
0045 .header_type = IW_HEADER_TYPE_PARAM,
0046 .flags = IW_DESCR_FLAG_DUMP,
0047 },
0048 [IW_IOCTL_IDX(SIOCSIWFREQ)] = {
0049 .header_type = IW_HEADER_TYPE_FREQ,
0050 .flags = IW_DESCR_FLAG_EVENT,
0051 },
0052 [IW_IOCTL_IDX(SIOCGIWFREQ)] = {
0053 .header_type = IW_HEADER_TYPE_FREQ,
0054 .flags = IW_DESCR_FLAG_DUMP,
0055 },
0056 [IW_IOCTL_IDX(SIOCSIWMODE)] = {
0057 .header_type = IW_HEADER_TYPE_UINT,
0058 .flags = IW_DESCR_FLAG_EVENT,
0059 },
0060 [IW_IOCTL_IDX(SIOCGIWMODE)] = {
0061 .header_type = IW_HEADER_TYPE_UINT,
0062 .flags = IW_DESCR_FLAG_DUMP,
0063 },
0064 [IW_IOCTL_IDX(SIOCSIWSENS)] = {
0065 .header_type = IW_HEADER_TYPE_PARAM,
0066 },
0067 [IW_IOCTL_IDX(SIOCGIWSENS)] = {
0068 .header_type = IW_HEADER_TYPE_PARAM,
0069 },
0070 [IW_IOCTL_IDX(SIOCSIWRANGE)] = {
0071 .header_type = IW_HEADER_TYPE_NULL,
0072 },
0073 [IW_IOCTL_IDX(SIOCGIWRANGE)] = {
0074 .header_type = IW_HEADER_TYPE_POINT,
0075 .token_size = 1,
0076 .max_tokens = sizeof(struct iw_range),
0077 .flags = IW_DESCR_FLAG_DUMP,
0078 },
0079 [IW_IOCTL_IDX(SIOCSIWPRIV)] = {
0080 .header_type = IW_HEADER_TYPE_NULL,
0081 },
0082 [IW_IOCTL_IDX(SIOCGIWPRIV)] = {
0083 .header_type = IW_HEADER_TYPE_POINT,
0084 .token_size = sizeof(struct iw_priv_args),
0085 .max_tokens = 16,
0086 .flags = IW_DESCR_FLAG_NOMAX,
0087 },
0088 [IW_IOCTL_IDX(SIOCSIWSTATS)] = {
0089 .header_type = IW_HEADER_TYPE_NULL,
0090 },
0091 [IW_IOCTL_IDX(SIOCGIWSTATS)] = {
0092 .header_type = IW_HEADER_TYPE_POINT,
0093 .token_size = 1,
0094 .max_tokens = sizeof(struct iw_statistics),
0095 .flags = IW_DESCR_FLAG_DUMP,
0096 },
0097 [IW_IOCTL_IDX(SIOCSIWSPY)] = {
0098 .header_type = IW_HEADER_TYPE_POINT,
0099 .token_size = sizeof(struct sockaddr),
0100 .max_tokens = IW_MAX_SPY,
0101 },
0102 [IW_IOCTL_IDX(SIOCGIWSPY)] = {
0103 .header_type = IW_HEADER_TYPE_POINT,
0104 .token_size = sizeof(struct sockaddr) +
0105 sizeof(struct iw_quality),
0106 .max_tokens = IW_MAX_SPY,
0107 },
0108 [IW_IOCTL_IDX(SIOCSIWTHRSPY)] = {
0109 .header_type = IW_HEADER_TYPE_POINT,
0110 .token_size = sizeof(struct iw_thrspy),
0111 .min_tokens = 1,
0112 .max_tokens = 1,
0113 },
0114 [IW_IOCTL_IDX(SIOCGIWTHRSPY)] = {
0115 .header_type = IW_HEADER_TYPE_POINT,
0116 .token_size = sizeof(struct iw_thrspy),
0117 .min_tokens = 1,
0118 .max_tokens = 1,
0119 },
0120 [IW_IOCTL_IDX(SIOCSIWAP)] = {
0121 .header_type = IW_HEADER_TYPE_ADDR,
0122 },
0123 [IW_IOCTL_IDX(SIOCGIWAP)] = {
0124 .header_type = IW_HEADER_TYPE_ADDR,
0125 .flags = IW_DESCR_FLAG_DUMP,
0126 },
0127 [IW_IOCTL_IDX(SIOCSIWMLME)] = {
0128 .header_type = IW_HEADER_TYPE_POINT,
0129 .token_size = 1,
0130 .min_tokens = sizeof(struct iw_mlme),
0131 .max_tokens = sizeof(struct iw_mlme),
0132 },
0133 [IW_IOCTL_IDX(SIOCGIWAPLIST)] = {
0134 .header_type = IW_HEADER_TYPE_POINT,
0135 .token_size = sizeof(struct sockaddr) +
0136 sizeof(struct iw_quality),
0137 .max_tokens = IW_MAX_AP,
0138 .flags = IW_DESCR_FLAG_NOMAX,
0139 },
0140 [IW_IOCTL_IDX(SIOCSIWSCAN)] = {
0141 .header_type = IW_HEADER_TYPE_POINT,
0142 .token_size = 1,
0143 .min_tokens = 0,
0144 .max_tokens = sizeof(struct iw_scan_req),
0145 },
0146 [IW_IOCTL_IDX(SIOCGIWSCAN)] = {
0147 .header_type = IW_HEADER_TYPE_POINT,
0148 .token_size = 1,
0149 .max_tokens = IW_SCAN_MAX_DATA,
0150 .flags = IW_DESCR_FLAG_NOMAX,
0151 },
0152 [IW_IOCTL_IDX(SIOCSIWESSID)] = {
0153 .header_type = IW_HEADER_TYPE_POINT,
0154 .token_size = 1,
0155 .max_tokens = IW_ESSID_MAX_SIZE,
0156 .flags = IW_DESCR_FLAG_EVENT,
0157 },
0158 [IW_IOCTL_IDX(SIOCGIWESSID)] = {
0159 .header_type = IW_HEADER_TYPE_POINT,
0160 .token_size = 1,
0161 .max_tokens = IW_ESSID_MAX_SIZE,
0162 .flags = IW_DESCR_FLAG_DUMP,
0163 },
0164 [IW_IOCTL_IDX(SIOCSIWNICKN)] = {
0165 .header_type = IW_HEADER_TYPE_POINT,
0166 .token_size = 1,
0167 .max_tokens = IW_ESSID_MAX_SIZE,
0168 },
0169 [IW_IOCTL_IDX(SIOCGIWNICKN)] = {
0170 .header_type = IW_HEADER_TYPE_POINT,
0171 .token_size = 1,
0172 .max_tokens = IW_ESSID_MAX_SIZE,
0173 },
0174 [IW_IOCTL_IDX(SIOCSIWRATE)] = {
0175 .header_type = IW_HEADER_TYPE_PARAM,
0176 },
0177 [IW_IOCTL_IDX(SIOCGIWRATE)] = {
0178 .header_type = IW_HEADER_TYPE_PARAM,
0179 },
0180 [IW_IOCTL_IDX(SIOCSIWRTS)] = {
0181 .header_type = IW_HEADER_TYPE_PARAM,
0182 },
0183 [IW_IOCTL_IDX(SIOCGIWRTS)] = {
0184 .header_type = IW_HEADER_TYPE_PARAM,
0185 },
0186 [IW_IOCTL_IDX(SIOCSIWFRAG)] = {
0187 .header_type = IW_HEADER_TYPE_PARAM,
0188 },
0189 [IW_IOCTL_IDX(SIOCGIWFRAG)] = {
0190 .header_type = IW_HEADER_TYPE_PARAM,
0191 },
0192 [IW_IOCTL_IDX(SIOCSIWTXPOW)] = {
0193 .header_type = IW_HEADER_TYPE_PARAM,
0194 },
0195 [IW_IOCTL_IDX(SIOCGIWTXPOW)] = {
0196 .header_type = IW_HEADER_TYPE_PARAM,
0197 },
0198 [IW_IOCTL_IDX(SIOCSIWRETRY)] = {
0199 .header_type = IW_HEADER_TYPE_PARAM,
0200 },
0201 [IW_IOCTL_IDX(SIOCGIWRETRY)] = {
0202 .header_type = IW_HEADER_TYPE_PARAM,
0203 },
0204 [IW_IOCTL_IDX(SIOCSIWENCODE)] = {
0205 .header_type = IW_HEADER_TYPE_POINT,
0206 .token_size = 1,
0207 .max_tokens = IW_ENCODING_TOKEN_MAX,
0208 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT,
0209 },
0210 [IW_IOCTL_IDX(SIOCGIWENCODE)] = {
0211 .header_type = IW_HEADER_TYPE_POINT,
0212 .token_size = 1,
0213 .max_tokens = IW_ENCODING_TOKEN_MAX,
0214 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT,
0215 },
0216 [IW_IOCTL_IDX(SIOCSIWPOWER)] = {
0217 .header_type = IW_HEADER_TYPE_PARAM,
0218 },
0219 [IW_IOCTL_IDX(SIOCGIWPOWER)] = {
0220 .header_type = IW_HEADER_TYPE_PARAM,
0221 },
0222 [IW_IOCTL_IDX(SIOCSIWGENIE)] = {
0223 .header_type = IW_HEADER_TYPE_POINT,
0224 .token_size = 1,
0225 .max_tokens = IW_GENERIC_IE_MAX,
0226 },
0227 [IW_IOCTL_IDX(SIOCGIWGENIE)] = {
0228 .header_type = IW_HEADER_TYPE_POINT,
0229 .token_size = 1,
0230 .max_tokens = IW_GENERIC_IE_MAX,
0231 },
0232 [IW_IOCTL_IDX(SIOCSIWAUTH)] = {
0233 .header_type = IW_HEADER_TYPE_PARAM,
0234 },
0235 [IW_IOCTL_IDX(SIOCGIWAUTH)] = {
0236 .header_type = IW_HEADER_TYPE_PARAM,
0237 },
0238 [IW_IOCTL_IDX(SIOCSIWENCODEEXT)] = {
0239 .header_type = IW_HEADER_TYPE_POINT,
0240 .token_size = 1,
0241 .min_tokens = sizeof(struct iw_encode_ext),
0242 .max_tokens = sizeof(struct iw_encode_ext) +
0243 IW_ENCODING_TOKEN_MAX,
0244 },
0245 [IW_IOCTL_IDX(SIOCGIWENCODEEXT)] = {
0246 .header_type = IW_HEADER_TYPE_POINT,
0247 .token_size = 1,
0248 .min_tokens = sizeof(struct iw_encode_ext),
0249 .max_tokens = sizeof(struct iw_encode_ext) +
0250 IW_ENCODING_TOKEN_MAX,
0251 },
0252 [IW_IOCTL_IDX(SIOCSIWPMKSA)] = {
0253 .header_type = IW_HEADER_TYPE_POINT,
0254 .token_size = 1,
0255 .min_tokens = sizeof(struct iw_pmksa),
0256 .max_tokens = sizeof(struct iw_pmksa),
0257 },
0258 };
0259 static const unsigned int standard_ioctl_num = ARRAY_SIZE(standard_ioctl);
0260
0261
0262
0263
0264
0265 static const struct iw_ioctl_description standard_event[] = {
0266 [IW_EVENT_IDX(IWEVTXDROP)] = {
0267 .header_type = IW_HEADER_TYPE_ADDR,
0268 },
0269 [IW_EVENT_IDX(IWEVQUAL)] = {
0270 .header_type = IW_HEADER_TYPE_QUAL,
0271 },
0272 [IW_EVENT_IDX(IWEVCUSTOM)] = {
0273 .header_type = IW_HEADER_TYPE_POINT,
0274 .token_size = 1,
0275 .max_tokens = IW_CUSTOM_MAX,
0276 },
0277 [IW_EVENT_IDX(IWEVREGISTERED)] = {
0278 .header_type = IW_HEADER_TYPE_ADDR,
0279 },
0280 [IW_EVENT_IDX(IWEVEXPIRED)] = {
0281 .header_type = IW_HEADER_TYPE_ADDR,
0282 },
0283 [IW_EVENT_IDX(IWEVGENIE)] = {
0284 .header_type = IW_HEADER_TYPE_POINT,
0285 .token_size = 1,
0286 .max_tokens = IW_GENERIC_IE_MAX,
0287 },
0288 [IW_EVENT_IDX(IWEVMICHAELMICFAILURE)] = {
0289 .header_type = IW_HEADER_TYPE_POINT,
0290 .token_size = 1,
0291 .max_tokens = sizeof(struct iw_michaelmicfailure),
0292 },
0293 [IW_EVENT_IDX(IWEVASSOCREQIE)] = {
0294 .header_type = IW_HEADER_TYPE_POINT,
0295 .token_size = 1,
0296 .max_tokens = IW_GENERIC_IE_MAX,
0297 },
0298 [IW_EVENT_IDX(IWEVASSOCRESPIE)] = {
0299 .header_type = IW_HEADER_TYPE_POINT,
0300 .token_size = 1,
0301 .max_tokens = IW_GENERIC_IE_MAX,
0302 },
0303 [IW_EVENT_IDX(IWEVPMKIDCAND)] = {
0304 .header_type = IW_HEADER_TYPE_POINT,
0305 .token_size = 1,
0306 .max_tokens = sizeof(struct iw_pmkid_cand),
0307 },
0308 };
0309 static const unsigned int standard_event_num = ARRAY_SIZE(standard_event);
0310
0311
0312 static const int event_type_size[] = {
0313 IW_EV_LCP_LEN,
0314 0,
0315 IW_EV_CHAR_LEN,
0316 0,
0317 IW_EV_UINT_LEN,
0318 IW_EV_FREQ_LEN,
0319 IW_EV_ADDR_LEN,
0320 0,
0321 IW_EV_POINT_LEN,
0322 IW_EV_PARAM_LEN,
0323 IW_EV_QUAL_LEN,
0324 };
0325
0326 #ifdef CONFIG_COMPAT
0327 static const int compat_event_type_size[] = {
0328 IW_EV_COMPAT_LCP_LEN,
0329 0,
0330 IW_EV_COMPAT_CHAR_LEN,
0331 0,
0332 IW_EV_COMPAT_UINT_LEN,
0333 IW_EV_COMPAT_FREQ_LEN,
0334 IW_EV_COMPAT_ADDR_LEN,
0335 0,
0336 IW_EV_COMPAT_POINT_LEN,
0337 IW_EV_COMPAT_PARAM_LEN,
0338 IW_EV_COMPAT_QUAL_LEN,
0339 };
0340 #endif
0341
0342
0343
0344
0345 void wireless_nlevent_flush(void)
0346 {
0347 struct sk_buff *skb;
0348 struct net *net;
0349
0350 down_read(&net_rwsem);
0351 for_each_net(net) {
0352 while ((skb = skb_dequeue(&net->wext_nlevents)))
0353 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
0354 GFP_KERNEL);
0355 }
0356 up_read(&net_rwsem);
0357 }
0358 EXPORT_SYMBOL_GPL(wireless_nlevent_flush);
0359
0360 static int wext_netdev_notifier_call(struct notifier_block *nb,
0361 unsigned long state, void *ptr)
0362 {
0363
0364
0365
0366
0367
0368
0369
0370 wireless_nlevent_flush();
0371
0372 return NOTIFY_OK;
0373 }
0374
0375 static struct notifier_block wext_netdev_notifier = {
0376 .notifier_call = wext_netdev_notifier_call,
0377 };
0378
0379 static int __net_init wext_pernet_init(struct net *net)
0380 {
0381 skb_queue_head_init(&net->wext_nlevents);
0382 return 0;
0383 }
0384
0385 static void __net_exit wext_pernet_exit(struct net *net)
0386 {
0387 skb_queue_purge(&net->wext_nlevents);
0388 }
0389
0390 static struct pernet_operations wext_pernet_ops = {
0391 .init = wext_pernet_init,
0392 .exit = wext_pernet_exit,
0393 };
0394
0395 static int __init wireless_nlevent_init(void)
0396 {
0397 int err = register_pernet_subsys(&wext_pernet_ops);
0398
0399 if (err)
0400 return err;
0401
0402 err = register_netdevice_notifier(&wext_netdev_notifier);
0403 if (err)
0404 unregister_pernet_subsys(&wext_pernet_ops);
0405 return err;
0406 }
0407
0408 subsys_initcall(wireless_nlevent_init);
0409
0410
0411 static void wireless_nlevent_process(struct work_struct *work)
0412 {
0413 wireless_nlevent_flush();
0414 }
0415
0416 static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
0417
0418 static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
0419 struct sk_buff *skb)
0420 {
0421 struct ifinfomsg *r;
0422 struct nlmsghdr *nlh;
0423
0424 nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
0425 if (!nlh)
0426 return NULL;
0427
0428 r = nlmsg_data(nlh);
0429 r->ifi_family = AF_UNSPEC;
0430 r->__ifi_pad = 0;
0431 r->ifi_type = dev->type;
0432 r->ifi_index = dev->ifindex;
0433 r->ifi_flags = dev_get_flags(dev);
0434 r->ifi_change = 0;
0435
0436 if (nla_put_string(skb, IFLA_IFNAME, dev->name))
0437 goto nla_put_failure;
0438
0439 return nlh;
0440 nla_put_failure:
0441 nlmsg_cancel(skb, nlh);
0442 return NULL;
0443 }
0444
0445
0446
0447
0448
0449
0450
0451 void wireless_send_event(struct net_device * dev,
0452 unsigned int cmd,
0453 union iwreq_data * wrqu,
0454 const char * extra)
0455 {
0456 const struct iw_ioctl_description * descr = NULL;
0457 int extra_len = 0;
0458 struct iw_event *event;
0459 int event_len;
0460 int hdr_len;
0461 int wrqu_off = 0;
0462
0463 unsigned int cmd_index;
0464 struct sk_buff *skb;
0465 struct nlmsghdr *nlh;
0466 struct nlattr *nla;
0467 #ifdef CONFIG_COMPAT
0468 struct __compat_iw_event *compat_event;
0469 struct compat_iw_point compat_wrqu;
0470 struct sk_buff *compskb;
0471 #endif
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 if (WARN_ON(cmd == SIOCGIWSCAN && extra))
0482 extra = NULL;
0483
0484
0485 if (cmd <= SIOCIWLAST) {
0486 cmd_index = IW_IOCTL_IDX(cmd);
0487 if (cmd_index < standard_ioctl_num)
0488 descr = &(standard_ioctl[cmd_index]);
0489 } else {
0490 cmd_index = IW_EVENT_IDX(cmd);
0491 if (cmd_index < standard_event_num)
0492 descr = &(standard_event[cmd_index]);
0493 }
0494
0495 if (descr == NULL) {
0496
0497
0498
0499
0500
0501
0502
0503 netdev_err(dev, "(WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
0504 cmd);
0505 return;
0506 }
0507
0508
0509 if (descr->header_type == IW_HEADER_TYPE_POINT) {
0510
0511 if (wrqu->data.length > descr->max_tokens) {
0512 netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too big (%d)\n",
0513 cmd, wrqu->data.length);
0514 return;
0515 }
0516 if (wrqu->data.length < descr->min_tokens) {
0517 netdev_err(dev, "(WE) : Wireless Event (cmd=0x%04X) too small (%d)\n",
0518 cmd, wrqu->data.length);
0519 return;
0520 }
0521
0522 if (extra != NULL)
0523 extra_len = wrqu->data.length * descr->token_size;
0524
0525 wrqu_off = IW_EV_POINT_OFF;
0526 }
0527
0528
0529 hdr_len = event_type_size[descr->header_type];
0530 event_len = hdr_len + extra_len;
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
0556 if (!skb)
0557 return;
0558
0559
0560 nlh = rtnetlink_ifinfo_prep(dev, skb);
0561 if (WARN_ON(!nlh)) {
0562 kfree_skb(skb);
0563 return;
0564 }
0565
0566
0567 nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
0568 if (!nla) {
0569 kfree_skb(skb);
0570 return;
0571 }
0572 event = nla_data(nla);
0573
0574
0575 memset(event, 0, hdr_len);
0576 event->len = event_len;
0577 event->cmd = cmd;
0578 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
0579 if (extra_len)
0580 memcpy(((char *) event) + hdr_len, extra, extra_len);
0581
0582 nlmsg_end(skb, nlh);
0583 #ifdef CONFIG_COMPAT
0584 hdr_len = compat_event_type_size[descr->header_type];
0585 event_len = hdr_len + extra_len;
0586
0587 compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
0588 if (!compskb) {
0589 kfree_skb(skb);
0590 return;
0591 }
0592
0593
0594 nlh = rtnetlink_ifinfo_prep(dev, compskb);
0595 if (WARN_ON(!nlh)) {
0596 kfree_skb(skb);
0597 kfree_skb(compskb);
0598 return;
0599 }
0600
0601
0602 nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
0603 if (!nla) {
0604 kfree_skb(skb);
0605 kfree_skb(compskb);
0606 return;
0607 }
0608 compat_event = nla_data(nla);
0609
0610 compat_event->len = event_len;
0611 compat_event->cmd = cmd;
0612 if (descr->header_type == IW_HEADER_TYPE_POINT) {
0613 compat_wrqu.length = wrqu->data.length;
0614 compat_wrqu.flags = wrqu->data.flags;
0615 memcpy(&compat_event->pointer,
0616 ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
0617 hdr_len - IW_EV_COMPAT_LCP_LEN);
0618 if (extra_len)
0619 memcpy(((char *) compat_event) + hdr_len,
0620 extra, extra_len);
0621 } else {
0622
0623 memcpy(&compat_event->pointer, wrqu,
0624 hdr_len - IW_EV_COMPAT_LCP_LEN);
0625 }
0626
0627 nlmsg_end(compskb, nlh);
0628
0629 skb_shinfo(skb)->frag_list = compskb;
0630 #endif
0631 skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
0632 schedule_work(&wireless_nlevent_work);
0633 }
0634 EXPORT_SYMBOL(wireless_send_event);
0635
0636
0637
0638
0639
0640 struct iw_statistics *get_wireless_stats(struct net_device *dev)
0641 {
0642 #ifdef CONFIG_WIRELESS_EXT
0643 if ((dev->wireless_handlers != NULL) &&
0644 (dev->wireless_handlers->get_wireless_stats != NULL))
0645 return dev->wireless_handlers->get_wireless_stats(dev);
0646 #endif
0647
0648 #ifdef CONFIG_CFG80211_WEXT
0649 if (dev->ieee80211_ptr &&
0650 dev->ieee80211_ptr->wiphy &&
0651 dev->ieee80211_ptr->wiphy->wext &&
0652 dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
0653 return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev);
0654 #endif
0655
0656
0657 return NULL;
0658 }
0659
0660
0661 static noinline int iw_handler_get_iwstats(struct net_device * dev,
0662 struct iw_request_info * info,
0663 union iwreq_data * wrqu,
0664 char * extra)
0665 {
0666
0667 struct iw_statistics *stats;
0668
0669 stats = get_wireless_stats(dev);
0670 if (stats) {
0671
0672 memcpy(extra, stats, sizeof(struct iw_statistics));
0673 wrqu->data.length = sizeof(struct iw_statistics);
0674
0675
0676 if (wrqu->data.flags != 0)
0677 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
0678 return 0;
0679 } else
0680 return -EOPNOTSUPP;
0681 }
0682
0683 static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
0684 {
0685
0686 unsigned int index;
0687 const struct iw_handler_def *handlers = NULL;
0688
0689 #ifdef CONFIG_CFG80211_WEXT
0690 if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)
0691 handlers = dev->ieee80211_ptr->wiphy->wext;
0692 #endif
0693 #ifdef CONFIG_WIRELESS_EXT
0694 if (dev->wireless_handlers)
0695 handlers = dev->wireless_handlers;
0696 #endif
0697
0698 if (!handlers)
0699 return NULL;
0700
0701
0702 index = IW_IOCTL_IDX(cmd);
0703 if (index < handlers->num_standard)
0704 return handlers->standard[index];
0705
0706 #ifdef CONFIG_WEXT_PRIV
0707
0708 index = cmd - SIOCIWFIRSTPRIV;
0709 if (index < handlers->num_private)
0710 return handlers->private[index];
0711 #endif
0712
0713
0714 return NULL;
0715 }
0716
0717 static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
0718 const struct iw_ioctl_description *descr,
0719 iw_handler handler, struct net_device *dev,
0720 struct iw_request_info *info)
0721 {
0722 int err, extra_size, user_length = 0, essid_compat = 0;
0723 char *extra;
0724
0725
0726
0727
0728 extra_size = descr->max_tokens * descr->token_size;
0729
0730
0731 switch (cmd) {
0732 case SIOCSIWESSID:
0733 case SIOCGIWESSID:
0734 case SIOCSIWNICKN:
0735 case SIOCGIWNICKN:
0736 if (iwp->length == descr->max_tokens + 1)
0737 essid_compat = 1;
0738 else if (IW_IS_SET(cmd) && (iwp->length != 0)) {
0739 char essid[IW_ESSID_MAX_SIZE + 1];
0740 unsigned int len;
0741 len = iwp->length * descr->token_size;
0742
0743 if (len > IW_ESSID_MAX_SIZE)
0744 return -EFAULT;
0745
0746 err = copy_from_user(essid, iwp->pointer, len);
0747 if (err)
0748 return -EFAULT;
0749
0750 if (essid[iwp->length - 1] == '\0')
0751 essid_compat = 1;
0752 }
0753 break;
0754 default:
0755 break;
0756 }
0757
0758 iwp->length -= essid_compat;
0759
0760
0761 if (IW_IS_SET(cmd)) {
0762
0763 if (!iwp->pointer && iwp->length != 0)
0764 return -EFAULT;
0765
0766 if (iwp->length > descr->max_tokens)
0767 return -E2BIG;
0768 if (iwp->length < descr->min_tokens)
0769 return -EINVAL;
0770 } else {
0771
0772 if (!iwp->pointer)
0773 return -EFAULT;
0774
0775 user_length = iwp->length;
0776
0777
0778
0779
0780
0781
0782
0783 if ((descr->flags & IW_DESCR_FLAG_NOMAX) &&
0784 (user_length > descr->max_tokens)) {
0785
0786
0787
0788
0789 extra_size = user_length * descr->token_size;
0790
0791
0792
0793
0794
0795
0796 }
0797 }
0798
0799
0800 extra = kzalloc(extra_size, GFP_KERNEL);
0801 if (!extra)
0802 return -ENOMEM;
0803
0804
0805 if (IW_IS_SET(cmd) && (iwp->length != 0)) {
0806 if (copy_from_user(extra, iwp->pointer,
0807 iwp->length *
0808 descr->token_size)) {
0809 err = -EFAULT;
0810 goto out;
0811 }
0812
0813 if (cmd == SIOCSIWENCODEEXT) {
0814 struct iw_encode_ext *ee = (void *) extra;
0815
0816 if (iwp->length < sizeof(*ee) + ee->key_len) {
0817 err = -EFAULT;
0818 goto out;
0819 }
0820 }
0821 }
0822
0823 if (IW_IS_GET(cmd) && !(descr->flags & IW_DESCR_FLAG_NOMAX)) {
0824
0825
0826
0827
0828
0829
0830
0831
0832
0833
0834
0835
0836 iwp->length = descr->max_tokens;
0837 }
0838
0839 err = handler(dev, info, (union iwreq_data *) iwp, extra);
0840
0841 iwp->length += essid_compat;
0842
0843
0844 if (!err && IW_IS_GET(cmd)) {
0845
0846 if (user_length < iwp->length) {
0847 err = -E2BIG;
0848 goto out;
0849 }
0850
0851 if (copy_to_user(iwp->pointer, extra,
0852 iwp->length *
0853 descr->token_size)) {
0854 err = -EFAULT;
0855 goto out;
0856 }
0857 }
0858
0859
0860 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
0861 ((err == 0) || (err == -EIWCOMMIT))) {
0862 union iwreq_data *data = (union iwreq_data *) iwp;
0863
0864 if (descr->flags & IW_DESCR_FLAG_RESTRICT)
0865
0866
0867
0868 wireless_send_event(dev, cmd, data, NULL);
0869 else
0870 wireless_send_event(dev, cmd, data, extra);
0871 }
0872
0873 out:
0874 kfree(extra);
0875 return err;
0876 }
0877
0878
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896 int call_commit_handler(struct net_device *dev)
0897 {
0898 #ifdef CONFIG_WIRELESS_EXT
0899 if (netif_running(dev) &&
0900 dev->wireless_handlers &&
0901 dev->wireless_handlers->standard[0])
0902
0903 return dev->wireless_handlers->standard[0](dev, NULL,
0904 NULL, NULL);
0905 else
0906 return 0;
0907 #else
0908
0909 return 0;
0910 #endif
0911 }
0912
0913
0914
0915
0916
0917 static int wireless_process_ioctl(struct net *net, struct iwreq *iwr,
0918 unsigned int cmd,
0919 struct iw_request_info *info,
0920 wext_ioctl_func standard,
0921 wext_ioctl_func private)
0922 {
0923 struct net_device *dev;
0924 iw_handler handler;
0925
0926
0927
0928
0929
0930 if ((dev = __dev_get_by_name(net, iwr->ifr_name)) == NULL)
0931 return -ENODEV;
0932
0933
0934
0935
0936 if (cmd == SIOCGIWSTATS)
0937 return standard(dev, iwr, cmd, info,
0938 &iw_handler_get_iwstats);
0939
0940 #ifdef CONFIG_WEXT_PRIV
0941 if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
0942 return standard(dev, iwr, cmd, info,
0943 iw_handler_get_private);
0944 #endif
0945
0946
0947 if (!netif_device_present(dev))
0948 return -ENODEV;
0949
0950
0951 handler = get_handler(dev, cmd);
0952 if (handler) {
0953
0954 if (cmd < SIOCIWFIRSTPRIV)
0955 return standard(dev, iwr, cmd, info, handler);
0956 else if (private)
0957 return private(dev, iwr, cmd, info, handler);
0958 }
0959 return -EOPNOTSUPP;
0960 }
0961
0962
0963
0964
0965 static int wext_permission_check(unsigned int cmd)
0966 {
0967 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE ||
0968 cmd == SIOCGIWENCODEEXT) &&
0969 !capable(CAP_NET_ADMIN))
0970 return -EPERM;
0971
0972 return 0;
0973 }
0974
0975
0976 static int wext_ioctl_dispatch(struct net *net, struct iwreq *iwr,
0977 unsigned int cmd, struct iw_request_info *info,
0978 wext_ioctl_func standard,
0979 wext_ioctl_func private)
0980 {
0981 int ret = wext_permission_check(cmd);
0982
0983 if (ret)
0984 return ret;
0985
0986 dev_load(net, iwr->ifr_name);
0987 rtnl_lock();
0988 ret = wireless_process_ioctl(net, iwr, cmd, info, standard, private);
0989 rtnl_unlock();
0990
0991 return ret;
0992 }
0993
0994
0995
0996
0997
0998
0999 static int ioctl_standard_call(struct net_device * dev,
1000 struct iwreq *iwr,
1001 unsigned int cmd,
1002 struct iw_request_info *info,
1003 iw_handler handler)
1004 {
1005 const struct iw_ioctl_description * descr;
1006 int ret = -EINVAL;
1007
1008
1009 if (IW_IOCTL_IDX(cmd) >= standard_ioctl_num)
1010 return -EOPNOTSUPP;
1011 descr = &(standard_ioctl[IW_IOCTL_IDX(cmd)]);
1012
1013
1014 if (descr->header_type != IW_HEADER_TYPE_POINT) {
1015
1016
1017 ret = handler(dev, info, &(iwr->u), NULL);
1018
1019
1020 if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
1021 ((ret == 0) || (ret == -EIWCOMMIT)))
1022 wireless_send_event(dev, cmd, &(iwr->u), NULL);
1023 } else {
1024 ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
1025 handler, dev, info);
1026 }
1027
1028
1029 if (ret == -EIWCOMMIT)
1030 ret = call_commit_handler(dev);
1031
1032
1033
1034 return ret;
1035 }
1036
1037
1038 int wext_handle_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1039 {
1040 struct iw_request_info info = { .cmd = cmd, .flags = 0 };
1041 struct iwreq iwr;
1042 int ret;
1043
1044 if (copy_from_user(&iwr, arg, sizeof(iwr)))
1045 return -EFAULT;
1046
1047 iwr.ifr_name[sizeof(iwr.ifr_name) - 1] = 0;
1048
1049 ret = wext_ioctl_dispatch(net, &iwr, cmd, &info,
1050 ioctl_standard_call,
1051 ioctl_private_call);
1052 if (ret >= 0 &&
1053 IW_IS_GET(cmd) &&
1054 copy_to_user(arg, &iwr, sizeof(struct iwreq)))
1055 return -EFAULT;
1056
1057 return ret;
1058 }
1059
1060 #ifdef CONFIG_COMPAT
1061 static int compat_standard_call(struct net_device *dev,
1062 struct iwreq *iwr,
1063 unsigned int cmd,
1064 struct iw_request_info *info,
1065 iw_handler handler)
1066 {
1067 const struct iw_ioctl_description *descr;
1068 struct compat_iw_point *iwp_compat;
1069 struct iw_point iwp;
1070 int err;
1071
1072 descr = standard_ioctl + IW_IOCTL_IDX(cmd);
1073
1074 if (descr->header_type != IW_HEADER_TYPE_POINT)
1075 return ioctl_standard_call(dev, iwr, cmd, info, handler);
1076
1077 iwp_compat = (struct compat_iw_point *) &iwr->u.data;
1078 iwp.pointer = compat_ptr(iwp_compat->pointer);
1079 iwp.length = iwp_compat->length;
1080 iwp.flags = iwp_compat->flags;
1081
1082 err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info);
1083
1084 iwp_compat->pointer = ptr_to_compat(iwp.pointer);
1085 iwp_compat->length = iwp.length;
1086 iwp_compat->flags = iwp.flags;
1087
1088 return err;
1089 }
1090
1091 int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1092 unsigned long arg)
1093 {
1094 void __user *argp = (void __user *)arg;
1095 struct iw_request_info info;
1096 struct iwreq iwr;
1097 char *colon;
1098 int ret;
1099
1100 if (copy_from_user(&iwr, argp, sizeof(struct iwreq)))
1101 return -EFAULT;
1102
1103 iwr.ifr_name[IFNAMSIZ-1] = 0;
1104 colon = strchr(iwr.ifr_name, ':');
1105 if (colon)
1106 *colon = 0;
1107
1108 info.cmd = cmd;
1109 info.flags = IW_REQUEST_FLAG_COMPAT;
1110
1111 ret = wext_ioctl_dispatch(net, &iwr, cmd, &info,
1112 compat_standard_call,
1113 compat_private_call);
1114
1115 if (ret >= 0 &&
1116 IW_IS_GET(cmd) &&
1117 copy_to_user(argp, &iwr, sizeof(struct iwreq)))
1118 return -EFAULT;
1119
1120 return ret;
1121 }
1122 #endif
1123
1124 char *iwe_stream_add_event(struct iw_request_info *info, char *stream,
1125 char *ends, struct iw_event *iwe, int event_len)
1126 {
1127 int lcp_len = iwe_stream_lcp_len(info);
1128
1129 event_len = iwe_stream_event_len_adjust(info, event_len);
1130
1131
1132 if (likely((stream + event_len) < ends)) {
1133 iwe->len = event_len;
1134
1135 memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
1136 memcpy(stream + lcp_len, &iwe->u,
1137 event_len - lcp_len);
1138 stream += event_len;
1139 }
1140
1141 return stream;
1142 }
1143 EXPORT_SYMBOL(iwe_stream_add_event);
1144
1145 char *iwe_stream_add_point(struct iw_request_info *info, char *stream,
1146 char *ends, struct iw_event *iwe, char *extra)
1147 {
1148 int event_len = iwe_stream_point_len(info) + iwe->u.data.length;
1149 int point_len = iwe_stream_point_len(info);
1150 int lcp_len = iwe_stream_lcp_len(info);
1151
1152
1153 if (likely((stream + event_len) < ends)) {
1154 iwe->len = event_len;
1155 memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN);
1156 memcpy(stream + lcp_len,
1157 ((char *) &iwe->u) + IW_EV_POINT_OFF,
1158 IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN);
1159 if (iwe->u.data.length && extra)
1160 memcpy(stream + point_len, extra, iwe->u.data.length);
1161 stream += event_len;
1162 }
1163
1164 return stream;
1165 }
1166 EXPORT_SYMBOL(iwe_stream_add_point);
1167
1168 char *iwe_stream_add_value(struct iw_request_info *info, char *event,
1169 char *value, char *ends, struct iw_event *iwe,
1170 int event_len)
1171 {
1172 int lcp_len = iwe_stream_lcp_len(info);
1173
1174
1175 event_len -= IW_EV_LCP_LEN;
1176
1177
1178 if (likely((value + event_len) < ends)) {
1179
1180 memcpy(value, &iwe->u, event_len);
1181 value += event_len;
1182
1183 iwe->len = value - event;
1184 memcpy(event, (char *) iwe, lcp_len);
1185 }
1186
1187 return value;
1188 }
1189 EXPORT_SYMBOL(iwe_stream_add_value);