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.c257
1 files changed, 169 insertions, 88 deletions
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 252c2010c2e2..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
@@ -1250,65 +1272,57 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
1250} 1272}
1251#endif 1273#endif
1252 1274
1253/************************* EVENT PROCESSING *************************/ 1275static int __net_init wext_pernet_init(struct net *net)
1254/* 1276{
1255 * Process events generated by the wireless layer or the driver. 1277 skb_queue_head_init(&net->wext_nlevents);
1256 * Most often, the event will be propagated through rtnetlink 1278 return 0;
1257 */ 1279}
1258 1280
1259/* ---------------------------------------------------------------- */ 1281static void __net_exit wext_pernet_exit(struct net *net)
1260/* 1282{
1261 * Locking... 1283 skb_queue_purge(&net->wext_nlevents);
1262 * ---------- 1284}
1263 *
1264 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
1265 * the locking issue in here and implementing this code !
1266 *
1267 * The issue : wireless_send_event() is often called in interrupt context,
1268 * while the Netlink layer can never be called in interrupt context.
1269 * The fully formed RtNetlink events are queued, and then a tasklet is run
1270 * to feed those to Netlink.
1271 * The skb_queue is interrupt safe, and its lock is not held while calling
1272 * Netlink, so there is no possibility of dealock.
1273 * Jean II
1274 */
1275 1285
1276static 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};
1277 1290
1278static int __init wireless_nlevent_init(void) 1291static int __init wireless_nlevent_init(void)
1279{ 1292{
1280 skb_queue_head_init(&wireless_nlevent_queue); 1293 return register_pernet_subsys(&wext_pernet_ops);
1281 return 0;
1282} 1294}
1283 1295
1284subsys_initcall(wireless_nlevent_init); 1296subsys_initcall(wireless_nlevent_init);
1285 1297
1286static 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)
1287{ 1300{
1288 struct sk_buff *skb; 1301 struct sk_buff *skb;
1302 struct net *net;
1289 1303
1290 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1304 rtnl_lock();
1291 rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1305
1306 for_each_net(net) {
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();
1292} 1313}
1293 1314
1294static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1315static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
1295 1316
1296/* ---------------------------------------------------------------- */ 1317static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
1297/* 1318 struct sk_buff *skb)
1298 * Fill a rtnetlink message with our event data.
1299 * Note that we propage only the specified event and don't dump the
1300 * current wireless config. Dumping the wireless config is far too
1301 * expensive (for each parameter, the driver need to query the hardware).
1302 */
1303static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
1304 int type, char *event, int event_len)
1305{ 1319{
1306 struct ifinfomsg *r; 1320 struct ifinfomsg *r;
1307 struct nlmsghdr *nlh; 1321 struct nlmsghdr *nlh;
1308 1322
1309 nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); 1323 nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
1310 if (nlh == NULL) 1324 if (!nlh)
1311 return -EMSGSIZE; 1325 return NULL;
1312 1326
1313 r = nlmsg_data(nlh); 1327 r = nlmsg_data(nlh);
1314 r->ifi_family = AF_UNSPEC; 1328 r->ifi_family = AF_UNSPEC;
@@ -1319,48 +1333,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev,
1319 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1333 r->ifi_change = 0; /* Wireless changes don't affect those flags */
1320 1334
1321 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); 1335 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
1322 /* Add the wireless events in the netlink packet */
1323 NLA_PUT(skb, IFLA_WIRELESS, event_len, event);
1324 1336
1325 return nlmsg_end(skb, nlh); 1337 return nlh;
1326 1338 nla_put_failure:
1327nla_put_failure:
1328 nlmsg_cancel(skb, nlh); 1339 nlmsg_cancel(skb, nlh);
1329 return -EMSGSIZE; 1340 return NULL;
1330} 1341}
1331 1342
1332/* ---------------------------------------------------------------- */
1333/*
1334 * Create and broadcast and send it on the standard rtnetlink socket
1335 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
1336 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
1337 * within a RTM_NEWLINK event.
1338 */
1339static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
1340{
1341 struct sk_buff *skb;
1342 int err;
1343
1344 if (!net_eq(dev_net(dev), &init_net))
1345 return;
1346
1347 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
1348 if (!skb)
1349 return;
1350 1343
1351 err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len);
1352 if (err < 0) {
1353 WARN_ON(err == -EMSGSIZE);
1354 kfree_skb(skb);
1355 return;
1356 }
1357
1358 NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
1359 skb_queue_tail(&wireless_nlevent_queue, skb);
1360 tasklet_schedule(&wireless_nlevent_tasklet);
1361}
1362
1363/* ---------------------------------------------------------------- */
1364/* 1344/*
1365 * Main event dispatcher. Called from other parts and drivers. 1345 * Main event dispatcher. Called from other parts and drivers.
1366 * Send the event on the appropriate channels. 1346 * Send the event on the appropriate channels.
@@ -1369,7 +1349,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
1369void wireless_send_event(struct net_device * dev, 1349void wireless_send_event(struct net_device * dev,
1370 unsigned int cmd, 1350 unsigned int cmd,
1371 union iwreq_data * wrqu, 1351 union iwreq_data * wrqu,
1372 char * extra) 1352 const char * extra)
1373{ 1353{
1374 const struct iw_ioctl_description * descr = NULL; 1354 const struct iw_ioctl_description * descr = NULL;
1375 int extra_len = 0; 1355 int extra_len = 0;
@@ -1379,6 +1359,25 @@ void wireless_send_event(struct net_device * dev,
1379 int wrqu_off = 0; /* Offset in wrqu */ 1359 int wrqu_off = 0; /* Offset in wrqu */
1380 /* Don't "optimise" the following variable, it will crash */ 1360 /* Don't "optimise" the following variable, it will crash */
1381 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;
1382 1381
1383 /* Get the description of the Event */ 1382 /* Get the description of the Event */
1384 if (cmd <= SIOCIWLAST) { 1383 if (cmd <= SIOCIWLAST) {
@@ -1426,25 +1425,107 @@ void wireless_send_event(struct net_device * dev,
1426 hdr_len = event_type_size[descr->header_type]; 1425 hdr_len = event_type_size[descr->header_type];
1427 event_len = hdr_len + extra_len; 1426 event_len = hdr_len + extra_len;
1428 1427
1429 /* Create temporary buffer to hold the event */ 1428 /*
1430 event = kmalloc(event_len, GFP_ATOMIC); 1429 * The problem for 64/32 bit.
1431 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)
1453 return;
1454
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);
1432 return; 1466 return;
1467 }
1468 event = nla_data(nla);
1433 1469
1434 /* Fill event */ 1470 /* Fill event - first clear to avoid data leaking */
1471 memset(event, 0, hdr_len);
1435 event->len = event_len; 1472 event->len = event_len;
1436 event->cmd = cmd; 1473 event->cmd = cmd;
1437 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);
1438 if (extra) 1475 if (extra_len)
1439 memcpy(((char *) event) + hdr_len, extra, extra_len); 1476 memcpy(((char *) event) + hdr_len, extra, extra_len);
1440 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
1441 /* Send via the RtNetlink event channel */ 1489 /* Send via the RtNetlink event channel */
1442 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 }
1443 1496
1444 /* Cleanup */ 1497 /* Add the wireless events in the netlink packet */
1445 kfree(event); 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);
1446 1505
1447 return; /* Always success, I guess ;-) */ 1506 compat_event->len = event_len;
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);
1524
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);
1448} 1529}
1449EXPORT_SYMBOL(wireless_send_event); 1530EXPORT_SYMBOL(wireless_send_event);
1450 1531