aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/nl80211.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-08-12 09:38:38 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-24 16:27:56 -0400
commit2e161f78e5f63a7f9fd25a766bb7f816a01eb14a (patch)
treebefd44feeb1f47da1f41e6fc310a223ad67030ff /net/wireless/nl80211.c
parentac4c977d16d843f12901595c91773dddb65768a9 (diff)
cfg80211/mac80211: extensible frame processing
Allow userspace to register for more than just action frames by giving the frame subtype, and make it possible to use this in various modes as well. With some tweaks and some added functionality this will, in the future, also be usable in AP mode and be able to replace the cooked monitor interface currently used in that case. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/nl80211.c')
-rw-r--r--net/wireless/nl80211.c108
1 files changed, 80 insertions, 28 deletions
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index bb5b78eebeb2..927ffbd2aebc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -156,6 +156,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
156 156
157 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 }, 157 [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
158 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 }, 158 [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
159 [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
159}; 160};
160 161
161/* policy for the attributes */ 162/* policy for the attributes */
@@ -437,6 +438,8 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
437 struct ieee80211_rate *rate; 438 struct ieee80211_rate *rate;
438 int i; 439 int i;
439 u16 ifmodes = dev->wiphy.interface_modes; 440 u16 ifmodes = dev->wiphy.interface_modes;
441 const struct ieee80211_txrx_stypes *mgmt_stypes =
442 dev->wiphy.mgmt_stypes;
440 443
441 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); 444 hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
442 if (!hdr) 445 if (!hdr)
@@ -587,7 +590,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
587 CMD(flush_pmksa, FLUSH_PMKSA); 590 CMD(flush_pmksa, FLUSH_PMKSA);
588 CMD(remain_on_channel, REMAIN_ON_CHANNEL); 591 CMD(remain_on_channel, REMAIN_ON_CHANNEL);
589 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK); 592 CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
590 CMD(action, ACTION); 593 CMD(mgmt_tx, FRAME);
591 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { 594 if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
592 i++; 595 i++;
593 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); 596 NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -608,6 +611,53 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
608 611
609 nla_nest_end(msg, nl_cmds); 612 nla_nest_end(msg, nl_cmds);
610 613
614 if (mgmt_stypes) {
615 u16 stypes;
616 struct nlattr *nl_ftypes, *nl_ifs;
617 enum nl80211_iftype ift;
618
619 nl_ifs = nla_nest_start(msg, NL80211_ATTR_TX_FRAME_TYPES);
620 if (!nl_ifs)
621 goto nla_put_failure;
622
623 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
624 nl_ftypes = nla_nest_start(msg, ift);
625 if (!nl_ftypes)
626 goto nla_put_failure;
627 i = 0;
628 stypes = mgmt_stypes[ift].tx;
629 while (stypes) {
630 if (stypes & 1)
631 NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
632 (i << 4) | IEEE80211_FTYPE_MGMT);
633 stypes >>= 1;
634 i++;
635 }
636 nla_nest_end(msg, nl_ftypes);
637 }
638
639 nl_ifs = nla_nest_start(msg, NL80211_ATTR_RX_FRAME_TYPES);
640 if (!nl_ifs)
641 goto nla_put_failure;
642
643 for (ift = 0; ift < NUM_NL80211_IFTYPES; ift++) {
644 nl_ftypes = nla_nest_start(msg, ift);
645 if (!nl_ftypes)
646 goto nla_put_failure;
647 i = 0;
648 stypes = mgmt_stypes[ift].rx;
649 while (stypes) {
650 if (stypes & 1)
651 NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE,
652 (i << 4) | IEEE80211_FTYPE_MGMT);
653 stypes >>= 1;
654 i++;
655 }
656 nla_nest_end(msg, nl_ftypes);
657 }
658 nla_nest_end(msg, nl_ifs);
659 }
660
611 return genlmsg_end(msg, hdr); 661 return genlmsg_end(msg, hdr);
612 662
613 nla_put_failure: 663 nla_put_failure:
@@ -4732,17 +4782,18 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb,
4732 return err; 4782 return err;
4733} 4783}
4734 4784
4735static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) 4785static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info)
4736{ 4786{
4737 struct cfg80211_registered_device *rdev; 4787 struct cfg80211_registered_device *rdev;
4738 struct net_device *dev; 4788 struct net_device *dev;
4789 u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION;
4739 int err; 4790 int err;
4740 4791
4741 if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) 4792 if (!info->attrs[NL80211_ATTR_FRAME_MATCH])
4742 return -EINVAL; 4793 return -EINVAL;
4743 4794
4744 if (nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]) < 1) 4795 if (info->attrs[NL80211_ATTR_FRAME_TYPE])
4745 return -EINVAL; 4796 frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]);
4746 4797
4747 rtnl_lock(); 4798 rtnl_lock();
4748 4799
@@ -4757,12 +4808,13 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4757 } 4808 }
4758 4809
4759 /* not much point in registering if we can't reply */ 4810 /* not much point in registering if we can't reply */
4760 if (!rdev->ops->action) { 4811 if (!rdev->ops->mgmt_tx) {
4761 err = -EOPNOTSUPP; 4812 err = -EOPNOTSUPP;
4762 goto out; 4813 goto out;
4763 } 4814 }
4764 4815
4765 err = cfg80211_mlme_register_action(dev->ieee80211_ptr, info->snd_pid, 4816 err = cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid,
4817 frame_type,
4766 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), 4818 nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]),
4767 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); 4819 nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH]));
4768 out: 4820 out:
@@ -4773,7 +4825,7 @@ static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info)
4773 return err; 4825 return err;
4774} 4826}
4775 4827
4776static int nl80211_action(struct sk_buff *skb, struct genl_info *info) 4828static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
4777{ 4829{
4778 struct cfg80211_registered_device *rdev; 4830 struct cfg80211_registered_device *rdev;
4779 struct net_device *dev; 4831 struct net_device *dev;
@@ -4796,7 +4848,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4796 if (err) 4848 if (err)
4797 goto unlock_rtnl; 4849 goto unlock_rtnl;
4798 4850
4799 if (!rdev->ops->action) { 4851 if (!rdev->ops->mgmt_tx) {
4800 err = -EOPNOTSUPP; 4852 err = -EOPNOTSUPP;
4801 goto out; 4853 goto out;
4802 } 4854 }
@@ -4839,17 +4891,17 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
4839 } 4891 }
4840 4892
4841 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, 4893 hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
4842 NL80211_CMD_ACTION); 4894 NL80211_CMD_FRAME);
4843 4895
4844 if (IS_ERR(hdr)) { 4896 if (IS_ERR(hdr)) {
4845 err = PTR_ERR(hdr); 4897 err = PTR_ERR(hdr);
4846 goto free_msg; 4898 goto free_msg;
4847 } 4899 }
4848 err = cfg80211_mlme_action(rdev, dev, chan, channel_type, 4900 err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
4849 channel_type_valid, 4901 channel_type_valid,
4850 nla_data(info->attrs[NL80211_ATTR_FRAME]), 4902 nla_data(info->attrs[NL80211_ATTR_FRAME]),
4851 nla_len(info->attrs[NL80211_ATTR_FRAME]), 4903 nla_len(info->attrs[NL80211_ATTR_FRAME]),
4852 &cookie); 4904 &cookie);
4853 if (err) 4905 if (err)
4854 goto free_msg; 4906 goto free_msg;
4855 4907
@@ -5348,14 +5400,14 @@ static struct genl_ops nl80211_ops[] = {
5348 .flags = GENL_ADMIN_PERM, 5400 .flags = GENL_ADMIN_PERM,
5349 }, 5401 },
5350 { 5402 {
5351 .cmd = NL80211_CMD_REGISTER_ACTION, 5403 .cmd = NL80211_CMD_REGISTER_FRAME,
5352 .doit = nl80211_register_action, 5404 .doit = nl80211_register_mgmt,
5353 .policy = nl80211_policy, 5405 .policy = nl80211_policy,
5354 .flags = GENL_ADMIN_PERM, 5406 .flags = GENL_ADMIN_PERM,
5355 }, 5407 },
5356 { 5408 {
5357 .cmd = NL80211_CMD_ACTION, 5409 .cmd = NL80211_CMD_FRAME,
5358 .doit = nl80211_action, 5410 .doit = nl80211_tx_mgmt,
5359 .policy = nl80211_policy, 5411 .policy = nl80211_policy,
5360 .flags = GENL_ADMIN_PERM, 5412 .flags = GENL_ADMIN_PERM,
5361 }, 5413 },
@@ -6055,9 +6107,9 @@ void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
6055 nl80211_mlme_mcgrp.id, gfp); 6107 nl80211_mlme_mcgrp.id, gfp);
6056} 6108}
6057 6109
6058int nl80211_send_action(struct cfg80211_registered_device *rdev, 6110int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
6059 struct net_device *netdev, u32 nlpid, 6111 struct net_device *netdev, u32 nlpid,
6060 int freq, const u8 *buf, size_t len, gfp_t gfp) 6112 int freq, const u8 *buf, size_t len, gfp_t gfp)
6061{ 6113{
6062 struct sk_buff *msg; 6114 struct sk_buff *msg;
6063 void *hdr; 6115 void *hdr;
@@ -6067,7 +6119,7 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
6067 if (!msg) 6119 if (!msg)
6068 return -ENOMEM; 6120 return -ENOMEM;
6069 6121
6070 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION); 6122 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
6071 if (!hdr) { 6123 if (!hdr) {
6072 nlmsg_free(msg); 6124 nlmsg_free(msg);
6073 return -ENOMEM; 6125 return -ENOMEM;
@@ -6095,10 +6147,10 @@ int nl80211_send_action(struct cfg80211_registered_device *rdev,
6095 return -ENOBUFS; 6147 return -ENOBUFS;
6096} 6148}
6097 6149
6098void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, 6150void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
6099 struct net_device *netdev, u64 cookie, 6151 struct net_device *netdev, u64 cookie,
6100 const u8 *buf, size_t len, bool ack, 6152 const u8 *buf, size_t len, bool ack,
6101 gfp_t gfp) 6153 gfp_t gfp)
6102{ 6154{
6103 struct sk_buff *msg; 6155 struct sk_buff *msg;
6104 void *hdr; 6156 void *hdr;
@@ -6107,7 +6159,7 @@ void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev,
6107 if (!msg) 6159 if (!msg)
6108 return; 6160 return;
6109 6161
6110 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ACTION_TX_STATUS); 6162 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME_TX_STATUS);
6111 if (!hdr) { 6163 if (!hdr) {
6112 nlmsg_free(msg); 6164 nlmsg_free(msg);
6113 return; 6165 return;
@@ -6194,7 +6246,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
6194 6246
6195 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) 6247 list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list)
6196 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) 6248 list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
6197 cfg80211_mlme_unregister_actions(wdev, notify->pid); 6249 cfg80211_mlme_unregister_socket(wdev, notify->pid);
6198 6250
6199 rcu_read_unlock(); 6251 rcu_read_unlock();
6200 6252