Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211_hwsim driver support userspace frame tx/rx

This patch adds to mac80211_hwsim the capability to send traffic via
userspace.

Frame exchange between kernel and user spaces is done through generic
netlink communication protocol. A new generic netlink family
MAC80211_HWSIM is proposed, this family contains three basic commands
HWSIM_CMD_REGISTER, which is the command used to register a new
traffic listener, HWSIM_CMD_FRAME, to exchange the frames from kernel
to user and vice-versa, and HWSIM_CMD_TX_INFO_FRAME which returns
from user all the information about retransmissions, rates, rx signal,
and so on.

How it works:

Once the driver is loaded the MAC80211_HWSIM family will be registered.
In the absence of userspace daemon, the driver itselfs implements a
perfect wireless medium as it did in the past. When a daemon sends a
HWSIM_CMD_REGISTER command, the module stores the application PID, and
from this moment all frames will be sent to the registered daemon.

The user space application will be in charge of process/forward all
frames broadcast by any mac80211_hwsim radio. If the user application
is stopped, the kernel module will detect the release of the socket
and it will switch back to in-kernel perfect channel simulation.

The userspace daemon must be waiting for incoming HWSIM_CMD_FRAME
commands sent from kernel, for each HWSIM_CMD_FRAME command the
application will try to broadcast this frame to all mac80211_hwsim
radios, however the application may decide to forward/drop this frame.
In the case of forwarding the frame, a new HWSIM_CMD_FRAME command will
be created, all necessary attributes will be populated and the frame
will be sent back to the kernel.

Also after the frame broadcast phase, a HWSIM_CMD_TX_INFO_FRAME
command will be sent from userspace to kernel, this command contains
all the information regarding the transmission, such as number of
tries, rates, ack signal, etc.

You can find the actual implementation of wireless mediumd daemon
(wmediumd) at:

* Last version tarball: https://github.com/jlopex/cozybit/tarball/master
* Or visiting my github tree: https://github.com/jlopex/cozybit/tree

Signed-off-by: Javier Lopez <jlopex@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Javier Lopez and committed by
John W. Linville
7882513b 0f93c794

+580 -15
+447 -15
drivers/net/wireless/mac80211_hwsim.c
··· 1 1 /* 2 2 * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 3 3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4 + * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> 4 5 * 5 6 * This program is free software; you can redistribute it and/or modify 6 7 * it under the terms of the GNU General Public License version 2 as ··· 26 25 #include <linux/rtnetlink.h> 27 26 #include <linux/etherdevice.h> 28 27 #include <linux/debugfs.h> 28 + #include <net/genetlink.h> 29 + #include "mac80211_hwsim.h" 30 + 31 + #define WARN_QUEUE 100 32 + #define MAX_QUEUE 200 29 33 30 34 MODULE_AUTHOR("Jouni Malinen"); 31 35 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); 32 36 MODULE_LICENSE("GPL"); 33 37 38 + int wmediumd_pid; 34 39 static int radios = 2; 35 40 module_param(radios, int, 0444); 36 41 MODULE_PARM_DESC(radios, "Number of simulated radios"); ··· 309 302 struct dentry *debugfs; 310 303 struct dentry *debugfs_ps; 311 304 305 + struct sk_buff_head pending; /* packets pending */ 312 306 /* 313 307 * Only radios in the same group can communicate together (the 314 308 * channel has to match too). Each bit represents a group. A ··· 330 322 __le16 rt_chbitmask; 331 323 } __packed; 332 324 325 + /* MAC80211_HWSIM netlinf family */ 326 + static struct genl_family hwsim_genl_family = { 327 + .id = GENL_ID_GENERATE, 328 + .hdrsize = 0, 329 + .name = "MAC80211_HWSIM", 330 + .version = 1, 331 + .maxattr = HWSIM_ATTR_MAX, 332 + }; 333 + 334 + /* MAC80211_HWSIM netlink policy */ 335 + 336 + static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { 337 + [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC, 338 + .len = 6*sizeof(u8) }, 339 + [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC, 340 + .len = 6*sizeof(u8) }, 341 + [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY, 342 + .len = IEEE80211_MAX_DATA_LEN }, 343 + [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 }, 344 + [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 }, 345 + [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 }, 346 + [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC, 347 + .len = IEEE80211_TX_MAX_RATES*sizeof( 348 + struct hwsim_tx_rate)}, 349 + [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 }, 350 + }; 333 351 334 352 static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb, 335 353 struct net_device *dev) ··· 512 478 return md.ret; 513 479 } 514 480 481 + static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 482 + struct sk_buff *my_skb, 483 + int dst_pid) 484 + { 485 + struct sk_buff *skb; 486 + struct mac80211_hwsim_data *data = hw->priv; 487 + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data; 488 + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb); 489 + void *msg_head; 490 + unsigned int hwsim_flags = 0; 491 + int i; 492 + struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES]; 515 493 516 - static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, 517 - struct sk_buff *skb) 494 + if (data->idle) { 495 + wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n"); 496 + dev_kfree_skb(my_skb); 497 + return; 498 + } 499 + 500 + if (data->ps != PS_DISABLED) 501 + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); 502 + /* If the queue contains MAX_QUEUE skb's drop some */ 503 + if (skb_queue_len(&data->pending) >= MAX_QUEUE) { 504 + /* Droping until WARN_QUEUE level */ 505 + while (skb_queue_len(&data->pending) >= WARN_QUEUE) 506 + skb_dequeue(&data->pending); 507 + } 508 + 509 + skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC); 510 + if (skb == NULL) 511 + goto nla_put_failure; 512 + 513 + msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0, 514 + HWSIM_CMD_FRAME); 515 + if (msg_head == NULL) { 516 + printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head\n"); 517 + goto nla_put_failure; 518 + } 519 + 520 + NLA_PUT(skb, HWSIM_ATTR_ADDR_TRANSMITTER, 521 + sizeof(struct mac_address), data->addresses[1].addr); 522 + 523 + /* We get the skb->data */ 524 + NLA_PUT(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data); 525 + 526 + /* We get the flags for this transmission, and we translate them to 527 + wmediumd flags */ 528 + 529 + if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) 530 + hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS; 531 + 532 + if (info->flags & IEEE80211_TX_CTL_NO_ACK) 533 + hwsim_flags |= HWSIM_TX_CTL_NO_ACK; 534 + 535 + NLA_PUT_U32(skb, HWSIM_ATTR_FLAGS, hwsim_flags); 536 + 537 + /* We get the tx control (rate and retries) info*/ 538 + 539 + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 540 + tx_attempts[i].idx = info->status.rates[i].idx; 541 + tx_attempts[i].count = info->status.rates[i].count; 542 + } 543 + 544 + NLA_PUT(skb, HWSIM_ATTR_TX_INFO, 545 + sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES, 546 + tx_attempts); 547 + 548 + /* We create a cookie to identify this skb */ 549 + NLA_PUT_U64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb); 550 + 551 + genlmsg_end(skb, msg_head); 552 + genlmsg_unicast(&init_net, skb, dst_pid); 553 + 554 + /* Enqueue the packet */ 555 + skb_queue_tail(&data->pending, my_skb); 556 + return; 557 + 558 + nla_put_failure: 559 + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); 560 + } 561 + 562 + static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, 563 + struct sk_buff *skb) 518 564 { 519 565 struct mac80211_hwsim_data *data = hw->priv, *data2; 520 566 bool ack = false; ··· 654 540 return ack; 655 541 } 656 542 657 - 658 543 static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 659 544 { 660 545 bool ack; 661 546 struct ieee80211_tx_info *txi; 547 + int _pid; 662 548 663 549 mac80211_hwsim_monitor_rx(hw, skb); 664 550 ··· 668 554 return; 669 555 } 670 556 671 - ack = mac80211_hwsim_tx_frame(hw, skb); 557 + /* wmediumd mode check */ 558 + _pid = wmediumd_pid; 559 + 560 + if (_pid) 561 + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); 562 + 563 + /* NO wmediumd detected, perfect medium simulation */ 564 + ack = mac80211_hwsim_tx_frame_no_nl(hw, skb); 565 + 672 566 if (ack && skb->len >= 16) { 673 567 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; 674 568 mac80211_hwsim_monitor_ack(hw, hdr->addr2); ··· 757 635 struct ieee80211_hw *hw = arg; 758 636 struct sk_buff *skb; 759 637 struct ieee80211_tx_info *info; 638 + int _pid; 760 639 761 640 hwsim_check_magic(vif); 762 641 ··· 772 649 info = IEEE80211_SKB_CB(skb); 773 650 774 651 mac80211_hwsim_monitor_rx(hw, skb); 775 - mac80211_hwsim_tx_frame(hw, skb); 652 + 653 + /* wmediumd mode check */ 654 + _pid = wmediumd_pid; 655 + 656 + if (_pid) 657 + return mac80211_hwsim_tx_frame_nl(hw, skb, _pid); 658 + 659 + mac80211_hwsim_tx_frame_no_nl(hw, skb); 776 660 dev_kfree_skb(skb); 777 661 } 778 662 ··· 1096 966 1097 967 static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) 1098 968 { 1099 - /* 1100 - * In this special case, there's nothing we need to 1101 - * do because hwsim does transmission synchronously. 1102 - * In the future, when it does transmissions via 1103 - * userspace, we may need to do something. 1104 - */ 969 + /* Not implemented, queues only on kernel side */ 1105 970 } 1106 971 1107 972 struct hw_scan_done { ··· 1244 1119 struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 1245 1120 struct sk_buff *skb; 1246 1121 struct ieee80211_pspoll *pspoll; 1122 + int _pid; 1247 1123 1248 1124 if (!vp->assoc) 1249 1125 return; ··· 1263 1137 pspoll->aid = cpu_to_le16(0xc000 | vp->aid); 1264 1138 memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); 1265 1139 memcpy(pspoll->ta, mac, ETH_ALEN); 1266 - if (!mac80211_hwsim_tx_frame(data->hw, skb)) 1267 - printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); 1140 + 1141 + /* wmediumd mode check */ 1142 + _pid = wmediumd_pid; 1143 + 1144 + if (_pid) 1145 + return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); 1146 + 1147 + if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) 1148 + printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__); 1268 1149 dev_kfree_skb(skb); 1269 1150 } 1270 1151 ··· 1282 1149 struct hwsim_vif_priv *vp = (void *)vif->drv_priv; 1283 1150 struct sk_buff *skb; 1284 1151 struct ieee80211_hdr *hdr; 1152 + int _pid; 1285 1153 1286 1154 if (!vp->assoc) 1287 1155 return; ··· 1302 1168 memcpy(hdr->addr1, vp->bssid, ETH_ALEN); 1303 1169 memcpy(hdr->addr2, mac, ETH_ALEN); 1304 1170 memcpy(hdr->addr3, vp->bssid, ETH_ALEN); 1305 - if (!mac80211_hwsim_tx_frame(data->hw, skb)) 1171 + 1172 + /* wmediumd mode check */ 1173 + _pid = wmediumd_pid; 1174 + 1175 + if (_pid) 1176 + return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid); 1177 + 1178 + if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb)) 1306 1179 printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); 1307 1180 dev_kfree_skb(skb); 1308 1181 } ··· 1389 1248 hwsim_fops_group_read, hwsim_fops_group_write, 1390 1249 "%llx\n"); 1391 1250 1251 + struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr( 1252 + struct mac_address *addr) 1253 + { 1254 + struct mac80211_hwsim_data *data; 1255 + bool _found = false; 1256 + 1257 + spin_lock_bh(&hwsim_radio_lock); 1258 + list_for_each_entry(data, &hwsim_radios, list) { 1259 + if (memcmp(data->addresses[1].addr, addr, 1260 + sizeof(struct mac_address)) == 0) { 1261 + _found = true; 1262 + break; 1263 + } 1264 + } 1265 + spin_unlock_bh(&hwsim_radio_lock); 1266 + 1267 + if (!_found) 1268 + return NULL; 1269 + 1270 + return data; 1271 + } 1272 + 1273 + static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 1274 + struct genl_info *info) 1275 + { 1276 + 1277 + struct ieee80211_hdr *hdr; 1278 + struct mac80211_hwsim_data *data2; 1279 + struct ieee80211_tx_info *txi; 1280 + struct hwsim_tx_rate *tx_attempts; 1281 + struct sk_buff __user *ret_skb; 1282 + struct sk_buff *skb, *tmp; 1283 + struct mac_address *src; 1284 + unsigned int hwsim_flags; 1285 + 1286 + int i; 1287 + bool found = false; 1288 + 1289 + if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 1290 + !info->attrs[HWSIM_ATTR_FLAGS] || 1291 + !info->attrs[HWSIM_ATTR_COOKIE] || 1292 + !info->attrs[HWSIM_ATTR_TX_INFO]) 1293 + goto out; 1294 + 1295 + src = (struct mac_address *)nla_data( 1296 + info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); 1297 + hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); 1298 + 1299 + ret_skb = (struct sk_buff __user *) 1300 + (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); 1301 + 1302 + data2 = get_hwsim_data_ref_from_addr(src); 1303 + 1304 + if (data2 == NULL) 1305 + goto out; 1306 + 1307 + /* look for the skb matching the cookie passed back from user */ 1308 + skb_queue_walk_safe(&data2->pending, skb, tmp) { 1309 + if (skb == ret_skb) { 1310 + skb_unlink(skb, &data2->pending); 1311 + found = true; 1312 + break; 1313 + } 1314 + } 1315 + 1316 + /* not found */ 1317 + if (!found) 1318 + goto out; 1319 + 1320 + /* Tx info received because the frame was broadcasted on user space, 1321 + so we get all the necessary info: tx attempts and skb control buff */ 1322 + 1323 + tx_attempts = (struct hwsim_tx_rate *)nla_data( 1324 + info->attrs[HWSIM_ATTR_TX_INFO]); 1325 + 1326 + /* now send back TX status */ 1327 + txi = IEEE80211_SKB_CB(skb); 1328 + 1329 + if (txi->control.vif) 1330 + hwsim_check_magic(txi->control.vif); 1331 + if (txi->control.sta) 1332 + hwsim_check_sta_magic(txi->control.sta); 1333 + 1334 + ieee80211_tx_info_clear_status(txi); 1335 + 1336 + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { 1337 + txi->status.rates[i].idx = tx_attempts[i].idx; 1338 + txi->status.rates[i].count = tx_attempts[i].count; 1339 + /*txi->status.rates[i].flags = 0;*/ 1340 + } 1341 + 1342 + txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 1343 + 1344 + if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) && 1345 + (hwsim_flags & HWSIM_TX_STAT_ACK)) { 1346 + if (skb->len >= 16) { 1347 + hdr = (struct ieee80211_hdr *) skb->data; 1348 + mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2); 1349 + } 1350 + } 1351 + ieee80211_tx_status_irqsafe(data2->hw, skb); 1352 + return 0; 1353 + out: 1354 + return -EINVAL; 1355 + 1356 + } 1357 + 1358 + static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, 1359 + struct genl_info *info) 1360 + { 1361 + 1362 + struct mac80211_hwsim_data *data2; 1363 + struct ieee80211_rx_status rx_status; 1364 + struct mac_address *dst; 1365 + int frame_data_len; 1366 + char *frame_data; 1367 + struct sk_buff *skb = NULL; 1368 + 1369 + if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 1370 + !info->attrs[HWSIM_ATTR_FRAME] || 1371 + !info->attrs[HWSIM_ATTR_RX_RATE] || 1372 + !info->attrs[HWSIM_ATTR_SIGNAL]) 1373 + goto out; 1374 + 1375 + dst = (struct mac_address *)nla_data( 1376 + info->attrs[HWSIM_ATTR_ADDR_RECEIVER]); 1377 + 1378 + frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]); 1379 + frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]); 1380 + 1381 + /* Allocate new skb here */ 1382 + skb = alloc_skb(frame_data_len, GFP_KERNEL); 1383 + if (skb == NULL) 1384 + goto err; 1385 + 1386 + if (frame_data_len <= IEEE80211_MAX_DATA_LEN) { 1387 + /* Copy the data */ 1388 + memcpy(skb_put(skb, frame_data_len), frame_data, 1389 + frame_data_len); 1390 + } else 1391 + goto err; 1392 + 1393 + data2 = get_hwsim_data_ref_from_addr(dst); 1394 + 1395 + if (data2 == NULL) 1396 + goto out; 1397 + 1398 + /* check if radio is configured properly */ 1399 + 1400 + if (data2->idle || !data2->started || !data2->channel) 1401 + goto out; 1402 + 1403 + /*A frame is received from user space*/ 1404 + memset(&rx_status, 0, sizeof(rx_status)); 1405 + rx_status.freq = data2->channel->center_freq; 1406 + rx_status.band = data2->channel->band; 1407 + rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); 1408 + rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); 1409 + 1410 + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); 1411 + ieee80211_rx_irqsafe(data2->hw, skb); 1412 + 1413 + return 0; 1414 + err: 1415 + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); 1416 + goto out; 1417 + out: 1418 + dev_kfree_skb(skb); 1419 + return -EINVAL; 1420 + } 1421 + 1422 + static int hwsim_register_received_nl(struct sk_buff *skb_2, 1423 + struct genl_info *info) 1424 + { 1425 + if (info == NULL) 1426 + goto out; 1427 + 1428 + wmediumd_pid = info->snd_pid; 1429 + 1430 + printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " 1431 + "switching to wmediumd mode with pid %d\n", info->snd_pid); 1432 + 1433 + return 0; 1434 + out: 1435 + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); 1436 + return -EINVAL; 1437 + } 1438 + 1439 + /* Generic Netlink operations array */ 1440 + static struct genl_ops hwsim_ops[] = { 1441 + { 1442 + .cmd = HWSIM_CMD_REGISTER, 1443 + .policy = hwsim_genl_policy, 1444 + .doit = hwsim_register_received_nl, 1445 + .flags = GENL_ADMIN_PERM, 1446 + }, 1447 + { 1448 + .cmd = HWSIM_CMD_FRAME, 1449 + .policy = hwsim_genl_policy, 1450 + .doit = hwsim_cloned_frame_received_nl, 1451 + }, 1452 + { 1453 + .cmd = HWSIM_CMD_TX_INFO_FRAME, 1454 + .policy = hwsim_genl_policy, 1455 + .doit = hwsim_tx_info_frame_received_nl, 1456 + }, 1457 + }; 1458 + 1459 + static int mac80211_hwsim_netlink_notify(struct notifier_block *nb, 1460 + unsigned long state, 1461 + void *_notify) 1462 + { 1463 + struct netlink_notify *notify = _notify; 1464 + 1465 + if (state != NETLINK_URELEASE) 1466 + return NOTIFY_DONE; 1467 + 1468 + if (notify->pid == wmediumd_pid) { 1469 + printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 1470 + " socket, switching to perfect channel medium\n"); 1471 + wmediumd_pid = 0; 1472 + } 1473 + return NOTIFY_DONE; 1474 + 1475 + } 1476 + 1477 + static struct notifier_block hwsim_netlink_notifier = { 1478 + .notifier_call = mac80211_hwsim_netlink_notify, 1479 + }; 1480 + 1481 + static int hwsim_init_netlink(void) 1482 + { 1483 + int rc; 1484 + printk(KERN_INFO "mac80211_hwsim: initializing netlink\n"); 1485 + 1486 + wmediumd_pid = 0; 1487 + 1488 + rc = genl_register_family_with_ops(&hwsim_genl_family, 1489 + hwsim_ops, ARRAY_SIZE(hwsim_ops)); 1490 + if (rc) 1491 + goto failure; 1492 + 1493 + rc = netlink_register_notifier(&hwsim_netlink_notifier); 1494 + if (rc) 1495 + goto failure; 1496 + 1497 + return 0; 1498 + 1499 + failure: 1500 + printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__); 1501 + return -EINVAL; 1502 + } 1503 + 1504 + static void hwsim_exit_netlink(void) 1505 + { 1506 + int ret; 1507 + 1508 + printk(KERN_INFO "mac80211_hwsim: closing netlink\n"); 1509 + /* unregister the notifier */ 1510 + netlink_unregister_notifier(&hwsim_netlink_notifier); 1511 + /* unregister the family */ 1512 + ret = genl_unregister_family(&hwsim_genl_family); 1513 + if (ret) 1514 + printk(KERN_DEBUG "mac80211_hwsim: " 1515 + "unregister family %i\n", ret); 1516 + } 1517 + 1392 1518 static int __init init_mac80211_hwsim(void) 1393 1519 { 1394 1520 int i, err = 0; ··· 1706 1298 goto failed_drvdata; 1707 1299 } 1708 1300 data->dev->driver = &mac80211_hwsim_driver; 1301 + skb_queue_head_init(&data->pending); 1709 1302 1710 1303 SET_IEEE80211_DEV(hw, data->dev); 1711 1304 addr[3] = i >> 8; ··· 1787 1378 /* By default all radios are belonging to the first group */ 1788 1379 data->group = 1; 1789 1380 mutex_init(&data->mutex); 1381 + 1382 + /* Enable frame retransmissions for lossy channels */ 1383 + hw->max_rates = 4; 1384 + hw->max_rate_tries = 11; 1790 1385 1791 1386 /* Work to be done prior to ieee80211_register_hw() */ 1792 1387 switch (regtest) { ··· 1928 1515 if (hwsim_mon == NULL) 1929 1516 goto failed; 1930 1517 1931 - err = register_netdev(hwsim_mon); 1518 + rtnl_lock(); 1519 + 1520 + err = dev_alloc_name(hwsim_mon, hwsim_mon->name); 1932 1521 if (err < 0) 1933 1522 goto failed_mon; 1934 1523 1524 + 1525 + err = register_netdevice(hwsim_mon); 1526 + if (err < 0) 1527 + goto failed_mon; 1528 + 1529 + rtnl_unlock(); 1530 + 1531 + err = hwsim_init_netlink(); 1532 + if (err < 0) 1533 + goto failed_nl; 1534 + 1935 1535 return 0; 1536 + 1537 + failed_nl: 1538 + printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n"); 1539 + return err; 1936 1540 1937 1541 failed_mon: 1938 1542 rtnl_unlock(); ··· 1970 1540 static void __exit exit_mac80211_hwsim(void) 1971 1541 { 1972 1542 printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n"); 1543 + 1544 + hwsim_exit_netlink(); 1973 1545 1974 1546 mac80211_hwsim_free(); 1975 1547 unregister_netdev(hwsim_mon);
+133
drivers/net/wireless/mac80211_hwsim.h
··· 1 + /* 2 + * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 3 + * Copyright (c) 2008, Jouni Malinen <j@w1.fi> 4 + * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #ifndef __MAC80211_HWSIM_H 12 + #define __MAC80211_HWSIM_H 13 + 14 + /** 15 + * enum hwsim_tx_control_flags - flags to describe transmission info/status 16 + * 17 + * These flags are used to give the wmediumd extra information in order to 18 + * modify its behavior for each frame 19 + * 20 + * @HWSIM_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame. 21 + * @HWSIM_TX_CTL_NO_ACK: tell the wmediumd not to wait for an ack 22 + * @HWSIM_TX_STAT_ACK: Frame was acknowledged 23 + * 24 + */ 25 + enum hwsim_tx_control_flags { 26 + HWSIM_TX_CTL_REQ_TX_STATUS = BIT(0), 27 + HWSIM_TX_CTL_NO_ACK = BIT(1), 28 + HWSIM_TX_STAT_ACK = BIT(2), 29 + }; 30 + 31 + /** 32 + * DOC: Frame transmission/registration support 33 + * 34 + * Frame transmission and registration support exists to allow userspace 35 + * entities such as wmediumd to receive and process all broadcasted 36 + * frames from a mac80211_hwsim radio device. 37 + * 38 + * This allow user space applications to decide if the frame should be 39 + * dropped or not and implement a wireless medium simulator at user space. 40 + * 41 + * Registration is done by sending a register message to the driver and 42 + * will be automatically unregistered if the user application doesn't 43 + * responds to sent frames. 44 + * Once registered the user application has to take responsibility of 45 + * broadcasting the frames to all listening mac80211_hwsim radio 46 + * interfaces. 47 + * 48 + * For more technical details, see the corresponding command descriptions 49 + * below. 50 + */ 51 + 52 + /** 53 + * enum hwsim_commands - supported hwsim commands 54 + * 55 + * @HWSIM_CMD_UNSPEC: unspecified command to catch errors 56 + * 57 + * @HWSIM_CMD_REGISTER: request to register and received all broadcasted 58 + * frames by any mac80211_hwsim radio device. 59 + * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user 60 + * space, uses: 61 + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER, 62 + * %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE, 63 + * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE 64 + * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to 65 + * kernel, uses: 66 + * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, 67 + * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE 68 + * @__HWSIM_CMD_MAX: enum limit 69 + */ 70 + enum { 71 + HWSIM_CMD_UNSPEC, 72 + HWSIM_CMD_REGISTER, 73 + HWSIM_CMD_FRAME, 74 + HWSIM_CMD_TX_INFO_FRAME, 75 + __HWSIM_CMD_MAX, 76 + }; 77 + #define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1) 78 + 79 + /** 80 + * enum hwsim_attrs - hwsim netlink attributes 81 + * 82 + * @HWSIM_ATTR_UNSPEC: unspecified attribute to catch errors 83 + * 84 + * @HWSIM_ATTR_ADDR_RECEIVER: MAC address of the radio device that 85 + * the frame is broadcasted to 86 + * @HWSIM_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that 87 + * the frame was broadcasted from 88 + * @HWSIM_ATTR_FRAME: Data array 89 + * @HWSIM_ATTR_FLAGS: mac80211 transmission flags, used to process 90 + properly the frame at user space 91 + * @HWSIM_ATTR_RX_RATE: estimated rx rate index for this frame at user 92 + space 93 + * @HWSIM_ATTR_SIGNAL: estimated RX signal for this frame at user 94 + space 95 + * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array 96 + * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame 97 + * @__HWSIM_ATTR_MAX: enum limit 98 + */ 99 + 100 + 101 + enum { 102 + HWSIM_ATTR_UNSPEC, 103 + HWSIM_ATTR_ADDR_RECEIVER, 104 + HWSIM_ATTR_ADDR_TRANSMITTER, 105 + HWSIM_ATTR_FRAME, 106 + HWSIM_ATTR_FLAGS, 107 + HWSIM_ATTR_RX_RATE, 108 + HWSIM_ATTR_SIGNAL, 109 + HWSIM_ATTR_TX_INFO, 110 + HWSIM_ATTR_COOKIE, 111 + __HWSIM_ATTR_MAX, 112 + }; 113 + #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) 114 + 115 + /** 116 + * struct hwsim_tx_rate - rate selection/status 117 + * 118 + * @idx: rate index to attempt to send with 119 + * @count: number of tries in this rate before going to the next rate 120 + * 121 + * A value of -1 for @idx indicates an invalid rate and, if used 122 + * in an array of retry rates, that no more rates should be tried. 123 + * 124 + * When used for transmit status reporting, the driver should 125 + * always report the rate and number of retries used. 126 + * 127 + */ 128 + struct hwsim_tx_rate { 129 + s8 idx; 130 + u8 count; 131 + } __packed; 132 + 133 + #endif /* __MAC80211_HWSIM_H */