aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-01 15:26:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:50 -0400
commitaff89a9b9084931e51b89d8f3ee3c547bea6c422 (patch)
tree592c1dfa2ef994a1b3e117b3d7bc1cc7b7bde637 /net
parent5121ea0481f9cea1dfd958f18d7b4ac78778cd40 (diff)
cfg80211: introduce nl80211 testmode command
This introduces a new NL80211_CMD_TESTMODE for testing and calibration use with nl80211. There's no multiplexing like like iwpriv had, and the command is not available by default, it needs to be explicitly enabled in Kconfig and shouldn't be enabled in most kernels. The command requires a wiphy index or interface index to identify the device to operate on, and the new TESTDATA attribute. There also is API for sending replies to the command, and testmode multicast messages (on a testmode multicast group). I've also updated mac80211 to be able to pass through the command to the driver, since it itself doesn't implement the testmode command. Additionally, to give people an idea of how to use the command, I've added a little code to hwsim that makes use of the new command to set the powersave mode, this is currently done via debugfs and should remain there, and the testmode command only serves as an example of how to use this best -- with nested netlink attributes in the TESTDATA attribute. A hwsim testmode tool can be found at http://git.sipsolutions.net/hwsim.git/. This tool is BSD licensed so people can easily use it as a basis for their own internal fabrication and validation tools. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-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
4 files changed, 168 insertions, 0 deletions
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);