aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/wext.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/wext.c')
-rw-r--r--net/wireless/wext.c312
1 files changed, 217 insertions, 95 deletions
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index cb6a5bb85d80..5b4a0cee4418 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -417,6 +417,21 @@ static const int event_type_size[] = {
417 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 417 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
418}; 418};
419 419
420#ifdef CONFIG_COMPAT
421static const int compat_event_type_size[] = {
422 IW_EV_COMPAT_LCP_LEN, /* IW_HEADER_TYPE_NULL */
423 0,
424 IW_EV_COMPAT_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */
425 0,
426 IW_EV_COMPAT_UINT_LEN, /* IW_HEADER_TYPE_UINT */
427 IW_EV_COMPAT_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */
428 IW_EV_COMPAT_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */
429 0,
430 IW_EV_COMPAT_POINT_LEN, /* Without variable payload */
431 IW_EV_COMPAT_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */
432 IW_EV_COMPAT_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */
433};
434#endif
420 435
421/************************ COMMON SUBROUTINES ************************/ 436/************************ COMMON SUBROUTINES ************************/
422/* 437/*
@@ -610,6 +625,11 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
610{ 625{
611 /* Get stats from the driver */ 626 /* Get stats from the driver */
612 struct iw_statistics *stats = get_wireless_stats(dev); 627 struct iw_statistics *stats = get_wireless_stats(dev);
628 static struct iw_statistics nullstats = {};
629
630 /* show device if it's wireless regardless of current stats */
631 if (!stats && dev->wireless_handlers)
632 stats = &nullstats;
613 633
614 if (stats) { 634 if (stats) {
615 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 635 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
@@ -628,7 +648,9 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
628 stats->discard.nwid, stats->discard.code, 648 stats->discard.nwid, stats->discard.code,
629 stats->discard.fragment, stats->discard.retries, 649 stats->discard.fragment, stats->discard.retries,
630 stats->discard.misc, stats->miss.beacon); 650 stats->discard.misc, stats->miss.beacon);
631 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 651
652 if (stats != &nullstats)
653 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
632 } 654 }
633} 655}
634 656
@@ -636,8 +658,10 @@ static void wireless_seq_printf_stats(struct seq_file *seq,
636/* 658/*
637 * Print info for /proc/net/wireless (print all entries) 659 * Print info for /proc/net/wireless (print all entries)
638 */ 660 */
639static int wireless_seq_show(struct seq_file *seq, void *v) 661static int wireless_dev_seq_show(struct seq_file *seq, void *v)
640{ 662{
663 might_sleep();
664
641 if (v == SEQ_START_TOKEN) 665 if (v == SEQ_START_TOKEN)
642 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 666 seq_printf(seq, "Inter-| sta-| Quality | Discarded "
643 "packets | Missed | WE\n" 667 "packets | Missed | WE\n"
@@ -649,14 +673,46 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
649 return 0; 673 return 0;
650} 674}
651 675
676static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
677{
678 struct net *net = seq_file_net(seq);
679 loff_t off;
680 struct net_device *dev;
681
682 rtnl_lock();
683 if (!*pos)
684 return SEQ_START_TOKEN;
685
686 off = 1;
687 for_each_netdev(net, dev)
688 if (off++ == *pos)
689 return dev;
690 return NULL;
691}
692
693static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
694{
695 struct net *net = seq_file_net(seq);
696
697 ++*pos;
698
699 return v == SEQ_START_TOKEN ?
700 first_net_device(net) : next_net_device(v);
701}
702
703static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
704{
705 rtnl_unlock();
706}
707
652static const struct seq_operations wireless_seq_ops = { 708static const struct seq_operations wireless_seq_ops = {
653 .start = dev_seq_start, 709 .start = wireless_dev_seq_start,
654 .next = dev_seq_next, 710 .next = wireless_dev_seq_next,
655 .stop = dev_seq_stop, 711 .stop = wireless_dev_seq_stop,
656 .show = wireless_seq_show, 712 .show = wireless_dev_seq_show,
657}; 713};
658 714
659static int wireless_seq_open(struct inode *inode, struct file *file) 715static int seq_open_wireless(struct inode *inode, struct file *file)
660{ 716{
661 return seq_open_net(inode, file, &wireless_seq_ops, 717 return seq_open_net(inode, file, &wireless_seq_ops,
662 sizeof(struct seq_net_private)); 718 sizeof(struct seq_net_private));
@@ -664,7 +720,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file)
664 720
665static const struct file_operations wireless_seq_fops = { 721static const struct file_operations wireless_seq_fops = {
666 .owner = THIS_MODULE, 722 .owner = THIS_MODULE,
667 .open = wireless_seq_open, 723 .open = seq_open_wireless,
668 .read = seq_read, 724 .read = seq_read,
669 .llseek = seq_lseek, 725 .llseek = seq_lseek,
670 .release = seq_release_net, 726 .release = seq_release_net,
@@ -786,6 +842,13 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
786 err = -EFAULT; 842 err = -EFAULT;
787 goto out; 843 goto out;
788 } 844 }
845
846 if (cmd == SIOCSIWENCODEEXT) {
847 struct iw_encode_ext *ee = (void *) extra;
848
849 if (iwp->length < sizeof(*ee) + ee->key_len)
850 return -EFAULT;
851 }
789 } 852 }
790 853
791 err = handler(dev, info, (union iwreq_data *) iwp, extra); 854 err = handler(dev, info, (union iwreq_data *) iwp, extra);
@@ -1209,65 +1272,57 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1209} 1272}
1210#endif 1273#endif
1211 1274
1212/************************* EVENT PROCESSING *************************/ 1275static int __net_init wext_pernet_init(struct net *net)
1213/* 1276{
1214 * Process events generated by the wireless layer or the driver. 1277 skb_queue_head_init(&net->wext_nlevents);
1215 * Most often, the event will be propagated through rtnetlink 1278 return 0;
1216 */ 1279}
1217 1280
1218/* ---------------------------------------------------------------- */ 1281static void __net_exit wext_pernet_exit(struct net *net)
1219/* 1282{
1220 * Locking... 1283 skb_queue_purge(&net->wext_nlevents);
1221 * ---------- 1284}
1222 *
1223 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
1224 * the locking issue in here and implementing this code !
1225 *
1226 * The issue : wireless_send_event() is often called in interrupt context,
1227 * while the Netlink layer can never be called in interrupt context.
1228 * The fully formed RtNetlink events are queued, and then a tasklet is run
1229 * to feed those to Netlink.
1230 * The skb_queue is interrupt safe, and its lock is not held while calling
1231 * Netlink, so there is no possibility of dealock.
1232 * Jean II
1233 */
1234 1285
1235static struct sk_buff_head wireless_nlevent_queue; 1286static struct pernet_operations wext_pernet_ops = {
1287 .init = wext_pernet_init,
1288 .exit = wext_pernet_exit,
1289};
1236 1290
1237static int __init wireless_nlevent_init(void) 1291static int __init wireless_nlevent_init(void)
1238{ 1292{
1239 skb_queue_head_init(&wireless_nlevent_queue); 1293 return register_pernet_subsys(&wext_pernet_ops);
1240 return 0;
1241} 1294}
1242 1295
1243subsys_initcall(wireless_nlevent_init); 1296subsys_initcall(wireless_nlevent_init);
1244 1297
1245static void wireless_nlevent_process(unsigned long data) 1298/* Process events generated by the wireless layer or the driver. */
1299static void wireless_nlevent_process(struct work_struct *work)
1246{ 1300{
1247 struct sk_buff *skb; 1301 struct sk_buff *skb;
1302 struct net *net;
1303
1304 rtnl_lock();
1248 1305
1249 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1306 for_each_net(net) {
1250 rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1307 while ((skb = skb_dequeue(&net->wext_nlevents)))
1308 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
1309 GFP_KERNEL);
1310 }
1311
1312 rtnl_unlock();
1251} 1313}
1252 1314
1253static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1315static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
1254 1316
1255/* ---------------------------------------------------------------- */ 1317static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
1256/* 1318 struct sk_buff *skb)
1257 * Fill a rtnetlink message with our event data.
1258 * Note that we propage only the specified event and don't dump the
1259 * current wireless config. Dumping the wireless config is far too
1260 * expensive (for each parameter, the driver need to query the hardware).
1261 */
1262static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
1263 int type, char *event, int event_len)
1264{ 1319{
1265 struct ifinfomsg *r; 1320 struct ifinfomsg *r;
1266 struct nlmsghdr *nlh; 1321 struct nlmsghdr *nlh;
1267 1322
1268 nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); 1323 nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
1269 if (nlh == NULL) 1324 if (!nlh)
1270 return -EMSGSIZE; 1325 return NULL;
1271 1326
1272 r = nlmsg_data(nlh); 1327 r = nlmsg_data(nlh);
1273 r->ifi_family = AF_UNSPEC; 1328 r->ifi_family = AF_UNSPEC;
@@ -1278,48 +1333,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
1278 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1333 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1279 1334
1280 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); 1335 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
1281 /* Add the wireless events in the netlink packet */
1282 NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
1283 1336
1284 return nlmsg_end(skb, nlh); 1337 return nlh;
1285 1338 nla_put_failure:
1286nla_put_failure:
1287 nlmsg_cancel(skb, nlh); 1339 nlmsg_cancel(skb, nlh);
1288 return -EMSGSIZE; 1340 return NULL;
1289} 1341}
1290 1342
1291/* ---------------------------------------------------------------- */
1292/*
1293 * Create and broadcast and send it on the standard rtnetlink socket
1294 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
1295 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
1296 * within a RTM_NEWLINK event.
1297 */
1298static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
1299{
1300 struct sk_buff *skb;
1301 int err;
1302
1303 if (!net_eq(dev_net(dev), &init_net))
1304 return;
1305
1306 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1307 if (!skb)
1308 return;
1309
1310 err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
1311 if (err < 0) {
1312 WARN_ON(err == -EMSGSIZE);
1313 kfree_skb(skb);
1314 return;
1315 }
1316 1343
1317 NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1318 skb_queue_tail(&wireless_nlevent_queue, skb);
1319 tasklet_schedule(&wireless_nlevent_tasklet);
1320}
1321
1322/* ---------------------------------------------------------------- */
1323/* 1344/*
1324 * Main event dispatcher. Called from other parts and drivers. 1345 * Main event dispatcher. Called from other parts and drivers.
1325 * Send the event on the appropriate channels. 1346 * Send the event on the appropriate channels.
@@ -1328,7 +1349,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
1328void wireless_send_event(struct net_device * dev, 1349void wireless_send_event(struct net_device * dev,
1329 unsigned int cmd, 1350 unsigned int cmd,
1330 union iwreq_data * wrqu, 1351 union iwreq_data * wrqu,
1331 char * extra) 1352 const char * extra)
1332{ 1353{
1333 const struct iw_ioctl_description * descr = NULL; 1354 const struct iw_ioctl_description * descr = NULL;
1334 int extra_len = 0; 1355 int extra_len = 0;
@@ -1338,6 +1359,25 @@ void wireless_send_event(struct net_device * dev,
1338 int wrqu_off = 0; /* Offset in wrqu */ 1359 int wrqu_off = 0; /* Offset in wrqu */
1339 /* Don't "optimise" the following variable, it will crash */ 1360 /* Don't "optimise" the following variable, it will crash */
1340 unsigned cmd_index; /* *MUST* be unsigned */ 1361 unsigned cmd_index; /* *MUST* be unsigned */
1362 struct sk_buff *skb;
1363 struct nlmsghdr *nlh;
1364 struct nlattr *nla;
1365#ifdef CONFIG_COMPAT
1366 struct __compat_iw_event *compat_event;
1367 struct compat_iw_point compat_wrqu;
1368 struct sk_buff *compskb;
1369#endif
1370
1371 /*
1372 * Nothing in the kernel sends scan events with data, be safe.
1373 * This is necessary because we cannot fix up scan event data
1374 * for compat, due to being contained in 'extra', but normally
1375 * applications are required to retrieve the scan data anyway
1376 * and no data is included in the event, this codifies that
1377 * practice.
1378 */
1379 if (WARN_ON(cmd == SIOCGIWSCAN && extra))
1380 extra = NULL;
1341 1381
1342 /* Get the description of the Event */ 1382 /* Get the description of the Event */
1343 if (cmd <= SIOCIWLAST) { 1383 if (cmd <= SIOCIWLAST) {
@@ -1385,25 +1425,107 @@ void wireless_send_event(struct net_device * dev,
1385 hdr_len = event_type_size[descr->header_type]; 1425 hdr_len = event_type_size[descr->header_type];
1386 event_len = hdr_len + extra_len; 1426 event_len = hdr_len + extra_len;
1387 1427
1388 /* Create temporary buffer to hold the event */ 1428 /*
1389 event = kmalloc(event_len, GFP_ATOMIC); 1429 * The problem for 64/32 bit.
1390 if (event == NULL) 1430 *
1431 * On 64-bit, a regular event is laid out as follows:
1432 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1433 * | event.len | event.cmd | p a d d i n g |
1434 * | wrqu data ... (with the correct size) |
1435 *
1436 * This padding exists because we manipulate event->u,
1437 * and 'event' is not packed.
1438 *
1439 * An iw_point event is laid out like this instead:
1440 * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1441 * | event.len | event.cmd | p a d d i n g |
1442 * | iwpnt.len | iwpnt.flg | p a d d i n g |
1443 * | extra data ...
1444 *
1445 * The second padding exists because struct iw_point is extended,
1446 * but this depends on the platform...
1447 *
1448 * On 32-bit, all the padding shouldn't be there.
1449 */
1450
1451 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1452 if (!skb)
1391 return; 1453 return;
1392 1454
1393 /* Fill event */ 1455 /* Send via the RtNetlink event channel */
1456 nlh = rtnetlink_ifinfo_prep(dev, skb);
1457 if (WARN_ON(!nlh)) {
1458 kfree_skb(skb);
1459 return;
1460 }
1461
1462 /* Add the wireless events in the netlink packet */
1463 nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
1464 if (!nla) {
1465 kfree_skb(skb);
1466 return;
1467 }
1468 event = nla_data(nla);
1469
1470 /* Fill event - first clear to avoid data leaking */
1471 memset(event, 0, hdr_len);
1394 event->len = event_len; 1472 event->len = event_len;
1395 event->cmd = cmd; 1473 event->cmd = cmd;
1396 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 1474 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
1397 if (extra) 1475 if (extra_len)
1398 memcpy(((char *) event) + hdr_len, extra, extra_len); 1476 memcpy(((char *) event) + hdr_len, extra, extra_len);
1399 1477
1478 nlmsg_end(skb, nlh);
1479#ifdef CONFIG_COMPAT
1480 hdr_len = compat_event_type_size[descr->header_type];
1481 event_len = hdr_len + extra_len;
1482
1483 compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1484 if (!compskb) {
1485 kfree_skb(skb);
1486 return;
1487 }
1488
1400 /* Send via the RtNetlink event channel */ 1489 /* Send via the RtNetlink event channel */
1401 rtmsg_iwinfo(dev, (char *) event, event_len); 1490 nlh = rtnetlink_ifinfo_prep(dev, compskb);
1491 if (WARN_ON(!nlh)) {
1492 kfree_skb(skb);
1493 kfree_skb(compskb);
1494 return;
1495 }
1496
1497 /* Add the wireless events in the netlink packet */
1498 nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
1499 if (!nla) {
1500 kfree_skb(skb);
1501 kfree_skb(compskb);
1502 return;
1503 }
1504 compat_event = nla_data(nla);
1402 1505
1403 /* Cleanup */ 1506 compat_event->len = event_len;
1404 kfree(event); 1507 compat_event->cmd = cmd;
1508 if (descr->header_type == IW_HEADER_TYPE_POINT) {
1509 compat_wrqu.length = wrqu->data.length;
1510 compat_wrqu.flags = wrqu->data.flags;
1511 memcpy(&compat_event->pointer,
1512 ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
1513 hdr_len - IW_EV_COMPAT_LCP_LEN);
1514 if (extra_len)
1515 memcpy(((char *) compat_event) + hdr_len,
1516 extra, extra_len);
1517 } else {
1518 /* extra_len must be zero, so no if (extra) needed */
1519 memcpy(&compat_event->pointer, wrqu,
1520 hdr_len - IW_EV_COMPAT_LCP_LEN);
1521 }
1522
1523 nlmsg_end(compskb, nlh);
1405 1524
1406 return; /* Always success, I guess ;-) */ 1525 skb_shinfo(skb)->frag_list = compskb;
1526#endif
1527 skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
1528 schedule_work(&wireless_nlevent_work);
1407} 1529}
1408EXPORT_SYMBOL(wireless_send_event); 1530EXPORT_SYMBOL(wireless_send_event);
1409 1531