aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
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
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')
-rw-r--r--net/wireless/core.c20
-rw-r--r--net/wireless/core.h9
-rw-r--r--net/wireless/mlme.c166
-rw-r--r--net/wireless/nl80211.c440
-rw-r--r--net/wireless/nl80211.h8
-rw-r--r--net/wireless/wext-compat.c10
6 files changed, 604 insertions, 49 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 71b6b3a9cf1f..7fdb9409ad2a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -677,6 +677,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
677 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work); 677 INIT_WORK(&wdev->cleanup_work, wdev_cleanup_work);
678 INIT_LIST_HEAD(&wdev->event_list); 678 INIT_LIST_HEAD(&wdev->event_list);
679 spin_lock_init(&wdev->event_lock); 679 spin_lock_init(&wdev->event_lock);
680 INIT_LIST_HEAD(&wdev->action_registrations);
681 spin_lock_init(&wdev->action_registrations_lock);
682
680 mutex_lock(&rdev->devlist_mtx); 683 mutex_lock(&rdev->devlist_mtx);
681 list_add_rcu(&wdev->list, &rdev->netdev_list); 684 list_add_rcu(&wdev->list, &rdev->netdev_list);
682 rdev->devlist_generation++; 685 rdev->devlist_generation++;
@@ -695,19 +698,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
695 wdev->wext.default_key = -1; 698 wdev->wext.default_key = -1;
696 wdev->wext.default_mgmt_key = -1; 699 wdev->wext.default_mgmt_key = -1;
697 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; 700 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
701#endif
702
698 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT) 703 if (wdev->wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT)
699 wdev->wext.ps = true; 704 wdev->ps = true;
700 else 705 else
701 wdev->wext.ps = false; 706 wdev->ps = false;
702 wdev->wext.ps_timeout = 100; 707 wdev->ps_timeout = 100;
703 if (rdev->ops->set_power_mgmt) 708 if (rdev->ops->set_power_mgmt)
704 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev, 709 if (rdev->ops->set_power_mgmt(wdev->wiphy, dev,
705 wdev->wext.ps, 710 wdev->ps,
706 wdev->wext.ps_timeout)) { 711 wdev->ps_timeout)) {
707 /* assume this means it's off */ 712 /* assume this means it's off */
708 wdev->wext.ps = false; 713 wdev->ps = false;
709 } 714 }
710#endif 715
711 if (!dev->ethtool_ops) 716 if (!dev->ethtool_ops)
712 dev->ethtool_ops = &cfg80211_ethtool_ops; 717 dev->ethtool_ops = &cfg80211_ethtool_ops;
713 718
@@ -792,6 +797,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
792 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 797 sysfs_remove_link(&dev->dev.kobj, "phy80211");
793 list_del_rcu(&wdev->list); 798 list_del_rcu(&wdev->list);
794 rdev->devlist_generation++; 799 rdev->devlist_generation++;
800 cfg80211_mlme_purge_actions(wdev);
795#ifdef CONFIG_CFG80211_WEXT 801#ifdef CONFIG_CFG80211_WEXT
796 kfree(wdev->wext.keys); 802 kfree(wdev->wext.keys);
797#endif 803#endif
diff --git a/net/wireless/core.h b/net/wireless/core.h
index c326a667022a..d52da913145a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -329,6 +329,15 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
329 const u8 *resp_ie, size_t resp_ie_len, 329 const u8 *resp_ie, size_t resp_ie_len,
330 u16 status, bool wextev, 330 u16 status, bool wextev,
331 struct cfg80211_bss *bss); 331 struct cfg80211_bss *bss);
332int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
333 const u8 *match_data, int match_len);
334void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid);
335void cfg80211_mlme_purge_actions(struct wireless_dev *wdev);
336int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
337 struct net_device *dev,
338 struct ieee80211_channel *chan,
339 enum nl80211_channel_type channel_type,
340 const u8 *buf, size_t len, u64 *cookie);
332 341
333/* SME */ 342/* SME */
334int __cfg80211_connect(struct cfg80211_registered_device *rdev, 343int __cfg80211_connect(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 94d151f6f73e..62bc8855e123 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -728,3 +728,169 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
728 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); 728 nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp);
729} 729}
730EXPORT_SYMBOL(cfg80211_new_sta); 730EXPORT_SYMBOL(cfg80211_new_sta);
731
732struct cfg80211_action_registration {
733 struct list_head list;
734
735 u32 nlpid;
736
737 int match_len;
738
739 u8 match[];
740};
741
742int cfg80211_mlme_register_action(struct wireless_dev *wdev, u32 snd_pid,
743 const u8 *match_data, int match_len)
744{
745 struct cfg80211_action_registration *reg, *nreg;
746 int err = 0;
747
748 nreg = kzalloc(sizeof(*reg) + match_len, GFP_KERNEL);
749 if (!nreg)
750 return -ENOMEM;
751
752 spin_lock_bh(&wdev->action_registrations_lock);
753
754 list_for_each_entry(reg, &wdev->action_registrations, list) {
755 int mlen = min(match_len, reg->match_len);
756
757 if (memcmp(reg->match, match_data, mlen) == 0) {
758 err = -EALREADY;
759 break;
760 }
761 }
762
763 if (err) {
764 kfree(nreg);
765 goto out;
766 }
767
768 memcpy(nreg->match, match_data, match_len);
769 nreg->match_len = match_len;
770 nreg->nlpid = snd_pid;
771 list_add(&nreg->list, &wdev->action_registrations);
772
773 out:
774 spin_unlock_bh(&wdev->action_registrations_lock);
775 return err;
776}
777
778void cfg80211_mlme_unregister_actions(struct wireless_dev *wdev, u32 nlpid)
779{
780 struct cfg80211_action_registration *reg, *tmp;
781
782 spin_lock_bh(&wdev->action_registrations_lock);
783
784 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
785 if (reg->nlpid == nlpid) {
786 list_del(&reg->list);
787 kfree(reg);
788 }
789 }
790
791 spin_unlock_bh(&wdev->action_registrations_lock);
792}
793
794void cfg80211_mlme_purge_actions(struct wireless_dev *wdev)
795{
796 struct cfg80211_action_registration *reg, *tmp;
797
798 spin_lock_bh(&wdev->action_registrations_lock);
799
800 list_for_each_entry_safe(reg, tmp, &wdev->action_registrations, list) {
801 list_del(&reg->list);
802 kfree(reg);
803 }
804
805 spin_unlock_bh(&wdev->action_registrations_lock);
806}
807
808int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
809 struct net_device *dev,
810 struct ieee80211_channel *chan,
811 enum nl80211_channel_type channel_type,
812 const u8 *buf, size_t len, u64 *cookie)
813{
814 struct wireless_dev *wdev = dev->ieee80211_ptr;
815 const struct ieee80211_mgmt *mgmt;
816
817 if (rdev->ops->action == NULL)
818 return -EOPNOTSUPP;
819 if (len < 24 + 1)
820 return -EINVAL;
821
822 mgmt = (const struct ieee80211_mgmt *) buf;
823 if (!ieee80211_is_action(mgmt->frame_control))
824 return -EINVAL;
825 if (mgmt->u.action.category != WLAN_CATEGORY_PUBLIC) {
826 /* Verify that we are associated with the destination AP */
827 if (!wdev->current_bss ||
828 memcmp(wdev->current_bss->pub.bssid, mgmt->bssid,
829 ETH_ALEN) != 0 ||
830 memcmp(wdev->current_bss->pub.bssid, mgmt->da,
831 ETH_ALEN) != 0)
832 return -ENOTCONN;
833 }
834
835 if (memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0)
836 return -EINVAL;
837
838 /* Transmit the Action frame as requested by user space */
839 return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
840 buf, len, cookie);
841}
842
843bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
844 size_t len, gfp_t gfp)
845{
846 struct wireless_dev *wdev = dev->ieee80211_ptr;
847 struct wiphy *wiphy = wdev->wiphy;
848 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
849 struct cfg80211_action_registration *reg;
850 const u8 *action_data;
851 int action_data_len;
852 bool result = false;
853
854 /* frame length - min size excluding category */
855 action_data_len = len - (IEEE80211_MIN_ACTION_SIZE - 1);
856
857 /* action data starts with category */
858 action_data = buf + IEEE80211_MIN_ACTION_SIZE - 1;
859
860 spin_lock_bh(&wdev->action_registrations_lock);
861
862 list_for_each_entry(reg, &wdev->action_registrations, list) {
863 if (reg->match_len > action_data_len)
864 continue;
865
866 if (memcmp(reg->match, action_data, reg->match_len))
867 continue;
868
869 /* found match! */
870
871 /* Indicate the received Action frame to user space */
872 if (nl80211_send_action(rdev, dev, reg->nlpid, freq,
873 buf, len, gfp))
874 continue;
875
876 result = true;
877 break;
878 }
879
880 spin_unlock_bh(&wdev->action_registrations_lock);
881
882 return result;
883}
884EXPORT_SYMBOL(cfg80211_rx_action);
885
886void cfg80211_action_tx_status(struct net_device *dev, u64 cookie,
887 const u8 *buf, size_t len, bool ack, gfp_t gfp)
888{
889 struct wireless_dev *wdev = dev->ieee80211_ptr;
890 struct wiphy *wiphy = wdev->wiphy;
891 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
892
893 /* Indicate TX status of the Action frame to user space */
894 nl80211_send_action_tx_status(rdev, dev, cookie, buf, len, ack, gfp);
895}
896EXPORT_SYMBOL(cfg80211_action_tx_status);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a001ea32cb7d..e447db04cf76 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}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 14855b8fb430..4ca511102c6c 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -74,4 +74,12 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
74 struct net_device *dev, const u8 *mac_addr, 74 struct net_device *dev, const u8 *mac_addr,
75 struct station_info *sinfo, gfp_t gfp); 75 struct station_info *sinfo, gfp_t gfp);
76 76
77int nl80211_send_action(struct cfg80211_registered_device *rdev,
78 struct net_device *netdev, u32 nlpid, int freq,
79 const u8 *buf, size_t len, gfp_t gfp);
80void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
81 struct net_device *netdev, u64 cookie,
82 const u8 *buf, size_t len, bool ack,
83 gfp_t gfp);
84
77#endif /* __NET_WIRELESS_NL80211_H */ 85#endif /* __NET_WIRELESS_NL80211_H */
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index b17eeae448d5..9ab51838849e 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -1099,8 +1099,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1099{ 1099{
1100 struct wireless_dev *wdev = dev->ieee80211_ptr; 1100 struct wireless_dev *wdev = dev->ieee80211_ptr;
1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 1101 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
1102 bool ps = wdev->wext.ps; 1102 bool ps = wdev->ps;
1103 int timeout = wdev->wext.ps_timeout; 1103 int timeout = wdev->ps_timeout;
1104 int err; 1104 int err;
1105 1105
1106 if (wdev->iftype != NL80211_IFTYPE_STATION) 1106 if (wdev->iftype != NL80211_IFTYPE_STATION)
@@ -1133,8 +1133,8 @@ int cfg80211_wext_siwpower(struct net_device *dev,
1133 if (err) 1133 if (err)
1134 return err; 1134 return err;
1135 1135
1136 wdev->wext.ps = ps; 1136 wdev->ps = ps;
1137 wdev->wext.ps_timeout = timeout; 1137 wdev->ps_timeout = timeout;
1138 1138
1139 return 0; 1139 return 0;
1140 1140
@@ -1147,7 +1147,7 @@ int cfg80211_wext_giwpower(struct net_device *dev,
1147{ 1147{
1148 struct wireless_dev *wdev = dev->ieee80211_ptr; 1148 struct wireless_dev *wdev = dev->ieee80211_ptr;
1149 1149
1150 wrq->disabled = !wdev->wext.ps; 1150 wrq->disabled = !wdev->ps;
1151 1151
1152 return 0; 1152 return 0;
1153} 1153}