aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-02-26 02:26:21 -0500
committerDavid S. Miller <davem@davemloft.net>2010-02-26 02:26:21 -0500
commit19bc291c99f018bd4f2c38bbf69144086dca903f (patch)
tree9d3cf9bc0c5a78e363dc0547da8bcd1e7c394265 /net/wireless/nl80211.c
parent04488734806948624dabc4514f96f14cd75b9a50 (diff)
parent4a6967b88af02eebeedfbb91bc09160750225bb5 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Conflicts: drivers/net/wireless/iwlwifi/iwl-core.h drivers/net/wireless/rt2x00/rt2800pci.c
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c440
1 files changed, 403 insertions, 37 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a001ea32cb7..e447db04cf7 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * This is the new netlink-based wireless configuration interface. 2 * This is the new netlink-based wireless configuration interface.
3 * 3 *
4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6 6
7#include <linux/if.h> 7#include <linux/if.h>
@@ -145,6 +145,10 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 }, 145 [NL80211_ATTR_DURATION] = { .type = NLA_U32 },
146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, 146 [NL80211_ATTR_COOKIE] = { .type = NLA_U64 },
147 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED }, 147 [NL80211_ATTR_TX_RATES] = { .type = NLA_NESTED },
148 [NL80211_ATTR_FRAME] = { .type = NLA_BINARY,
149 .len = IEEE80211_MAX_DATA_LEN },
150 [NL80211_ATTR_FRAME_MATCH] = { .type = NLA_BINARY, },
151 [NL80211_ATTR_PS_STATE] = { .type = NLA_U32 },
148}; 152};
149 153
150/* policy for the attributes */ 154/* policy for the attributes */
@@ -576,6 +580,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
576 CMD(flush_pmksa, FLUSH_PMKSA); 580 CMD(flush_pmksa, FLUSH_PMKSA);
577 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 581 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
578 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); 582 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
583 CMD(action, ACTION);
579 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 584 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
580 i++; 585 i++;
581 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 586 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -2009,6 +2014,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2009 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]) 2014 if (!info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES])
2010 return -EINVAL; 2015 return -EINVAL;
2011 2016
2017 if (!info->attrs[NL80211_ATTR_STA_AID])
2018 return -EINVAL;
2019
2012 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 2020 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2013 params.supported_rates = 2021 params.supported_rates =
2014 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]); 2022 nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_RATES]);
@@ -2017,11 +2025,9 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2017 params.listen_interval = 2025 params.listen_interval =
2018 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]); 2026 nla_get_u16(info->attrs[NL80211_ATTR_STA_LISTEN_INTERVAL]);
2019 2027
2020 if (info->attrs[NL80211_ATTR_STA_AID]) { 2028 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]);
2021 params.aid = nla_get_u16(info->attrs[NL80211_ATTR_STA_AID]); 2029 if (!params.aid || params.aid > IEEE80211_MAX_AID)
2022 if (!params.aid || params.aid > IEEE80211_MAX_AID) 2030 return -EINVAL;
2023 return -EINVAL;
2024 }
2025 2031
2026 if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) 2032 if (info->attrs[NL80211_ATTR_HT_CAPABILITY])
2027 params.ht_capa = 2033 params.ht_capa =
@@ -2036,6 +2042,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2036 if (err) 2042 if (err)
2037 goto out_rtnl; 2043 goto out_rtnl;
2038 2044
2045 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2046 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
2047 err = -EINVAL;
2048 goto out;
2049 }
2050
2039 err = get_vlan(info, rdev, &params.vlan); 2051 err = get_vlan(info, rdev, &params.vlan);
2040 if (err) 2052 if (err)
2041 goto out; 2053 goto out;
@@ -2043,35 +2055,6 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
2043 /* validate settings */ 2055 /* validate settings */
2044 err = 0; 2056 err = 0;
2045 2057
2046 switch (dev->ieee80211_ptr->iftype) {
2047 case NL80211_IFTYPE_AP:
2048 case NL80211_IFTYPE_AP_VLAN:
2049 /* all ok but must have AID */
2050 if (!params.aid)
2051 err = -EINVAL;
2052 break;
2053 case NL80211_IFTYPE_MESH_POINT:
2054 /* disallow things mesh doesn't support */
2055 if (params.vlan)
2056 err = -EINVAL;
2057 if (params.aid)
2058 err = -EINVAL;
2059 if (params.ht_capa)
2060 err = -EINVAL;
2061 if (params.listen_interval >= 0)
2062 err = -EINVAL;
2063 if (params.supported_rates)
2064 err = -EINVAL;
2065 if (params.sta_flags_mask)
2066 err = -EINVAL;
2067 break;
2068 default:
2069 err = -EINVAL;
2070 }
2071
2072 if (err)
2073 goto out;
2074
2075 if (!rdev->ops->add_station) { 2058 if (!rdev->ops->add_station) {
2076 err = -EOPNOTSUPP; 2059 err = -EOPNOTSUPP;
2077 goto out; 2060 goto out;
@@ -2112,8 +2095,7 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
2112 goto out_rtnl; 2095 goto out_rtnl;
2113 2096
2114 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2097 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2115 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && 2098 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
2116 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT) {
2117 err = -EINVAL; 2099 err = -EINVAL;
2118 goto out; 2100 goto out;
2119 } 2101 }
@@ -4545,6 +4527,257 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4545 return err; 4527 return err;
4546} 4528}
4547 4529
4530static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4531{
4532 struct cfg80211_registered_device *rdev;
4533 struct net_device *dev;
4534 int err;
4535
4536 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
4537 return -EINVAL;
4538
4539 if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
4540 return -EINVAL;
4541
4542 rtnl_lock();
4543
4544 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4545 if (err)
4546 goto unlock_rtnl;
4547
4548 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4549 err = -EOPNOTSUPP;
4550 goto out;
4551 }
4552
4553 /* not much point in registering if we can't reply */
4554 if (!rdev->ops->action) {
4555 err = -EOPNOTSUPP;
4556 goto out;
4557 }
4558
4559 err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
4560 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
4561 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
4562 out:
4563 cfg80211_unlock_rdev(rdev);
4564 dev_put(dev);
4565 unlock_rtnl:
4566 rtnl_unlock();
4567 return err;
4568}
4569
4570static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4571{
4572 struct cfg80211_registered_device *rdev;
4573 struct net_device *dev;
4574 struct ieee80211_channel *chan;
4575 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
4576 u32 freq;
4577 int err;
4578 void *hdr;
4579 u64 cookie;
4580 struct sk_buff *msg;
4581
4582 if (!info->attrs[NL80211_ATTR_FRAME] ||
4583 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
4584 return -EINVAL;
4585
4586 rtnl_lock();
4587
4588 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4589 if (err)
4590 goto unlock_rtnl;
4591
4592 if (!rdev->ops->action) {
4593 err = -EOPNOTSUPP;
4594 goto out;
4595 }
4596
4597 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4598 err = -EOPNOTSUPP;
4599 goto out;
4600 }
4601
4602 if (!netif_running(dev)) {
4603 err = -ENETDOWN;
4604 goto out;
4605 }
4606
4607 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
4608 channel_type = nla_get_u32(
4609 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
4610 if (channel_type != NL80211_CHAN_NO_HT &&
4611 channel_type != NL80211_CHAN_HT20 &&
4612 channel_type != NL80211_CHAN_HT40PLUS &&
4613 channel_type != NL80211_CHAN_HT40MINUS)
4614 err = -EINVAL;
4615 goto out;
4616 }
4617
4618 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
4619 chan = rdev_freq_to_chan(rdev, freq, channel_type);
4620 if (chan == NULL) {
4621 err = -EINVAL;
4622 goto out;
4623 }
4624
4625 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4626 if (!msg) {
4627 err = -ENOMEM;
4628 goto out;
4629 }
4630
4631 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4632 NL80211_CMD_ACTION);
4633
4634 if (IS_ERR(hdr)) {
4635 err = PTR_ERR(hdr);
4636 goto free_msg;
4637 }
4638 err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
4639 nla_data(info->attrs[NL80211_ATTR_FRAME]),
4640 nla_len(info->attrs[NL80211_ATTR_FRAME]),
4641 &cookie);
4642 if (err)
4643 goto free_msg;
4644
4645 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
4646
4647 genlmsg_end(msg, hdr);
4648 err = genlmsg_reply(msg, info);
4649 goto out;
4650
4651 nla_put_failure:
4652 err = -ENOBUFS;
4653 free_msg:
4654 nlmsg_free(msg);
4655 out:
4656 cfg80211_unlock_rdev(rdev);
4657 dev_put(dev);
4658unlock_rtnl:
4659 rtnl_unlock();
4660 return err;
4661}
4662
4663static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
4664{
4665 struct cfg80211_registered_device *rdev;
4666 struct wireless_dev *wdev;
4667 struct net_device *dev;
4668 u8 ps_state;
4669 bool state;
4670 int err;
4671
4672 if (!info->attrs[NL80211_ATTR_PS_STATE]) {
4673 err = -EINVAL;
4674 goto out;
4675 }
4676
4677 ps_state = nla_get_u32(info->attrs[NL80211_ATTR_PS_STATE]);
4678
4679 if (ps_state != NL80211_PS_DISABLED && ps_state != NL80211_PS_ENABLED) {
4680 err = -EINVAL;
4681 goto out;
4682 }
4683
4684 rtnl_lock();
4685
4686 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4687 if (err)
4688 goto unlock_rdev;
4689
4690 wdev = dev->ieee80211_ptr;
4691
4692 if (!rdev->ops->set_power_mgmt) {
4693 err = -EOPNOTSUPP;
4694 goto unlock_rdev;
4695 }
4696
4697 state = (ps_state == NL80211_PS_ENABLED) ? true : false;
4698
4699 if (state == wdev->ps)
4700 goto unlock_rdev;
4701
4702 wdev->ps = state;
4703
4704 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, wdev->ps,
4705 wdev->ps_timeout))
4706 /* assume this means it's off */
4707 wdev->ps = false;
4708
4709unlock_rdev:
4710 cfg80211_unlock_rdev(rdev);
4711 dev_put(dev);
4712 rtnl_unlock();
4713
4714out:
4715 return err;
4716}
4717
4718static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
4719{
4720 struct cfg80211_registered_device *rdev;
4721 enum nl80211_ps_state ps_state;
4722 struct wireless_dev *wdev;
4723 struct net_device *dev;
4724 struct sk_buff *msg;
4725 void *hdr;
4726 int err;
4727
4728 rtnl_lock();
4729
4730 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4731 if (err)
4732 goto unlock_rtnl;
4733
4734 wdev = dev->ieee80211_ptr;
4735
4736 if (!rdev->ops->set_power_mgmt) {
4737 err = -EOPNOTSUPP;
4738 goto out;
4739 }
4740
4741 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4742 if (!msg) {
4743 err = -ENOMEM;
4744 goto out;
4745 }
4746
4747 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4748 NL80211_CMD_GET_POWER_SAVE);
4749 if (!hdr) {
4750 err = -ENOMEM;
4751 goto free_msg;
4752 }
4753
4754 if (wdev->ps)
4755 ps_state = NL80211_PS_ENABLED;
4756 else
4757 ps_state = NL80211_PS_DISABLED;
4758
4759 NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state);
4760
4761 genlmsg_end(msg, hdr);
4762 err = genlmsg_reply(msg, info);
4763 goto out;
4764
4765nla_put_failure:
4766 err = -ENOBUFS;
4767
4768free_msg:
4769 nlmsg_free(msg);
4770
4771out:
4772 cfg80211_unlock_rdev(rdev);
4773 dev_put(dev);
4774
4775unlock_rtnl:
4776 rtnl_unlock();
4777
4778 return err;
4779}
4780
4548static struct genl_ops nl80211_ops[] = { 4781static struct genl_ops nl80211_ops[] = {
4549 { 4782 {
4550 .cmd = NL80211_CMD_GET_WIPHY, 4783 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4825,6 +5058,30 @@ static struct genl_ops nl80211_ops[] = {
4825 .policy = nl80211_policy, 5058 .policy = nl80211_policy,
4826 .flags = GENL_ADMIN_PERM, 5059 .flags = GENL_ADMIN_PERM,
4827 }, 5060 },
5061 {
5062 .cmd = NL80211_CMD_REGISTER_ACTION,
5063 .doit = nl80211_register_action,
5064 .policy = nl80211_policy,
5065 .flags = GENL_ADMIN_PERM,
5066 },
5067 {
5068 .cmd = NL80211_CMD_ACTION,
5069 .doit = nl80211_action,
5070 .policy = nl80211_policy,
5071 .flags = GENL_ADMIN_PERM,
5072 },
5073 {
5074 .cmd = NL80211_CMD_SET_POWER_SAVE,
5075 .doit = nl80211_set_power_save,
5076 .policy = nl80211_policy,
5077 .flags = GENL_ADMIN_PERM,
5078 },
5079 {
5080 .cmd = NL80211_CMD_GET_POWER_SAVE,
5081 .doit = nl80211_get_power_save,
5082 .policy = nl80211_policy,
5083 /* can be retrieved by unprivileged users */
5084 },
4828}; 5085};
4829 5086
4830static struct genl_multicast_group nl80211_mlme_mcgrp = { 5087static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5497,6 +5754,110 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
5497 nl80211_mlme_mcgrp.id, gfp); 5754 nl80211_mlme_mcgrp.id, gfp);
5498} 5755}
5499 5756
5757int nl80211_send_action(struct cfg80211_registered_device *rdev,
5758 struct net_device *netdev, u32 nlpid,
5759 int freq, const u8 *buf, size_t len, gfp_t gfp)
5760{
5761 struct sk_buff *msg;
5762 void *hdr;
5763 int err;
5764
5765 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5766 if (!msg)
5767 return -ENOMEM;
5768
5769 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
5770 if (!hdr) {
5771 nlmsg_free(msg);
5772 return -ENOMEM;
5773 }
5774
5775 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5776 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5777 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
5778 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5779
5780 err = genlmsg_end(msg, hdr);
5781 if (err < 0) {
5782 nlmsg_free(msg);
5783 return err;
5784 }
5785
5786 err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
5787 if (err < 0)
5788 return err;
5789 return 0;
5790
5791 nla_put_failure:
5792 genlmsg_cancel(msg, hdr);
5793 nlmsg_free(msg);
5794 return -ENOBUFS;
5795}
5796
5797void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5798 struct net_device *netdev, u64 cookie,
5799 const u8 *buf, size_t len, bool ack,
5800 gfp_t gfp)
5801{
5802 struct sk_buff *msg;
5803 void *hdr;
5804
5805 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5806 if (!msg)
5807 return;
5808
5809 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
5810 if (!hdr) {
5811 nlmsg_free(msg);
5812 return;
5813 }
5814
5815 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5816 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5817 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5818 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5819 if (ack)
5820 NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
5821
5822 if (genlmsg_end(msg, hdr) < 0) {
5823 nlmsg_free(msg);
5824 return;
5825 }
5826
5827 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
5828 return;
5829
5830 nla_put_failure:
5831 genlmsg_cancel(msg, hdr);
5832 nlmsg_free(msg);
5833}
5834
5835static int nl80211_netlink_notify(struct notifier_block * nb,
5836 unsigned long state,
5837 void *_notify)
5838{
5839 struct netlink_notify *notify = _notify;
5840 struct cfg80211_registered_device *rdev;
5841 struct wireless_dev *wdev;
5842
5843 if (state != NETLINK_URELEASE)
5844 return NOTIFY_DONE;
5845
5846 rcu_read_lock();
5847
5848 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
5849 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
5850 cfg80211_mlme_unregister_actions(wdev, notify->pid);
5851
5852 rcu_read_unlock();
5853
5854 return NOTIFY_DONE;
5855}
5856
5857static struct notifier_block nl80211_netlink_notifier = {
5858 .notifier_call = nl80211_netlink_notify,
5859};
5860
5500/* initialisation/exit functions */ 5861/* initialisation/exit functions */
5501 5862
5502int nl80211_init(void) 5863int nl80211_init(void)
@@ -5530,6 +5891,10 @@ int nl80211_init(void)
5530 goto err_out; 5891 goto err_out;
5531#endif 5892#endif
5532 5893
5894 err = netlink_register_notifier(&nl80211_netlink_notifier);
5895 if (err)
5896 goto err_out;
5897
5533 return 0; 5898 return 0;
5534 err_out: 5899 err_out:
5535 genl_unregister_family(&nl80211_fam); 5900 genl_unregister_family(&nl80211_fam);
@@ -5538,5 +5903,6 @@ int nl80211_init(void)
5538 5903
5539void nl80211_exit(void) 5904void nl80211_exit(void)
5540{ 5905{
5906 netlink_unregister_notifier(&nl80211_netlink_notifier);
5541 genl_unregister_family(&nl80211_fam); 5907 genl_unregister_family(&nl80211_fam);
5542} 5908}