aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/core.h9
-rw-r--r--net/wireless/mlme.c166
-rw-r--r--net/wireless/nl80211.c260
-rw-r--r--net/wireless/nl80211.h8
5 files changed, 446 insertions, 1 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 71b6b3a9cf1f..51908dc2ea00 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++;
@@ -792,6 +795,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
792 sysfs_remove_link(&dev->dev.kobj, "phy80211"); 795 sysfs_remove_link(&dev->dev.kobj, "phy80211");
793 list_del_rcu(&wdev->list); 796 list_del_rcu(&wdev->list);
794 rdev->devlist_generation++; 797 rdev->devlist_generation++;
798 cfg80211_mlme_purge_actions(wdev);
795#ifdef CONFIG_CFG80211_WEXT 799#ifdef CONFIG_CFG80211_WEXT
796 kfree(wdev->wext.keys); 800 kfree(wdev->wext.keys);
797#endif 801#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 a95ab9e4c19e..328112081358 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,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
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, },
148}; 151};
149 152
150/* policy for the attributes */ 153/* policy for the attributes */
@@ -577,6 +580,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
577 CMD(flush_pmksa, FLUSH_PMKSA); 580 CMD(flush_pmksa, FLUSH_PMKSA);
578 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 581 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
579 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); 582 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
583 CMD(action, ACTION);
580 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 584 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
581 i++; 585 i++;
582 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 586 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -4526,6 +4530,139 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4526 return err; 4530 return err;
4527} 4531}
4528 4532
4533static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4534{
4535 struct cfg80211_registered_device *rdev;
4536 struct net_device *dev;
4537 int err;
4538
4539 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
4540 return -EINVAL;
4541
4542 if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1)
4543 return -EINVAL;
4544
4545 rtnl_lock();
4546
4547 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4548 if (err)
4549 goto unlock_rtnl;
4550
4551 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4552 err = -EOPNOTSUPP;
4553 goto out;
4554 }
4555
4556 /* not much point in registering if we can't reply */
4557 if (!rdev->ops->action) {
4558 err = -EOPNOTSUPP;
4559 goto out;
4560 }
4561
4562 err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid,
4563 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
4564 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
4565 out:
4566 cfg80211_unlock_rdev(rdev);
4567 dev_put(dev);
4568 unlock_rtnl:
4569 rtnl_unlock();
4570 return err;
4571}
4572
4573static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4574{
4575 struct cfg80211_registered_device *rdev;
4576 struct net_device *dev;
4577 struct ieee80211_channel *chan;
4578 enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
4579 u32 freq;
4580 int err;
4581 void *hdr;
4582 u64 cookie;
4583 struct sk_buff *msg;
4584
4585 if (!info->attrs[NL80211_ATTR_FRAME] ||
4586 !info->attrs[NL80211_ATTR_WIPHY_FREQ])
4587 return -EINVAL;
4588
4589 rtnl_lock();
4590
4591 err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
4592 if (err)
4593 goto unlock_rtnl;
4594
4595 if (!rdev->ops->action) {
4596 err = -EOPNOTSUPP;
4597 goto out;
4598 }
4599
4600 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) {
4601 err = -EOPNOTSUPP;
4602 goto out;
4603 }
4604
4605 if (!netif_running(dev)) {
4606 err = -ENETDOWN;
4607 goto out;
4608 }
4609
4610 if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
4611 channel_type = nla_get_u32(
4612 info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
4613 if (channel_type != NL80211_CHAN_NO_HT &&
4614 channel_type != NL80211_CHAN_HT20 &&
4615 channel_type != NL80211_CHAN_HT40PLUS &&
4616 channel_type != NL80211_CHAN_HT40MINUS)
4617 err = -EINVAL;
4618 goto out;
4619 }
4620
4621 freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
4622 chan = rdev_freq_to_chan(rdev, freq, channel_type);
4623 if (chan == NULL) {
4624 err = -EINVAL;
4625 goto out;
4626 }
4627
4628 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4629 if (!msg) {
4630 err = -ENOMEM;
4631 goto out;
4632 }
4633
4634 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4635 NL80211_CMD_ACTION);
4636
4637 if (IS_ERR(hdr)) {
4638 err = PTR_ERR(hdr);
4639 goto free_msg;
4640 }
4641 err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
4642 nla_data(info->attrs[NL80211_ATTR_FRAME]),
4643 nla_len(info->attrs[NL80211_ATTR_FRAME]),
4644 &cookie);
4645 if (err)
4646 goto free_msg;
4647
4648 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
4649
4650 genlmsg_end(msg, hdr);
4651 err = genlmsg_reply(msg, info);
4652 goto out;
4653
4654 nla_put_failure:
4655 err = -ENOBUFS;
4656 free_msg:
4657 nlmsg_free(msg);
4658 out:
4659 cfg80211_unlock_rdev(rdev);
4660 dev_put(dev);
4661unlock_rtnl:
4662 rtnl_unlock();
4663 return err;
4664}
4665
4529static struct genl_ops nl80211_ops[] = { 4666static struct genl_ops nl80211_ops[] = {
4530 { 4667 {
4531 .cmd = NL80211_CMD_GET_WIPHY, 4668 .cmd = NL80211_CMD_GET_WIPHY,
@@ -4806,6 +4943,18 @@ static struct genl_ops nl80211_ops[] = {
4806 .policy = nl80211_policy, 4943 .policy = nl80211_policy,
4807 .flags = GENL_ADMIN_PERM, 4944 .flags = GENL_ADMIN_PERM,
4808 }, 4945 },
4946 {
4947 .cmd = NL80211_CMD_REGISTER_ACTION,
4948 .doit = nl80211_register_action,
4949 .policy = nl80211_policy,
4950 .flags = GENL_ADMIN_PERM,
4951 },
4952 {
4953 .cmd = NL80211_CMD_ACTION,
4954 .doit = nl80211_action,
4955 .policy = nl80211_policy,
4956 .flags = GENL_ADMIN_PERM,
4957 },
4809}; 4958};
4810 4959
4811static struct genl_multicast_group nl80211_mlme_mcgrp = { 4960static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5478,6 +5627,110 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
5478 nl80211_mlme_mcgrp.id, gfp); 5627 nl80211_mlme_mcgrp.id, gfp);
5479} 5628}
5480 5629
5630int nl80211_send_action(struct cfg80211_registered_device *rdev,
5631 struct net_device *netdev, u32 nlpid,
5632 int freq, const u8 *buf, size_t len, gfp_t gfp)
5633{
5634 struct sk_buff *msg;
5635 void *hdr;
5636 int err;
5637
5638 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5639 if (!msg)
5640 return -ENOMEM;
5641
5642 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION);
5643 if (!hdr) {
5644 nlmsg_free(msg);
5645 return -ENOMEM;
5646 }
5647
5648 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5649 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5650 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
5651 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5652
5653 err = genlmsg_end(msg, hdr);
5654 if (err < 0) {
5655 nlmsg_free(msg);
5656 return err;
5657 }
5658
5659 err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
5660 if (err < 0)
5661 return err;
5662 return 0;
5663
5664 nla_put_failure:
5665 genlmsg_cancel(msg, hdr);
5666 nlmsg_free(msg);
5667 return -ENOBUFS;
5668}
5669
5670void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
5671 struct net_device *netdev, u64 cookie,
5672 const u8 *buf, size_t len, bool ack,
5673 gfp_t gfp)
5674{
5675 struct sk_buff *msg;
5676 void *hdr;
5677
5678 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
5679 if (!msg)
5680 return;
5681
5682 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS);
5683 if (!hdr) {
5684 nlmsg_free(msg);
5685 return;
5686 }
5687
5688 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
5689 NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
5690 NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
5691 NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
5692 if (ack)
5693 NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
5694
5695 if (genlmsg_end(msg, hdr) < 0) {
5696 nlmsg_free(msg);
5697 return;
5698 }
5699
5700 genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
5701 return;
5702
5703 nla_put_failure:
5704 genlmsg_cancel(msg, hdr);
5705 nlmsg_free(msg);
5706}
5707
5708static int nl80211_netlink_notify(struct notifier_block * nb,
5709 unsigned long state,
5710 void *_notify)
5711{
5712 struct netlink_notify *notify = _notify;
5713 struct cfg80211_registered_device *rdev;
5714 struct wireless_dev *wdev;
5715
5716 if (state != NETLINK_URELEASE)
5717 return NOTIFY_DONE;
5718
5719 rcu_read_lock();
5720
5721 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
5722 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
5723 cfg80211_mlme_unregister_actions(wdev, notify->pid);
5724
5725 rcu_read_unlock();
5726
5727 return NOTIFY_DONE;
5728}
5729
5730static struct notifier_block nl80211_netlink_notifier = {
5731 .notifier_call = nl80211_netlink_notify,
5732};
5733
5481/* initialisation/exit functions */ 5734/* initialisation/exit functions */
5482 5735
5483int nl80211_init(void) 5736int nl80211_init(void)
@@ -5511,6 +5764,10 @@ int nl80211_init(void)
5511 goto err_out; 5764 goto err_out;
5512#endif 5765#endif
5513 5766
5767 err = netlink_register_notifier(&nl80211_netlink_notifier);
5768 if (err)
5769 goto err_out;
5770
5514 return 0; 5771 return 0;
5515 err_out: 5772 err_out:
5516 genl_unregister_family(&nl80211_fam); 5773 genl_unregister_family(&nl80211_fam);
@@ -5519,5 +5776,6 @@ int nl80211_init(void)
5519 5776
5520void nl80211_exit(void) 5777void nl80211_exit(void)
5521{ 5778{
5779 netlink_unregister_notifier(&nl80211_netlink_notifier);
5522 genl_unregister_family(&nl80211_fam); 5780 genl_unregister_family(&nl80211_fam);
5523} 5781}
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 */