aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c68
-rw-r--r--include/linux/nl80211.h11
-rw-r--r--include/net/cfg80211.h83
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/cfg.c13
-rw-r--r--net/wireless/Kconfig15
-rw-r--r--net/wireless/core.h4
-rw-r--r--net/wireless/nl80211.c136
8 files changed, 335 insertions, 0 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 93c1c4a73e6c..6ac8565072e9 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -700,6 +700,73 @@ static int mac80211_hwsim_conf_tx(
700 return 0; 700 return 0;
701} 701}
702 702
703#ifdef CONFIG_NL80211_TESTMODE
704/*
705 * This section contains example code for using netlink
706 * attributes with the testmode command in nl80211.
707 */
708
709/* These enums need to be kept in sync with userspace */
710enum hwsim_testmode_attr {
711 __HWSIM_TM_ATTR_INVALID = 0,
712 HWSIM_TM_ATTR_CMD = 1,
713 HWSIM_TM_ATTR_PS = 2,
714
715 /* keep last */
716 __HWSIM_TM_ATTR_AFTER_LAST,
717 HWSIM_TM_ATTR_MAX = __HWSIM_TM_ATTR_AFTER_LAST - 1
718};
719
720enum hwsim_testmode_cmd {
721 HWSIM_TM_CMD_SET_PS = 0,
722 HWSIM_TM_CMD_GET_PS = 1,
723};
724
725static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = {
726 [HWSIM_TM_ATTR_CMD] = { .type = NLA_U32 },
727 [HWSIM_TM_ATTR_PS] = { .type = NLA_U32 },
728};
729
730static int hwsim_fops_ps_write(void *dat, u64 val);
731
732int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
733{
734 struct mac80211_hwsim_data *hwsim = hw->priv;
735 struct nlattr *tb[HWSIM_TM_ATTR_MAX + 1];
736 struct sk_buff *skb;
737 int err, ps;
738
739 err = nla_parse(tb, HWSIM_TM_ATTR_MAX, data, len,
740 hwsim_testmode_policy);
741 if (err)
742 return err;
743
744 if (!tb[HWSIM_TM_ATTR_CMD])
745 return -EINVAL;
746
747 switch (nla_get_u32(tb[HWSIM_TM_ATTR_CMD])) {
748 case HWSIM_TM_CMD_SET_PS:
749 if (!tb[HWSIM_TM_ATTR_PS])
750 return -EINVAL;
751 ps = nla_get_u32(tb[HWSIM_TM_ATTR_PS]);
752 return hwsim_fops_ps_write(hwsim, ps);
753 case HWSIM_TM_CMD_GET_PS:
754 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
755 nla_total_size(sizeof(u32)));
756 if (!skb)
757 return -ENOMEM;
758 NLA_PUT_U32(skb, HWSIM_TM_ATTR_PS, hwsim->ps);
759 return cfg80211_testmode_reply(skb);
760 default:
761 return -EOPNOTSUPP;
762 }
763
764 nla_put_failure:
765 kfree_skb(skb);
766 return -ENOBUFS;
767}
768#endif
769
703static const struct ieee80211_ops mac80211_hwsim_ops = 770static const struct ieee80211_ops mac80211_hwsim_ops =
704{ 771{
705 .tx = mac80211_hwsim_tx, 772 .tx = mac80211_hwsim_tx,
@@ -713,6 +780,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
713 .sta_notify = mac80211_hwsim_sta_notify, 780 .sta_notify = mac80211_hwsim_sta_notify,
714 .set_tim = mac80211_hwsim_set_tim, 781 .set_tim = mac80211_hwsim_set_tim,
715 .conf_tx = mac80211_hwsim_conf_tx, 782 .conf_tx = mac80211_hwsim_conf_tx,
783 CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
716}; 784};
717 785
718 786
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index dbea93b694e5..651b18839088 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -242,6 +242,10 @@
242 * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is 242 * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
243 * determined by the network interface. 243 * determined by the network interface.
244 * 244 *
245 * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
246 * to identify the device, and the TESTDATA blob attribute to pass through
247 * to the driver.
248 *
245 * @NL80211_CMD_MAX: highest used command number 249 * @NL80211_CMD_MAX: highest used command number
246 * @__NL80211_CMD_AFTER_LAST: internal use 250 * @__NL80211_CMD_AFTER_LAST: internal use
247 */ 251 */
@@ -310,6 +314,8 @@ enum nl80211_commands {
310 NL80211_CMD_JOIN_IBSS, 314 NL80211_CMD_JOIN_IBSS,
311 NL80211_CMD_LEAVE_IBSS, 315 NL80211_CMD_LEAVE_IBSS,
312 316
317 NL80211_CMD_TESTMODE,
318
313 /* add new commands above here */ 319 /* add new commands above here */
314 320
315 /* used to define NL80211_CMD_MAX below */ 321 /* used to define NL80211_CMD_MAX below */
@@ -511,6 +517,9 @@ enum nl80211_commands {
511 * authorized by user space. Otherwise, port is marked authorized by 517 * authorized by user space. Otherwise, port is marked authorized by
512 * default in station mode. 518 * default in station mode.
513 * 519 *
520 * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
521 * We recommend using nested, driver-specific attributes within this.
522 *
514 * @NL80211_ATTR_MAX: highest attribute number currently defined 523 * @NL80211_ATTR_MAX: highest attribute number currently defined
515 * @__NL80211_ATTR_AFTER_LAST: internal use 524 * @__NL80211_ATTR_AFTER_LAST: internal use
516 */ 525 */
@@ -619,6 +628,8 @@ enum nl80211_attrs {
619 628
620 NL80211_ATTR_CONTROL_PORT, 629 NL80211_ATTR_CONTROL_PORT,
621 630
631 NL80211_ATTR_TESTDATA,
632
622 /* add attributes here, update the policy in nl80211.c */ 633 /* add attributes here, update the policy in nl80211.c */
623 634
624 __NL80211_ATTR_AFTER_LAST, 635 __NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 10eb53e2bc9f..885d4e5bc4b5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -857,6 +857,8 @@ enum tx_power_setting {
857 * 857 *
858 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting 858 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
859 * functions to adjust rfkill hw state 859 * functions to adjust rfkill hw state
860 *
861 * @testmode_cmd: run a test mode command
860 */ 862 */
861struct cfg80211_ops { 863struct cfg80211_ops {
862 int (*suspend)(struct wiphy *wiphy); 864 int (*suspend)(struct wiphy *wiphy);
@@ -955,6 +957,10 @@ struct cfg80211_ops {
955 int (*get_tx_power)(struct wiphy *wiphy, int *dbm); 957 int (*get_tx_power)(struct wiphy *wiphy, int *dbm);
956 958
957 void (*rfkill_poll)(struct wiphy *wiphy); 959 void (*rfkill_poll)(struct wiphy *wiphy);
960
961#ifdef CONFIG_NL80211_TESTMODE
962 int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
963#endif
958}; 964};
959 965
960/* 966/*
@@ -1705,4 +1711,81 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy);
1705 */ 1711 */
1706void wiphy_rfkill_stop_polling(struct wiphy *wiphy); 1712void wiphy_rfkill_stop_polling(struct wiphy *wiphy);
1707 1713
1714#ifdef CONFIG_NL80211_TESTMODE
1715/**
1716 * cfg80211_testmode_alloc_reply_skb - allocate testmode reply
1717 * @wiphy: the wiphy
1718 * @approxlen: an upper bound of the length of the data that will
1719 * be put into the skb
1720 *
1721 * This function allocates and pre-fills an skb for a reply to
1722 * the testmode command. Since it is intended for a reply, calling
1723 * it outside of the @testmode_cmd operation is invalid.
1724 *
1725 * The returned skb (or %NULL if any errors happen) is pre-filled
1726 * with the wiphy index and set up in a way that any data that is
1727 * put into the skb (with skb_put(), nla_put() or similar) will end
1728 * up being within the %NL80211_ATTR_TESTDATA attribute, so all that
1729 * needs to be done with the skb is adding data for the corresponding
1730 * userspace tool which can then read that data out of the testdata
1731 * attribute. You must not modify the skb in any other way.
1732 *
1733 * When done, call cfg80211_testmode_reply() with the skb and return
1734 * its error code as the result of the @testmode_cmd operation.
1735 */
1736struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
1737 int approxlen);
1738
1739/**
1740 * cfg80211_testmode_reply - send the reply skb
1741 * @skb: The skb, must have been allocated with
1742 * cfg80211_testmode_alloc_reply_skb()
1743 *
1744 * Returns an error code or 0 on success, since calling this
1745 * function will usually be the last thing before returning
1746 * from the @testmode_cmd you should return the error code.
1747 * Note that this function consumes the skb regardless of the
1748 * return value.
1749 */
1750int cfg80211_testmode_reply(struct sk_buff *skb);
1751
1752/**
1753 * cfg80211_testmode_alloc_event_skb - allocate testmode event
1754 * @wiphy: the wiphy
1755 * @approxlen: an upper bound of the length of the data that will
1756 * be put into the skb
1757 * @gfp: allocation flags
1758 *
1759 * This function allocates and pre-fills an skb for an event on the
1760 * testmode multicast group.
1761 *
1762 * The returned skb (or %NULL if any errors happen) is set up in the
1763 * same way as with cfg80211_testmode_alloc_reply_skb() but prepared
1764 * for an event. As there, you should simply add data to it that will
1765 * then end up in the %NL80211_ATTR_TESTDATA attribute. Again, you must
1766 * not modify the skb in any other way.
1767 *
1768 * When done filling the skb, call cfg80211_testmode_event() with the
1769 * skb to send the event.
1770 */
1771struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
1772 int approxlen, gfp_t gfp);
1773
1774/**
1775 * cfg80211_testmode_event - send the event
1776 * @skb: The skb, must have been allocated with
1777 * cfg80211_testmode_alloc_event_skb()
1778 * @gfp: allocation flags
1779 *
1780 * This function sends the given @skb, which must have been allocated
1781 * by cfg80211_testmode_alloc_event_skb(), as an event. It always
1782 * consumes it.
1783 */
1784void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
1785
1786#define CFG80211_TESTMODE_CMD(cmd) .testmode_cmd = (cmd),
1787#else
1788#define CFG80211_TESTMODE_CMD(cmd)
1789#endif
1790
1708#endif /* __NET_CFG80211_H */ 1791#endif /* __NET_CFG80211_H */
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index fe80771d95f1..ce7cb1b5d453 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1416,6 +1416,8 @@ enum ieee80211_ampdu_mlme_action {
1416 * @rfkill_poll: Poll rfkill hardware state. If you need this, you also 1416 * @rfkill_poll: Poll rfkill hardware state. If you need this, you also
1417 * need to set wiphy->rfkill_poll to %true before registration, 1417 * need to set wiphy->rfkill_poll to %true before registration,
1418 * and need to call wiphy_rfkill_set_hw_state() in the callback. 1418 * and need to call wiphy_rfkill_set_hw_state() in the callback.
1419 *
1420 * @testmode_cmd: Implement a cfg80211 test mode command.
1419 */ 1421 */
1420struct ieee80211_ops { 1422struct ieee80211_ops {
1421 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); 1423 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1466,6 +1468,9 @@ struct ieee80211_ops {
1466 struct ieee80211_sta *sta, u16 tid, u16 *ssn); 1468 struct ieee80211_sta *sta, u16 tid, u16 *ssn);
1467 1469
1468 void (*rfkill_poll)(struct ieee80211_hw *hw); 1470 void (*rfkill_poll)(struct ieee80211_hw *hw);
1471#ifdef CONFIG_NL80211_TESTMODE
1472 int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
1473#endif
1469}; 1474};
1470 1475
1471/** 1476/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index eb93eb6a9cc7..c34c1a41019a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1376,6 +1376,18 @@ static void ieee80211_rfkill_poll(struct wiphy *wiphy)
1376 drv_rfkill_poll(local); 1376 drv_rfkill_poll(local);
1377} 1377}
1378 1378
1379#ifdef CONFIG_NL80211_TESTMODE
1380int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
1381{
1382 struct ieee80211_local *local = wiphy_priv(wiphy);
1383
1384 if (!local->ops->testmode_cmd)
1385 return -EOPNOTSUPP;
1386
1387 return local->ops->testmode_cmd(&local->hw, data, len);
1388}
1389#endif
1390
1379struct cfg80211_ops mac80211_config_ops = { 1391struct cfg80211_ops mac80211_config_ops = {
1380 .add_virtual_intf = ieee80211_add_iface, 1392 .add_virtual_intf = ieee80211_add_iface,
1381 .del_virtual_intf = ieee80211_del_iface, 1393 .del_virtual_intf = ieee80211_del_iface,
@@ -1418,4 +1430,5 @@ struct cfg80211_ops mac80211_config_ops = {
1418 .set_tx_power = ieee80211_set_tx_power, 1430 .set_tx_power = ieee80211_set_tx_power,
1419 .get_tx_power = ieee80211_get_tx_power, 1431 .get_tx_power = ieee80211_get_tx_power,
1420 .rfkill_poll = ieee80211_rfkill_poll, 1432 .rfkill_poll = ieee80211_rfkill_poll,
1433 CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
1421}; 1434};
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index ec64571c4c23..040263118a20 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -2,6 +2,21 @@ config CFG80211
2 tristate "Improved wireless configuration API" 2 tristate "Improved wireless configuration API"
3 depends on RFKILL || !RFKILL 3 depends on RFKILL || !RFKILL
4 4
5config NL80211_TESTMODE
6 bool "nl80211 testmode command"
7 depends on CFG80211
8 help
9 The nl80211 testmode command helps implementing things like
10 factory calibration or validation tools for wireless chips.
11
12 Select this option ONLY for kernels that are specifically
13 built for such purposes.
14
15 Debugging tools that are supposed to end up in the hands of
16 users should better be implemented with debugfs.
17
18 Say N.
19
5config CFG80211_REG_DEBUG 20config CFG80211_REG_DEBUG
6 bool "cfg80211 regulatory debugging" 21 bool "cfg80211 regulatory debugging"
7 depends on CFG80211 22 depends on CFG80211
diff --git a/net/wireless/core.h b/net/wireless/core.h
index bfa340c7abb5..bc084b68865c 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -58,6 +58,10 @@ struct cfg80211_registered_device {
58 struct cfg80211_scan_request *scan_req; /* protected by RTNL */ 58 struct cfg80211_scan_request *scan_req; /* protected by RTNL */
59 unsigned long suspend_at; 59 unsigned long suspend_at;
60 60
61#ifdef CONFIG_NL80211_TESTMODE
62 struct genl_info *testmode_info;
63#endif
64
61#ifdef CONFIG_CFG80211_DEBUGFS 65#ifdef CONFIG_CFG80211_DEBUGFS
62 /* Debugfs entries */ 66 /* Debugfs entries */
63 struct wiphy_debugfsdentries { 67 struct wiphy_debugfsdentries {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 01523ba81baf..bb8de268a6bf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3416,6 +3416,128 @@ unlock_rtnl:
3416 return err; 3416 return err;
3417} 3417}
3418 3418
3419#ifdef CONFIG_NL80211_TESTMODE
3420static struct genl_multicast_group nl80211_testmode_mcgrp = {
3421 .name = "testmode",
3422};
3423
3424static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
3425{
3426 struct cfg80211_registered_device *rdev;
3427 int err;
3428
3429 if (!info->attrs[NL80211_ATTR_TESTDATA])
3430 return -EINVAL;
3431
3432 rtnl_lock();
3433
3434 rdev = cfg80211_get_dev_from_info(info);
3435 if (IS_ERR(rdev)) {
3436 err = PTR_ERR(rdev);
3437 goto unlock_rtnl;
3438 }
3439
3440 err = -EOPNOTSUPP;
3441 if (rdev->ops->testmode_cmd) {
3442 rdev->testmode_info = info;
3443 err = rdev->ops->testmode_cmd(&rdev->wiphy,
3444 nla_data(info->attrs[NL80211_ATTR_TESTDATA]),
3445 nla_len(info->attrs[NL80211_ATTR_TESTDATA]));
3446 rdev->testmode_info = NULL;
3447 }
3448
3449 cfg80211_put_dev(rdev);
3450
3451 unlock_rtnl:
3452 rtnl_unlock();
3453 return err;
3454}
3455
3456static struct sk_buff *
3457__cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
3458 int approxlen, u32 pid, u32 seq, gfp_t gfp)
3459{
3460 struct sk_buff *skb;
3461 void *hdr;
3462 struct nlattr *data;
3463
3464 skb = nlmsg_new(approxlen + 100, gfp);
3465 if (!skb)
3466 return NULL;
3467
3468 hdr = nl80211hdr_put(skb, pid, seq, 0, NL80211_CMD_TESTMODE);
3469 if (!hdr) {
3470 kfree_skb(skb);
3471 return NULL;
3472 }
3473
3474 NLA_PUT_U32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
3475 data = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
3476
3477 ((void **)skb->cb)[0] = rdev;
3478 ((void **)skb->cb)[1] = hdr;
3479 ((void **)skb->cb)[2] = data;
3480
3481 return skb;
3482
3483 nla_put_failure:
3484 kfree_skb(skb);
3485 return NULL;
3486}
3487
3488struct sk_buff *cfg80211_testmode_alloc_reply_skb(struct wiphy *wiphy,
3489 int approxlen)
3490{
3491 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
3492
3493 if (WARN_ON(!rdev->testmode_info))
3494 return NULL;
3495
3496 return __cfg80211_testmode_alloc_skb(rdev, approxlen,
3497 rdev->testmode_info->snd_pid,
3498 rdev->testmode_info->snd_seq,
3499 GFP_KERNEL);
3500}
3501EXPORT_SYMBOL(cfg80211_testmode_alloc_reply_skb);
3502
3503int cfg80211_testmode_reply(struct sk_buff *skb)
3504{
3505 struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
3506 void *hdr = ((void **)skb->cb)[1];
3507 struct nlattr *data = ((void **)skb->cb)[2];
3508
3509 if (WARN_ON(!rdev->testmode_info)) {
3510 kfree_skb(skb);
3511 return -EINVAL;
3512 }
3513
3514 nla_nest_end(skb, data);
3515 genlmsg_end(skb, hdr);
3516 return genlmsg_reply(skb, rdev->testmode_info);
3517}
3518EXPORT_SYMBOL(cfg80211_testmode_reply);
3519
3520struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
3521 int approxlen, gfp_t gfp)
3522{
3523 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
3524
3525 return __cfg80211_testmode_alloc_skb(rdev, approxlen, 0, 0, gfp);
3526}
3527EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
3528
3529void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
3530{
3531 void *hdr = ((void **)skb->cb)[1];
3532 struct nlattr *data = ((void **)skb->cb)[2];
3533
3534 nla_nest_end(skb, data);
3535 genlmsg_end(skb, hdr);
3536 genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
3537}
3538EXPORT_SYMBOL(cfg80211_testmode_event);
3539#endif
3540
3419static struct genl_ops nl80211_ops[] = { 3541static struct genl_ops nl80211_ops[] = {
3420 { 3542 {
3421 .cmd = NL80211_CMD_GET_WIPHY, 3543 .cmd = NL80211_CMD_GET_WIPHY,
@@ -3629,6 +3751,14 @@ static struct genl_ops nl80211_ops[] = {
3629 .policy = nl80211_policy, 3751 .policy = nl80211_policy,
3630 .flags = GENL_ADMIN_PERM, 3752 .flags = GENL_ADMIN_PERM,
3631 }, 3753 },
3754#ifdef CONFIG_NL80211_TESTMODE
3755 {
3756 .cmd = NL80211_CMD_TESTMODE,
3757 .doit = nl80211_testmode_do,
3758 .policy = nl80211_policy,
3759 .flags = GENL_ADMIN_PERM,
3760 },
3761#endif
3632}; 3762};
3633static struct genl_multicast_group nl80211_mlme_mcgrp = { 3763static struct genl_multicast_group nl80211_mlme_mcgrp = {
3634 .name = "mlme", 3764 .name = "mlme",
@@ -4102,6 +4232,12 @@ int nl80211_init(void)
4102 if (err) 4232 if (err)
4103 goto err_out; 4233 goto err_out;
4104 4234
4235#ifdef CONFIG_NL80211_TESTMODE
4236 err = genl_register_mc_group(&nl80211_fam, &nl80211_testmode_mcgrp);
4237 if (err)
4238 goto err_out;
4239#endif
4240
4105 return 0; 4241 return 0;
4106 err_out: 4242 err_out:
4107 genl_unregister_family(&nl80211_fam); 4243 genl_unregister_family(&nl80211_fam);