aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2016-05-14 04:34:44 -0400
committerJohannes Berg <johannes@sipsolutions.net>2016-06-30 06:06:17 -0400
commitf21e4d8ed16bb9cae27c7f1a07a2e0cd4daab736 (patch)
tree3ba49aa3a9adf34baeaf0d4e37e28a1f4f8b5699 /drivers
parentee58b57100ca953da7320c285315a95db2f7053d (diff)
mac80211_hwsim: Allow wmediumd to attach to radios created in its netns
Registering wmediumd is currently limited to the initial network namespace. This patch enables wmediumd to attach from non-initial network namespaces using a user namespace having CAP_NET_ADMIN. A registered wmediumd can forward frames on radios that have been created in the same network namespace, even if they have been moved to other network namespaces. The wmediumd Netlink portid is tracked per net namespace. Additionally, the portid is stored on all radios created in that net namespace to simplify the portid lookup in the data path. Signed-off-by: Martin Willi <martin@strongswan.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c92
1 files changed, 76 insertions, 16 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a1e28a4fd658..382109bbc2c1 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -41,8 +41,6 @@ MODULE_AUTHOR("Jouni Malinen");
41MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); 41MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
42MODULE_LICENSE("GPL"); 42MODULE_LICENSE("GPL");
43 43
44static u32 wmediumd_portid;
45
46static int radios = 2; 44static int radios = 2;
47module_param(radios, int, 0444); 45module_param(radios, int, 0444);
48MODULE_PARM_DESC(radios, "Number of simulated radios"); 46MODULE_PARM_DESC(radios, "Number of simulated radios");
@@ -258,6 +256,7 @@ static int hwsim_netgroup;
258 256
259struct hwsim_net { 257struct hwsim_net {
260 int netgroup; 258 int netgroup;
259 u32 wmediumd;
261}; 260};
262 261
263static inline int hwsim_net_get_netgroup(struct net *net) 262static inline int hwsim_net_get_netgroup(struct net *net)
@@ -274,6 +273,20 @@ static inline void hwsim_net_set_netgroup(struct net *net)
274 hwsim_net->netgroup = hwsim_netgroup++; 273 hwsim_net->netgroup = hwsim_netgroup++;
275} 274}
276 275
276static inline u32 hwsim_net_get_wmediumd(struct net *net)
277{
278 struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
279
280 return hwsim_net->wmediumd;
281}
282
283static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid)
284{
285 struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
286
287 hwsim_net->wmediumd = portid;
288}
289
277static struct class *hwsim_class; 290static struct class *hwsim_class;
278 291
279static struct net_device *hwsim_mon; /* global monitor netdev */ 292static struct net_device *hwsim_mon; /* global monitor netdev */
@@ -552,6 +565,8 @@ struct mac80211_hwsim_data {
552 565
553 /* group shared by radios created in the same netns */ 566 /* group shared by radios created in the same netns */
554 int netgroup; 567 int netgroup;
568 /* wmediumd portid responsible for netgroup of this radio */
569 u32 wmediumd;
555 570
556 int power_level; 571 int power_level;
557 572
@@ -983,6 +998,29 @@ static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data,
983 return true; 998 return true;
984} 999}
985 1000
1001static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
1002 struct sk_buff *skb, int portid)
1003{
1004 struct net *net;
1005 bool found = false;
1006 int res = -ENOENT;
1007
1008 rcu_read_lock();
1009 for_each_net_rcu(net) {
1010 if (data->netgroup == hwsim_net_get_netgroup(net)) {
1011 res = genlmsg_unicast(net, skb, portid);
1012 found = true;
1013 break;
1014 }
1015 }
1016 rcu_read_unlock();
1017
1018 if (!found)
1019 nlmsg_free(skb);
1020
1021 return res;
1022}
1023
986static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw, 1024static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
987 struct sk_buff *my_skb, 1025 struct sk_buff *my_skb,
988 int dst_portid) 1026 int dst_portid)
@@ -1062,7 +1100,7 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
1062 goto nla_put_failure; 1100 goto nla_put_failure;
1063 1101
1064 genlmsg_end(skb, msg_head); 1102 genlmsg_end(skb, msg_head);
1065 if (genlmsg_unicast(&init_net, skb, dst_portid)) 1103 if (hwsim_unicast_netgroup(data, skb, dst_portid))
1066 goto err_free_txskb; 1104 goto err_free_txskb;
1067 1105
1068 /* Enqueue the packet */ 1106 /* Enqueue the packet */
@@ -1355,7 +1393,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
1355 mac80211_hwsim_monitor_rx(hw, skb, channel); 1393 mac80211_hwsim_monitor_rx(hw, skb, channel);
1356 1394
1357 /* wmediumd mode check */ 1395 /* wmediumd mode check */
1358 _portid = ACCESS_ONCE(wmediumd_portid); 1396 _portid = ACCESS_ONCE(data->wmediumd);
1359 1397
1360 if (_portid) 1398 if (_portid)
1361 return mac80211_hwsim_tx_frame_nl(hw, skb, _portid); 1399 return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
@@ -1451,7 +1489,8 @@ static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
1451 struct sk_buff *skb, 1489 struct sk_buff *skb,
1452 struct ieee80211_channel *chan) 1490 struct ieee80211_channel *chan)
1453{ 1491{
1454 u32 _pid = ACCESS_ONCE(wmediumd_portid); 1492 struct mac80211_hwsim_data *data = hw->priv;
1493 u32 _pid = ACCESS_ONCE(data->wmediumd);
1455 1494
1456 if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) { 1495 if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
1457 struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb); 1496 struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
@@ -2796,6 +2835,20 @@ static struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(const u8 *addr)
2796 return data; 2835 return data;
2797} 2836}
2798 2837
2838static void hwsim_register_wmediumd(struct net *net, u32 portid)
2839{
2840 struct mac80211_hwsim_data *data;
2841
2842 hwsim_net_set_wmediumd(net, portid);
2843
2844 spin_lock_bh(&hwsim_radio_lock);
2845 list_for_each_entry(data, &hwsim_radios, list) {
2846 if (data->netgroup == hwsim_net_get_netgroup(net))
2847 data->wmediumd = portid;
2848 }
2849 spin_unlock_bh(&hwsim_radio_lock);
2850}
2851
2799static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, 2852static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
2800 struct genl_info *info) 2853 struct genl_info *info)
2801{ 2854{
@@ -2811,9 +2864,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
2811 int i; 2864 int i;
2812 bool found = false; 2865 bool found = false;
2813 2866
2814 if (info->snd_portid != wmediumd_portid)
2815 return -EINVAL;
2816
2817 if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] || 2867 if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
2818 !info->attrs[HWSIM_ATTR_FLAGS] || 2868 !info->attrs[HWSIM_ATTR_FLAGS] ||
2819 !info->attrs[HWSIM_ATTR_COOKIE] || 2869 !info->attrs[HWSIM_ATTR_COOKIE] ||
@@ -2829,6 +2879,12 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
2829 if (!data2) 2879 if (!data2)
2830 goto out; 2880 goto out;
2831 2881
2882 if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
2883 goto out;
2884
2885 if (info->snd_portid != data2->wmediumd)
2886 goto out;
2887
2832 /* look for the skb matching the cookie passed back from user */ 2888 /* look for the skb matching the cookie passed back from user */
2833 skb_queue_walk_safe(&data2->pending, skb, tmp) { 2889 skb_queue_walk_safe(&data2->pending, skb, tmp) {
2834 u64 skb_cookie; 2890 u64 skb_cookie;
@@ -2892,9 +2948,6 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
2892 void *frame_data; 2948 void *frame_data;
2893 struct sk_buff *skb = NULL; 2949 struct sk_buff *skb = NULL;
2894 2950
2895 if (info->snd_portid != wmediumd_portid)
2896 return -EINVAL;
2897
2898 if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] || 2951 if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
2899 !info->attrs[HWSIM_ATTR_FRAME] || 2952 !info->attrs[HWSIM_ATTR_FRAME] ||
2900 !info->attrs[HWSIM_ATTR_RX_RATE] || 2953 !info->attrs[HWSIM_ATTR_RX_RATE] ||
@@ -2920,6 +2973,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
2920 if (!data2) 2973 if (!data2)
2921 goto out; 2974 goto out;
2922 2975
2976 if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
2977 goto out;
2978
2979 if (info->snd_portid != data2->wmediumd)
2980 goto out;
2981
2923 /* check if radio is configured properly */ 2982 /* check if radio is configured properly */
2924 2983
2925 if (data2->idle || !data2->started) 2984 if (data2->idle || !data2->started)
@@ -2966,6 +3025,7 @@ out:
2966static int hwsim_register_received_nl(struct sk_buff *skb_2, 3025static int hwsim_register_received_nl(struct sk_buff *skb_2,
2967 struct genl_info *info) 3026 struct genl_info *info)
2968{ 3027{
3028 struct net *net = genl_info_net(info);
2969 struct mac80211_hwsim_data *data; 3029 struct mac80211_hwsim_data *data;
2970 int chans = 1; 3030 int chans = 1;
2971 3031
@@ -2982,10 +3042,10 @@ static int hwsim_register_received_nl(struct sk_buff *skb_2,
2982 if (chans > 1) 3042 if (chans > 1)
2983 return -EOPNOTSUPP; 3043 return -EOPNOTSUPP;
2984 3044
2985 if (wmediumd_portid) 3045 if (hwsim_net_get_wmediumd(net))
2986 return -EBUSY; 3046 return -EBUSY;
2987 3047
2988 wmediumd_portid = info->snd_portid; 3048 hwsim_register_wmediumd(net, info->snd_portid);
2989 3049
2990 printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, " 3050 printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
2991 "switching to wmediumd mode with pid %d\n", info->snd_portid); 3051 "switching to wmediumd mode with pid %d\n", info->snd_portid);
@@ -3152,7 +3212,7 @@ static const struct genl_ops hwsim_ops[] = {
3152 .cmd = HWSIM_CMD_REGISTER, 3212 .cmd = HWSIM_CMD_REGISTER,
3153 .policy = hwsim_genl_policy, 3213 .policy = hwsim_genl_policy,
3154 .doit = hwsim_register_received_nl, 3214 .doit = hwsim_register_received_nl,
3155 .flags = GENL_ADMIN_PERM, 3215 .flags = GENL_UNS_ADMIN_PERM,
3156 }, 3216 },
3157 { 3217 {
3158 .cmd = HWSIM_CMD_FRAME, 3218 .cmd = HWSIM_CMD_FRAME,
@@ -3218,10 +3278,10 @@ static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
3218 3278
3219 remove_user_radios(notify->portid); 3279 remove_user_radios(notify->portid);
3220 3280
3221 if (notify->portid == wmediumd_portid) { 3281 if (notify->portid == hwsim_net_get_wmediumd(notify->net)) {
3222 printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink" 3282 printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
3223 " socket, switching to perfect channel medium\n"); 3283 " socket, switching to perfect channel medium\n");
3224 wmediumd_portid = 0; 3284 hwsim_register_wmediumd(notify->net, 0);
3225 } 3285 }
3226 return NOTIFY_DONE; 3286 return NOTIFY_DONE;
3227 3287