diff options
Diffstat (limited to 'net/wireless/wext.c')
-rw-r--r-- | net/wireless/wext.c | 114 |
1 files changed, 57 insertions, 57 deletions
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index db8351a5a87d..ee35e6422f1f 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -1300,22 +1300,15 @@ static void wireless_nlevent_process(struct work_struct *work) | |||
1300 | 1300 | ||
1301 | static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); | 1301 | static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process); |
1302 | 1302 | ||
1303 | /* ---------------------------------------------------------------- */ | 1303 | static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev, |
1304 | /* | 1304 | struct sk_buff *skb) |
1305 | * Fill a rtnetlink message with our event data. | ||
1306 | * Note that we propage only the specified event and don't dump the | ||
1307 | * current wireless config. Dumping the wireless config is far too | ||
1308 | * expensive (for each parameter, the driver need to query the hardware). | ||
1309 | */ | ||
1310 | static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, | ||
1311 | int type, char *event, int event_len) | ||
1312 | { | 1305 | { |
1313 | struct ifinfomsg *r; | 1306 | struct ifinfomsg *r; |
1314 | struct nlmsghdr *nlh; | 1307 | struct nlmsghdr *nlh; |
1315 | 1308 | ||
1316 | nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); | 1309 | nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0); |
1317 | if (nlh == NULL) | 1310 | if (!nlh) |
1318 | return -EMSGSIZE; | 1311 | return NULL; |
1319 | 1312 | ||
1320 | r = nlmsg_data(nlh); | 1313 | r = nlmsg_data(nlh); |
1321 | r->ifi_family = AF_UNSPEC; | 1314 | r->ifi_family = AF_UNSPEC; |
@@ -1326,45 +1319,14 @@ static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, | |||
1326 | r->ifi_change = 0; /* Wireless changes don't affect those flags */ | 1319 | r->ifi_change = 0; /* Wireless changes don't affect those flags */ |
1327 | 1320 | ||
1328 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); | 1321 | NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); |
1329 | /* Add the wireless events in the netlink packet */ | ||
1330 | NLA_PUT(skb, IFLA_WIRELESS, event_len, event); | ||
1331 | |||
1332 | return nlmsg_end(skb, nlh); | ||
1333 | 1322 | ||
1334 | nla_put_failure: | 1323 | return nlh; |
1324 | nla_put_failure: | ||
1335 | nlmsg_cancel(skb, nlh); | 1325 | nlmsg_cancel(skb, nlh); |
1336 | return -EMSGSIZE; | 1326 | return NULL; |
1337 | } | 1327 | } |
1338 | 1328 | ||
1339 | /* ---------------------------------------------------------------- */ | ||
1340 | /* | ||
1341 | * Create and broadcast and send it on the standard rtnetlink socket | ||
1342 | * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c | ||
1343 | * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field | ||
1344 | * within a RTM_NEWLINK event. | ||
1345 | */ | ||
1346 | static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) | ||
1347 | { | ||
1348 | struct sk_buff *skb; | ||
1349 | int err; | ||
1350 | |||
1351 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
1352 | if (!skb) | ||
1353 | return; | ||
1354 | 1329 | ||
1355 | err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len); | ||
1356 | if (err < 0) { | ||
1357 | WARN_ON(err == -EMSGSIZE); | ||
1358 | kfree_skb(skb); | ||
1359 | return; | ||
1360 | } | ||
1361 | |||
1362 | NETLINK_CB(skb).dst_group = RTNLGRP_LINK; | ||
1363 | skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); | ||
1364 | schedule_work(&wireless_nlevent_work); | ||
1365 | } | ||
1366 | |||
1367 | /* ---------------------------------------------------------------- */ | ||
1368 | /* | 1330 | /* |
1369 | * Main event dispatcher. Called from other parts and drivers. | 1331 | * Main event dispatcher. Called from other parts and drivers. |
1370 | * Send the event on the appropriate channels. | 1332 | * Send the event on the appropriate channels. |
@@ -1383,6 +1345,9 @@ void wireless_send_event(struct net_device * dev, | |||
1383 | int wrqu_off = 0; /* Offset in wrqu */ | 1345 | int wrqu_off = 0; /* Offset in wrqu */ |
1384 | /* Don't "optimise" the following variable, it will crash */ | 1346 | /* Don't "optimise" the following variable, it will crash */ |
1385 | unsigned cmd_index; /* *MUST* be unsigned */ | 1347 | unsigned cmd_index; /* *MUST* be unsigned */ |
1348 | struct sk_buff *skb; | ||
1349 | struct nlmsghdr *nlh; | ||
1350 | struct nlattr *nla; | ||
1386 | 1351 | ||
1387 | /* Get the description of the Event */ | 1352 | /* Get the description of the Event */ |
1388 | if (cmd <= SIOCIWLAST) { | 1353 | if (cmd <= SIOCIWLAST) { |
@@ -1430,25 +1395,60 @@ void wireless_send_event(struct net_device * dev, | |||
1430 | hdr_len = event_type_size[descr->header_type]; | 1395 | hdr_len = event_type_size[descr->header_type]; |
1431 | event_len = hdr_len + extra_len; | 1396 | event_len = hdr_len + extra_len; |
1432 | 1397 | ||
1433 | /* Create temporary buffer to hold the event */ | 1398 | /* |
1434 | event = kmalloc(event_len, GFP_ATOMIC); | 1399 | * The problem for 64/32 bit. |
1435 | if (event == NULL) | 1400 | * |
1401 | * On 64-bit, a regular event is laid out as follows: | ||
1402 | * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | ||
1403 | * | event.len | event.cmd | p a d d i n g | | ||
1404 | * | wrqu data ... (with the correct size) | | ||
1405 | * | ||
1406 | * This padding exists because we manipulate event->u, | ||
1407 | * and 'event' is not packed. | ||
1408 | * | ||
1409 | * An iw_point event is laid out like this instead: | ||
1410 | * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | ||
1411 | * | event.len | event.cmd | p a d d i n g | | ||
1412 | * | iwpnt.len | iwpnt.flg | p a d d i n g | | ||
1413 | * | extra data ... | ||
1414 | * | ||
1415 | * The second padding exists because struct iw_point is extended, | ||
1416 | * but this depends on the platform... | ||
1417 | * | ||
1418 | * On 32-bit, all the padding shouldn't be there. | ||
1419 | */ | ||
1420 | |||
1421 | skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); | ||
1422 | if (!skb) | ||
1423 | return; | ||
1424 | |||
1425 | /* Send via the RtNetlink event channel */ | ||
1426 | nlh = rtnetlink_ifinfo_prep(dev, skb); | ||
1427 | if (WARN_ON(!nlh)) { | ||
1428 | kfree_skb(skb); | ||
1429 | return; | ||
1430 | } | ||
1431 | |||
1432 | /* Add the wireless events in the netlink packet */ | ||
1433 | nla = nla_reserve(skb, IFLA_WIRELESS, event_len); | ||
1434 | if (!nla) { | ||
1435 | kfree_skb(skb); | ||
1436 | return; | 1436 | return; |
1437 | } | ||
1438 | event = nla_data(nla); | ||
1437 | 1439 | ||
1438 | /* Fill event */ | 1440 | /* Fill event - first clear to avoid data leaking */ |
1441 | memset(event, 0, hdr_len); | ||
1439 | event->len = event_len; | 1442 | event->len = event_len; |
1440 | event->cmd = cmd; | 1443 | event->cmd = cmd; |
1441 | memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); | 1444 | memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); |
1442 | if (extra) | 1445 | if (extra_len) |
1443 | memcpy(((char *) event) + hdr_len, extra, extra_len); | 1446 | memcpy(((char *) event) + hdr_len, extra, extra_len); |
1444 | 1447 | ||
1445 | /* Send via the RtNetlink event channel */ | 1448 | nlmsg_end(skb, nlh); |
1446 | rtmsg_iwinfo(dev, (char *) event, event_len); | ||
1447 | |||
1448 | /* Cleanup */ | ||
1449 | kfree(event); | ||
1450 | 1449 | ||
1451 | return; /* Always success, I guess ;-) */ | 1450 | skb_queue_tail(&dev_net(dev)->wext_nlevents, skb); |
1451 | schedule_work(&wireless_nlevent_work); | ||
1452 | } | 1452 | } |
1453 | EXPORT_SYMBOL(wireless_send_event); | 1453 | EXPORT_SYMBOL(wireless_send_event); |
1454 | 1454 | ||