MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
 MODULE_LICENSE("GPL");
 
-static u32 wmediumd_portid;
-
 static int radios = 2;
 module_param(radios, int, 0444);
 MODULE_PARM_DESC(radios, "Number of simulated radios");
 
 struct hwsim_net {
        int netgroup;
+       u32 wmediumd;
 };
 
 static inline int hwsim_net_get_netgroup(struct net *net)
        hwsim_net->netgroup = hwsim_netgroup++;
 }
 
+static inline u32 hwsim_net_get_wmediumd(struct net *net)
+{
+       struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
+
+       return hwsim_net->wmediumd;
+}
+
+static inline void hwsim_net_set_wmediumd(struct net *net, u32 portid)
+{
+       struct hwsim_net *hwsim_net = net_generic(net, hwsim_net_id);
+
+       hwsim_net->wmediumd = portid;
+}
+
 static struct class *hwsim_class;
 
 static struct net_device *hwsim_mon; /* global monitor netdev */
 
        /* group shared by radios created in the same netns */
        int netgroup;
+       /* wmediumd portid responsible for netgroup of this radio */
+       u32 wmediumd;
 
        int power_level;
 
        return true;
 }
 
+static int hwsim_unicast_netgroup(struct mac80211_hwsim_data *data,
+                                 struct sk_buff *skb, int portid)
+{
+       struct net *net;
+       bool found = false;
+       int res = -ENOENT;
+
+       rcu_read_lock();
+       for_each_net_rcu(net) {
+               if (data->netgroup == hwsim_net_get_netgroup(net)) {
+                       res = genlmsg_unicast(net, skb, portid);
+                       found = true;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       if (!found)
+               nlmsg_free(skb);
+
+       return res;
+}
+
 static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
                                       struct sk_buff *my_skb,
                                       int dst_portid)
                goto nla_put_failure;
 
        genlmsg_end(skb, msg_head);
-       if (genlmsg_unicast(&init_net, skb, dst_portid))
+       if (hwsim_unicast_netgroup(data, skb, dst_portid))
                goto err_free_txskb;
 
        /* Enqueue the packet */
        mac80211_hwsim_monitor_rx(hw, skb, channel);
 
        /* wmediumd mode check */
-       _portid = ACCESS_ONCE(wmediumd_portid);
+       _portid = ACCESS_ONCE(data->wmediumd);
 
        if (_portid)
                return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
                                    struct sk_buff *skb,
                                    struct ieee80211_channel *chan)
 {
-       u32 _pid = ACCESS_ONCE(wmediumd_portid);
+       struct mac80211_hwsim_data *data = hw->priv;
+       u32 _pid = ACCESS_ONCE(data->wmediumd);
 
        if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE)) {
                struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
        return data;
 }
 
+static void hwsim_register_wmediumd(struct net *net, u32 portid)
+{
+       struct mac80211_hwsim_data *data;
+
+       hwsim_net_set_wmediumd(net, portid);
+
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry(data, &hwsim_radios, list) {
+               if (data->netgroup == hwsim_net_get_netgroup(net))
+                       data->wmediumd = portid;
+       }
+       spin_unlock_bh(&hwsim_radio_lock);
+}
+
 static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
                                           struct genl_info *info)
 {
        int i;
        bool found = false;
 
-       if (info->snd_portid != wmediumd_portid)
-               return -EINVAL;
-
        if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
            !info->attrs[HWSIM_ATTR_FLAGS] ||
            !info->attrs[HWSIM_ATTR_COOKIE] ||
        if (!data2)
                goto out;
 
+       if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
+               goto out;
+
+       if (info->snd_portid != data2->wmediumd)
+               goto out;
+
        /* look for the skb matching the cookie passed back from user */
        skb_queue_walk_safe(&data2->pending, skb, tmp) {
                u64 skb_cookie;
        void *frame_data;
        struct sk_buff *skb = NULL;
 
-       if (info->snd_portid != wmediumd_portid)
-               return -EINVAL;
-
        if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
            !info->attrs[HWSIM_ATTR_FRAME] ||
            !info->attrs[HWSIM_ATTR_RX_RATE] ||
        if (!data2)
                goto out;
 
+       if (hwsim_net_get_netgroup(genl_info_net(info)) != data2->netgroup)
+               goto out;
+
+       if (info->snd_portid != data2->wmediumd)
+               goto out;
+
        /* check if radio is configured properly */
 
        if (data2->idle || !data2->started)
 static int hwsim_register_received_nl(struct sk_buff *skb_2,
                                      struct genl_info *info)
 {
+       struct net *net = genl_info_net(info);
        struct mac80211_hwsim_data *data;
        int chans = 1;
 
        if (chans > 1)
                return -EOPNOTSUPP;
 
-       if (wmediumd_portid)
+       if (hwsim_net_get_wmediumd(net))
                return -EBUSY;
 
-       wmediumd_portid = info->snd_portid;
+       hwsim_register_wmediumd(net, info->snd_portid);
 
        printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
               "switching to wmediumd mode with pid %d\n", info->snd_portid);
                .cmd = HWSIM_CMD_REGISTER,
                .policy = hwsim_genl_policy,
                .doit = hwsim_register_received_nl,
-               .flags = GENL_ADMIN_PERM,
+               .flags = GENL_UNS_ADMIN_PERM,
        },
        {
                .cmd = HWSIM_CMD_FRAME,
 
        remove_user_radios(notify->portid);
 
-       if (notify->portid == wmediumd_portid) {
+       if (notify->portid == hwsim_net_get_wmediumd(notify->net)) {
                printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
                       " socket, switching to perfect channel medium\n");
-               wmediumd_portid = 0;
+               hwsim_register_wmediumd(notify->net, 0);
        }
        return NOTIFY_DONE;