diff options
author | Johannes Berg <johannes.berg@intel.com> | 2010-08-12 09:38:38 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-08-24 16:27:56 -0400 |
commit | 2e161f78e5f63a7f9fd25a766bb7f816a01eb14a (patch) | |
tree | befd44feeb1f47da1f41e6fc310a223ad67030ff /net/wireless/nl80211.c | |
parent | ac4c977d16d843f12901595c91773dddb65768a9 (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.c | 108 |
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 | ||
4735 | static int nl80211_register_action(struct sk_buff *skb, struct genl_info *info) | 4785 | static 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 | ||
4776 | static int nl80211_action(struct sk_buff *skb, struct genl_info *info) | 4828 | static 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 | ||
6058 | int nl80211_send_action(struct cfg80211_registered_device *rdev, | 6110 | int 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 | ||
6098 | void nl80211_send_action_tx_status(struct cfg80211_registered_device *rdev, | 6150 | void 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 | ||