diff options
Diffstat (limited to 'drivers/net/wireless/mac80211_hwsim.c')
-rw-r--r-- | drivers/net/wireless/mac80211_hwsim.c | 462 |
1 files changed, 447 insertions, 15 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9d4a40ee16c4..7e1fa9671277 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 | 2 | * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 |
3 | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> | 3 | * Copyright (c) 2008, Jouni Malinen <j@w1.fi> |
4 | * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> | ||
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
@@ -25,11 +26,17 @@ | |||
25 | #include <linux/rtnetlink.h> | 26 | #include <linux/rtnetlink.h> |
26 | #include <linux/etherdevice.h> | 27 | #include <linux/etherdevice.h> |
27 | #include <linux/debugfs.h> | 28 | #include <linux/debugfs.h> |
29 | #include <net/genetlink.h> | ||
30 | #include "mac80211_hwsim.h" | ||
31 | |||
32 | #define WARN_QUEUE 100 | ||
33 | #define MAX_QUEUE 200 | ||
28 | 34 | ||
29 | MODULE_AUTHOR("Jouni Malinen"); | 35 | MODULE_AUTHOR("Jouni Malinen"); |
30 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); | 36 | MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); |
31 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
32 | 38 | ||
39 | int wmediumd_pid; | ||
33 | static int radios = 2; | 40 | static int radios = 2; |
34 | module_param(radios, int, 0444); | 41 | module_param(radios, int, 0444); |
35 | MODULE_PARM_DESC(radios, "Number of simulated radios"); | 42 | MODULE_PARM_DESC(radios, "Number of simulated radios"); |
@@ -302,6 +309,7 @@ struct mac80211_hwsim_data { | |||
302 | struct dentry *debugfs; | 309 | struct dentry *debugfs; |
303 | struct dentry *debugfs_ps; | 310 | struct dentry *debugfs_ps; |
304 | 311 | ||
312 | struct sk_buff_head pending; /* packets pending */ | ||
305 | /* | 313 | /* |
306 | * Only radios in the same group can communicate together (the | 314 | * Only radios in the same group can communicate together (the |
307 | * channel has to match too). Each bit represents a group. A | 315 | * channel has to match too). Each bit represents a group. A |
@@ -322,6 +330,32 @@ struct hwsim_radiotap_hdr { | |||
322 | __le16 rt_chbitmask; | 330 | __le16 rt_chbitmask; |
323 | } __packed; | 331 | } __packed; |
324 | 332 | ||
333 | /* MAC80211_HWSIM netlinf family */ | ||
334 | static struct genl_family hwsim_genl_family = { | ||
335 | .id = GENL_ID_GENERATE, | ||
336 | .hdrsize = 0, | ||
337 | .name = "MAC80211_HWSIM", | ||
338 | .version = 1, | ||
339 | .maxattr = HWSIM_ATTR_MAX, | ||
340 | }; | ||
341 | |||
342 | /* MAC80211_HWSIM netlink policy */ | ||
343 | |||
344 | static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { | ||
345 | [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, | ||
346 | .len = 6*sizeof(u8) }, | ||
347 | [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, | ||
348 | .len = 6*sizeof(u8) }, | ||
349 | [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, | ||
350 | .len = IEEE80211_MAX_DATA_LEN }, | ||
351 | [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, | ||
352 | [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, | ||
353 | [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, | ||
354 | [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC, | ||
355 | .len = IEEE80211_TX_MAX_RATES*sizeof( | ||
356 | struct hwsim_tx_rate)}, | ||
357 | [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, | ||
358 | }; | ||
325 | 359 | ||
326 | static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, | 360 | static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, |
327 | struct net_device *dev) | 361 | struct net_device *dev) |
@@ -478,9 +512,89 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data, | |||
478 | return md.ret; | 512 | return md.ret; |
479 | } | 513 | } |
480 | 514 | ||
515 | static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, | ||
516 | struct sk_buff *my_skb, | ||
517 | int dst_pid) | ||
518 | { | ||
519 | struct sk_buff *skb; | ||
520 | struct mac80211_hwsim_data *data = hw->priv; | ||
521 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; | ||
522 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); | ||
523 | void *msg_head; | ||
524 | unsigned int hwsim_flags = 0; | ||
525 | int i; | ||
526 | struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; | ||
527 | |||
528 | if (data->idle) { | ||
529 | wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); | ||
530 | dev_kfree_skb(my_skb); | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | if (data->ps != PS_DISABLED) | ||
535 | hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); | ||
536 | /* If the queue contains MAX_QUEUE skb's drop some */ | ||
537 | if (skb_queue_len(&data->pending) >= MAX_QUEUE) { | ||
538 | /* Droping until WARN_QUEUE level */ | ||
539 | while (skb_queue_len(&data->pending) >= WARN_QUEUE) | ||
540 | skb_dequeue(&data->pending); | ||
541 | } | ||
542 | |||
543 | skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
544 | if (skb == NULL) | ||
545 | goto nla_put_failure; | ||
546 | |||
547 | msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, | ||
548 | HWSIM_CMD_FRAME); | ||
549 | if (msg_head == NULL) { | ||
550 | printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head\n"); | ||
551 | goto nla_put_failure; | ||
552 | } | ||
553 | |||
554 | NLA_PUT(skb, HWSIM_ATTR_ADDR_TRANSMITTER, | ||
555 | sizeof(struct mac_address), data->addresses[1].addr); | ||
481 | 556 | ||
482 | static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | 557 | /* We get the skb->data */ |
483 | struct sk_buff *skb) | 558 | NLA_PUT(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data); |
559 | |||
560 | /* We get the flags for this transmission, and we translate them to | ||
561 | wmediumd flags */ | ||
562 | |||
563 | if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) | ||
564 | hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; | ||
565 | |||
566 | if (info->flags & IEEE80211_TX_CTL_NO_ACK) | ||
567 | hwsim_flags |= HWSIM_TX_CTL_NO_ACK; | ||
568 | |||
569 | NLA_PUT_U32(skb, HWSIM_ATTR_FLAGS, hwsim_flags); | ||
570 | |||
571 | /* We get the tx control (rate and retries) info*/ | ||
572 | |||
573 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
574 | tx_attempts[i].idx = info->status.rates[i].idx; | ||
575 | tx_attempts[i].count = info->status.rates[i].count; | ||
576 | } | ||
577 | |||
578 | NLA_PUT(skb, HWSIM_ATTR_TX_INFO, | ||
579 | sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, | ||
580 | tx_attempts); | ||
581 | |||
582 | /* We create a cookie to identify this skb */ | ||
583 | NLA_PUT_U64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb); | ||
584 | |||
585 | genlmsg_end(skb, msg_head); | ||
586 | genlmsg_unicast(&init_net, skb, dst_pid); | ||
587 | |||
588 | /* Enqueue the packet */ | ||
589 | skb_queue_tail(&data->pending, my_skb); | ||
590 | return; | ||
591 | |||
592 | nla_put_failure: | ||
593 | printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); | ||
594 | } | ||
595 | |||
596 | static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, | ||
597 | struct sk_buff *skb) | ||
484 | { | 598 | { |
485 | struct mac80211_hwsim_data *data = hw->priv, *data2; | 599 | struct mac80211_hwsim_data *data = hw->priv, *data2; |
486 | bool ack = false; | 600 | bool ack = false; |
@@ -540,11 +654,11 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, | |||
540 | return ack; | 654 | return ack; |
541 | } | 655 | } |
542 | 656 | ||
543 | |||
544 | static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | 657 | static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) |
545 | { | 658 | { |
546 | bool ack; | 659 | bool ack; |
547 | struct ieee80211_tx_info *txi; | 660 | struct ieee80211_tx_info *txi; |
661 | int _pid; | ||
548 | 662 | ||
549 | mac80211_hwsim_monitor_rx(hw, skb); | 663 | mac80211_hwsim_monitor_rx(hw, skb); |
550 | 664 | ||
@@ -554,7 +668,15 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
554 | return; | 668 | return; |
555 | } | 669 | } |
556 | 670 | ||
557 | ack = mac80211_hwsim_tx_frame(hw, skb); | 671 | /* wmediumd mode check */ |
672 | _pid = wmediumd_pid; | ||
673 | |||
674 | if (_pid) | ||
675 | return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); | ||
676 | |||
677 | /* NO wmediumd detected, perfect medium simulation */ | ||
678 | ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); | ||
679 | |||
558 | if (ack && skb->len >= 16) { | 680 | if (ack && skb->len >= 16) { |
559 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | 681 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; |
560 | mac80211_hwsim_monitor_ack(hw, hdr->addr2); | 682 | mac80211_hwsim_monitor_ack(hw, hdr->addr2); |
@@ -635,6 +757,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
635 | struct ieee80211_hw *hw = arg; | 757 | struct ieee80211_hw *hw = arg; |
636 | struct sk_buff *skb; | 758 | struct sk_buff *skb; |
637 | struct ieee80211_tx_info *info; | 759 | struct ieee80211_tx_info *info; |
760 | int _pid; | ||
638 | 761 | ||
639 | hwsim_check_magic(vif); | 762 | hwsim_check_magic(vif); |
640 | 763 | ||
@@ -649,7 +772,14 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, | |||
649 | info = IEEE80211_SKB_CB(skb); | 772 | info = IEEE80211_SKB_CB(skb); |
650 | 773 | ||
651 | mac80211_hwsim_monitor_rx(hw, skb); | 774 | mac80211_hwsim_monitor_rx(hw, skb); |
652 | mac80211_hwsim_tx_frame(hw, skb); | 775 | |
776 | /* wmediumd mode check */ | ||
777 | _pid = wmediumd_pid; | ||
778 | |||
779 | if (_pid) | ||
780 | return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); | ||
781 | |||
782 | mac80211_hwsim_tx_frame_no_nl(hw, skb); | ||
653 | dev_kfree_skb(skb); | 783 | dev_kfree_skb(skb); |
654 | } | 784 | } |
655 | 785 | ||
@@ -966,12 +1096,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, | |||
966 | 1096 | ||
967 | static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | 1097 | static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) |
968 | { | 1098 | { |
969 | /* | 1099 | /* Not implemented, queues only on kernel side */ |
970 | * In this special case, there's nothing we need to | ||
971 | * do because hwsim does transmission synchronously. | ||
972 | * In the future, when it does transmissions via | ||
973 | * userspace, we may need to do something. | ||
974 | */ | ||
975 | } | 1100 | } |
976 | 1101 | ||
977 | struct hw_scan_done { | 1102 | struct hw_scan_done { |
@@ -1119,6 +1244,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1119 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1244 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1120 | struct sk_buff *skb; | 1245 | struct sk_buff *skb; |
1121 | struct ieee80211_pspoll *pspoll; | 1246 | struct ieee80211_pspoll *pspoll; |
1247 | int _pid; | ||
1122 | 1248 | ||
1123 | if (!vp->assoc) | 1249 | if (!vp->assoc) |
1124 | return; | 1250 | return; |
@@ -1137,8 +1263,15 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) | |||
1137 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); | 1263 | pspoll->aid = cpu_to_le16(0xc000 | vp->aid); |
1138 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); | 1264 | memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); |
1139 | memcpy(pspoll->ta, mac, ETH_ALEN); | 1265 | memcpy(pspoll->ta, mac, ETH_ALEN); |
1140 | if (!mac80211_hwsim_tx_frame(data->hw, skb)) | 1266 | |
1141 | printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); | 1267 | /* wmediumd mode check */ |
1268 | _pid = wmediumd_pid; | ||
1269 | |||
1270 | if (_pid) | ||
1271 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); | ||
1272 | |||
1273 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1274 | printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); | ||
1142 | dev_kfree_skb(skb); | 1275 | dev_kfree_skb(skb); |
1143 | } | 1276 | } |
1144 | 1277 | ||
@@ -1149,6 +1282,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | |||
1149 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; | 1282 | struct hwsim_vif_priv *vp = (void *)vif->drv_priv; |
1150 | struct sk_buff *skb; | 1283 | struct sk_buff *skb; |
1151 | struct ieee80211_hdr *hdr; | 1284 | struct ieee80211_hdr *hdr; |
1285 | int _pid; | ||
1152 | 1286 | ||
1153 | if (!vp->assoc) | 1287 | if (!vp->assoc) |
1154 | return; | 1288 | return; |
@@ -1168,7 +1302,14 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, | |||
1168 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); | 1302 | memcpy(hdr->addr1, vp->bssid, ETH_ALEN); |
1169 | memcpy(hdr->addr2, mac, ETH_ALEN); | 1303 | memcpy(hdr->addr2, mac, ETH_ALEN); |
1170 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); | 1304 | memcpy(hdr->addr3, vp->bssid, ETH_ALEN); |
1171 | if (!mac80211_hwsim_tx_frame(data->hw, skb)) | 1305 | |
1306 | /* wmediumd mode check */ | ||
1307 | _pid = wmediumd_pid; | ||
1308 | |||
1309 | if (_pid) | ||
1310 | return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); | ||
1311 | |||
1312 | if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) | ||
1172 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); | 1313 | printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); |
1173 | dev_kfree_skb(skb); | 1314 | dev_kfree_skb(skb); |
1174 | } | 1315 | } |
@@ -1248,6 +1389,273 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group, | |||
1248 | hwsim_fops_group_read, hwsim_fops_group_write, | 1389 | hwsim_fops_group_read, hwsim_fops_group_write, |
1249 | "%llx\n"); | 1390 | "%llx\n"); |
1250 | 1391 | ||
1392 | struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( | ||
1393 | struct mac_address *addr) | ||
1394 | { | ||
1395 | struct mac80211_hwsim_data *data; | ||
1396 | bool _found = false; | ||
1397 | |||
1398 | spin_lock_bh(&hwsim_radio_lock); | ||
1399 | list_for_each_entry(data, &hwsim_radios, list) { | ||
1400 | if (memcmp(data->addresses[1].addr, addr, | ||
1401 | sizeof(struct mac_address)) == 0) { | ||
1402 | _found = true; | ||
1403 | break; | ||
1404 | } | ||
1405 | } | ||
1406 | spin_unlock_bh(&hwsim_radio_lock); | ||
1407 | |||
1408 | if (!_found) | ||
1409 | return NULL; | ||
1410 | |||
1411 | return data; | ||
1412 | } | ||
1413 | |||
1414 | static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, | ||
1415 | struct genl_info *info) | ||
1416 | { | ||
1417 | |||
1418 | struct ieee80211_hdr *hdr; | ||
1419 | struct mac80211_hwsim_data *data2; | ||
1420 | struct ieee80211_tx_info *txi; | ||
1421 | struct hwsim_tx_rate *tx_attempts; | ||
1422 | struct sk_buff __user *ret_skb; | ||
1423 | struct sk_buff *skb, *tmp; | ||
1424 | struct mac_address *src; | ||
1425 | unsigned int hwsim_flags; | ||
1426 | |||
1427 | int i; | ||
1428 | bool found = false; | ||
1429 | |||
1430 | if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || | ||
1431 | !info->attrs[HWSIM_ATTR_FLAGS] || | ||
1432 | !info->attrs[HWSIM_ATTR_COOKIE] || | ||
1433 | !info->attrs[HWSIM_ATTR_TX_INFO]) | ||
1434 | goto out; | ||
1435 | |||
1436 | src = (struct mac_address *)nla_data( | ||
1437 | info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); | ||
1438 | hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); | ||
1439 | |||
1440 | ret_skb = (struct sk_buff __user *) | ||
1441 | (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); | ||
1442 | |||
1443 | data2 = get_hwsim_data_ref_from_addr(src); | ||
1444 | |||
1445 | if (data2 == NULL) | ||
1446 | goto out; | ||
1447 | |||
1448 | /* look for the skb matching the cookie passed back from user */ | ||
1449 | skb_queue_walk_safe(&data2->pending, skb, tmp) { | ||
1450 | if (skb == ret_skb) { | ||
1451 | skb_unlink(skb, &data2->pending); | ||
1452 | found = true; | ||
1453 | break; | ||
1454 | } | ||
1455 | } | ||
1456 | |||
1457 | /* not found */ | ||
1458 | if (!found) | ||
1459 | goto out; | ||
1460 | |||
1461 | /* Tx info received because the frame was broadcasted on user space, | ||
1462 | so we get all the necessary info: tx attempts and skb control buff */ | ||
1463 | |||
1464 | tx_attempts = (struct hwsim_tx_rate *)nla_data( | ||
1465 | info->attrs[HWSIM_ATTR_TX_INFO]); | ||
1466 | |||
1467 | /* now send back TX status */ | ||
1468 | txi = IEEE80211_SKB_CB(skb); | ||
1469 | |||
1470 | if (txi->control.vif) | ||
1471 | hwsim_check_magic(txi->control.vif); | ||
1472 | if (txi->control.sta) | ||
1473 | hwsim_check_sta_magic(txi->control.sta); | ||
1474 | |||
1475 | ieee80211_tx_info_clear_status(txi); | ||
1476 | |||
1477 | for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||
1478 | txi->status.rates[i].idx = tx_attempts[i].idx; | ||
1479 | txi->status.rates[i].count = tx_attempts[i].count; | ||
1480 | /*txi->status.rates[i].flags = 0;*/ | ||
1481 | } | ||
1482 | |||
1483 | txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); | ||
1484 | |||
1485 | if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && | ||
1486 | (hwsim_flags & HWSIM_TX_STAT_ACK)) { | ||
1487 | if (skb->len >= 16) { | ||
1488 | hdr = (struct ieee80211_hdr *) skb->data; | ||
1489 | mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); | ||
1490 | } | ||
1491 | } | ||
1492 | ieee80211_tx_status_irqsafe(data2->hw, skb); | ||
1493 | return 0; | ||
1494 | out: | ||
1495 | return -EINVAL; | ||
1496 | |||
1497 | } | ||
1498 | |||
1499 | static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, | ||
1500 | struct genl_info *info) | ||
1501 | { | ||
1502 | |||
1503 | struct mac80211_hwsim_data *data2; | ||
1504 | struct ieee80211_rx_status rx_status; | ||
1505 | struct mac_address *dst; | ||
1506 | int frame_data_len; | ||
1507 | char *frame_data; | ||
1508 | struct sk_buff *skb = NULL; | ||
1509 | |||
1510 | if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || | ||
1511 | !info->attrs[HWSIM_ATTR_FRAME] || | ||
1512 | !info->attrs[HWSIM_ATTR_RX_RATE] || | ||
1513 | !info->attrs[HWSIM_ATTR_SIGNAL]) | ||
1514 | goto out; | ||
1515 | |||
1516 | dst = (struct mac_address *)nla_data( | ||
1517 | info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); | ||
1518 | |||
1519 | frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); | ||
1520 | frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); | ||
1521 | |||
1522 | /* Allocate new skb here */ | ||
1523 | skb = alloc_skb(frame_data_len, GFP_KERNEL); | ||
1524 | if (skb == NULL) | ||
1525 | goto err; | ||
1526 | |||
1527 | if (frame_data_len <= IEEE80211_MAX_DATA_LEN) { | ||
1528 | /* Copy the data */ | ||
1529 | memcpy(skb_put(skb, frame_data_len), frame_data, | ||
1530 | frame_data_len); | ||
1531 | } else | ||
1532 | goto err; | ||
1533 | |||
1534 | data2 = get_hwsim_data_ref_from_addr(dst); | ||
1535 | |||
1536 | if (data2 == NULL) | ||
1537 | goto out; | ||
1538 | |||
1539 | /* check if radio is configured properly */ | ||
1540 | |||
1541 | if (data2->idle || !data2->started || !data2->channel) | ||
1542 | goto out; | ||
1543 | |||
1544 | /*A frame is received from user space*/ | ||
1545 | memset(&rx_status, 0, sizeof(rx_status)); | ||
1546 | rx_status.freq = data2->channel->center_freq; | ||
1547 | rx_status.band = data2->channel->band; | ||
1548 | rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); | ||
1549 | rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); | ||
1550 | |||
1551 | memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); | ||
1552 | ieee80211_rx_irqsafe(data2->hw, skb); | ||
1553 | |||
1554 | return 0; | ||
1555 | err: | ||
1556 | printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); | ||
1557 | goto out; | ||
1558 | out: | ||
1559 | dev_kfree_skb(skb); | ||
1560 | return -EINVAL; | ||
1561 | } | ||
1562 | |||
1563 | static int hwsim_register_received_nl(struct sk_buff *skb_2, | ||
1564 | struct genl_info *info) | ||
1565 | { | ||
1566 | if (info == NULL) | ||
1567 | goto out; | ||
1568 | |||
1569 | wmediumd_pid = info->snd_pid; | ||
1570 | |||
1571 | printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " | ||
1572 | "switching to wmediumd mode with pid %d\n", info->snd_pid); | ||
1573 | |||
1574 | return 0; | ||
1575 | out: | ||
1576 | printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); | ||
1577 | return -EINVAL; | ||
1578 | } | ||
1579 | |||
1580 | /* Generic Netlink operations array */ | ||
1581 | static struct genl_ops hwsim_ops[] = { | ||
1582 | { | ||
1583 | .cmd = HWSIM_CMD_REGISTER, | ||
1584 | .policy = hwsim_genl_policy, | ||
1585 | .doit = hwsim_register_received_nl, | ||
1586 | .flags = GENL_ADMIN_PERM, | ||
1587 | }, | ||
1588 | { | ||
1589 | .cmd = HWSIM_CMD_FRAME, | ||
1590 | .policy = hwsim_genl_policy, | ||
1591 | .doit = hwsim_cloned_frame_received_nl, | ||
1592 | }, | ||
1593 | { | ||
1594 | .cmd = HWSIM_CMD_TX_INFO_FRAME, | ||
1595 | .policy = hwsim_genl_policy, | ||
1596 | .doit = hwsim_tx_info_frame_received_nl, | ||
1597 | }, | ||
1598 | }; | ||
1599 | |||
1600 | static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, | ||
1601 | unsigned long state, | ||
1602 | void *_notify) | ||
1603 | { | ||
1604 | struct netlink_notify *notify = _notify; | ||
1605 | |||
1606 | if (state != NETLINK_URELEASE) | ||
1607 | return NOTIFY_DONE; | ||
1608 | |||
1609 | if (notify->pid == wmediumd_pid) { | ||
1610 | printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" | ||
1611 | " socket, switching to perfect channel medium\n"); | ||
1612 | wmediumd_pid = 0; | ||
1613 | } | ||
1614 | return NOTIFY_DONE; | ||
1615 | |||
1616 | } | ||
1617 | |||
1618 | static struct notifier_block hwsim_netlink_notifier = { | ||
1619 | .notifier_call = mac80211_hwsim_netlink_notify, | ||
1620 | }; | ||
1621 | |||
1622 | static int hwsim_init_netlink(void) | ||
1623 | { | ||
1624 | int rc; | ||
1625 | printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); | ||
1626 | |||
1627 | wmediumd_pid = 0; | ||
1628 | |||
1629 | rc = genl_register_family_with_ops(&hwsim_genl_family, | ||
1630 | hwsim_ops, ARRAY_SIZE(hwsim_ops)); | ||
1631 | if (rc) | ||
1632 | goto failure; | ||
1633 | |||
1634 | rc = netlink_register_notifier(&hwsim_netlink_notifier); | ||
1635 | if (rc) | ||
1636 | goto failure; | ||
1637 | |||
1638 | return 0; | ||
1639 | |||
1640 | failure: | ||
1641 | printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); | ||
1642 | return -EINVAL; | ||
1643 | } | ||
1644 | |||
1645 | static void hwsim_exit_netlink(void) | ||
1646 | { | ||
1647 | int ret; | ||
1648 | |||
1649 | printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); | ||
1650 | /* unregister the notifier */ | ||
1651 | netlink_unregister_notifier(&hwsim_netlink_notifier); | ||
1652 | /* unregister the family */ | ||
1653 | ret = genl_unregister_family(&hwsim_genl_family); | ||
1654 | if (ret) | ||
1655 | printk(KERN_DEBUG "mac80211_hwsim: " | ||
1656 | "unregister family %i\n", ret); | ||
1657 | } | ||
1658 | |||
1251 | static int __init init_mac80211_hwsim(void) | 1659 | static int __init init_mac80211_hwsim(void) |
1252 | { | 1660 | { |
1253 | int i, err = 0; | 1661 | int i, err = 0; |
@@ -1298,6 +1706,7 @@ static int __init init_mac80211_hwsim(void) | |||
1298 | goto failed_drvdata; | 1706 | goto failed_drvdata; |
1299 | } | 1707 | } |
1300 | data->dev->driver = &mac80211_hwsim_driver; | 1708 | data->dev->driver = &mac80211_hwsim_driver; |
1709 | skb_queue_head_init(&data->pending); | ||
1301 | 1710 | ||
1302 | SET_IEEE80211_DEV(hw, data->dev); | 1711 | SET_IEEE80211_DEV(hw, data->dev); |
1303 | addr[3] = i >> 8; | 1712 | addr[3] = i >> 8; |
@@ -1379,6 +1788,10 @@ static int __init init_mac80211_hwsim(void) | |||
1379 | data->group = 1; | 1788 | data->group = 1; |
1380 | mutex_init(&data->mutex); | 1789 | mutex_init(&data->mutex); |
1381 | 1790 | ||
1791 | /* Enable frame retransmissions for lossy channels */ | ||
1792 | hw->max_rates = 4; | ||
1793 | hw->max_rate_tries = 11; | ||
1794 | |||
1382 | /* Work to be done prior to ieee80211_register_hw() */ | 1795 | /* Work to be done prior to ieee80211_register_hw() */ |
1383 | switch (regtest) { | 1796 | switch (regtest) { |
1384 | case HWSIM_REGTEST_DISABLED: | 1797 | case HWSIM_REGTEST_DISABLED: |
@@ -1515,12 +1928,29 @@ static int __init init_mac80211_hwsim(void) | |||
1515 | if (hwsim_mon == NULL) | 1928 | if (hwsim_mon == NULL) |
1516 | goto failed; | 1929 | goto failed; |
1517 | 1930 | ||
1518 | err = register_netdev(hwsim_mon); | 1931 | rtnl_lock(); |
1932 | |||
1933 | err = dev_alloc_name(hwsim_mon, hwsim_mon->name); | ||
1519 | if (err < 0) | 1934 | if (err < 0) |
1520 | goto failed_mon; | 1935 | goto failed_mon; |
1521 | 1936 | ||
1937 | |||
1938 | err = register_netdevice(hwsim_mon); | ||
1939 | if (err < 0) | ||
1940 | goto failed_mon; | ||
1941 | |||
1942 | rtnl_unlock(); | ||
1943 | |||
1944 | err = hwsim_init_netlink(); | ||
1945 | if (err < 0) | ||
1946 | goto failed_nl; | ||
1947 | |||
1522 | return 0; | 1948 | return 0; |
1523 | 1949 | ||
1950 | failed_nl: | ||
1951 | printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n"); | ||
1952 | return err; | ||
1953 | |||
1524 | failed_mon: | 1954 | failed_mon: |
1525 | rtnl_unlock(); | 1955 | rtnl_unlock(); |
1526 | free_netdev(hwsim_mon); | 1956 | free_netdev(hwsim_mon); |
@@ -1541,6 +1971,8 @@ static void __exit exit_mac80211_hwsim(void) | |||
1541 | { | 1971 | { |
1542 | printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); | 1972 | printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); |
1543 | 1973 | ||
1974 | hwsim_exit_netlink(); | ||
1975 | |||
1544 | mac80211_hwsim_free(); | 1976 | mac80211_hwsim_free(); |
1545 | unregister_netdev(hwsim_mon); | 1977 | unregister_netdev(hwsim_mon); |
1546 | } | 1978 | } |