Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b333b3d2 authored by Johannes Berg's avatar Johannes Berg Committed by David S. Miller
Browse files

wireless extensions: make netns aware



This makes wireless extensions netns aware. The
tasklet sending the events is converted to a work
struct so that we can rtnl_lock() in it.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 97fd5bc7
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -79,6 +79,9 @@ struct net {
#endif
#endif
#ifdef CONFIG_XFRM
#ifdef CONFIG_XFRM
	struct netns_xfrm	xfrm;
	struct netns_xfrm	xfrm;
#endif
#ifdef CONFIG_WIRELESS_EXT
	struct sk_buff_head	wext_nlevents;
#endif
#endif
	struct net_generic	*gen;
	struct net_generic	*gen;
};
};
+29 −32
Original line number Original line Diff line number Diff line
@@ -1257,48 +1257,48 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
}
}
#endif
#endif


/************************* EVENT PROCESSING *************************/
static int __net_init wext_pernet_init(struct net *net)
/*
{
 * Process events generated by the wireless layer or the driver.
	skb_queue_head_init(&net->wext_nlevents);
 * Most often, the event will be propagated through rtnetlink
	return 0;
 */
}


/* ---------------------------------------------------------------- */
static void __net_exit wext_pernet_exit(struct net *net)
/*
{
 * Locking...
	skb_queue_purge(&net->wext_nlevents);
 * ----------
}
 *
 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
 * the locking issue in here and implementing this code !
 *
 * The issue : wireless_send_event() is often called in interrupt context,
 * while the Netlink layer can never be called in interrupt context.
 * The fully formed RtNetlink events are queued, and then a tasklet is run
 * to feed those to Netlink.
 * The skb_queue is interrupt safe, and its lock is not held while calling
 * Netlink, so there is no possibility of dealock.
 * Jean II
 */


static struct sk_buff_head wireless_nlevent_queue;
static struct pernet_operations wext_pernet_ops = {
	.init = wext_pernet_init,
	.exit = wext_pernet_exit,
};


static int __init wireless_nlevent_init(void)
static int __init wireless_nlevent_init(void)
{
{
	skb_queue_head_init(&wireless_nlevent_queue);
	return register_pernet_subsys(&wext_pernet_ops);
	return 0;
	return 0;
}
}


subsys_initcall(wireless_nlevent_init);
subsys_initcall(wireless_nlevent_init);


static void wireless_nlevent_process(unsigned long data)
/* Process events generated by the wireless layer or the driver. */
static void wireless_nlevent_process(struct work_struct *work)
{
{
	struct sk_buff *skb;
	struct sk_buff *skb;
	struct net *net;

	rtnl_lock();


	while ((skb = skb_dequeue(&wireless_nlevent_queue)))
	for_each_net(net) {
		rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
		while ((skb = skb_dequeue(&net->wext_nlevents)))
			rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
				    GFP_KERNEL);
	}
	}


static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0);
	rtnl_unlock();
}

static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);


/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
/*
/*
@@ -1348,9 +1348,6 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
	struct sk_buff *skb;
	struct sk_buff *skb;
	int err;
	int err;


	if (!net_eq(dev_net(dev), &init_net))
		return;

	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
	if (!skb)
	if (!skb)
		return;
		return;
@@ -1363,8 +1360,8 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
	}
	}


	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
	NETLINK_CB(skb).dst_group = RTNLGRP_LINK;
	skb_queue_tail(&wireless_nlevent_queue, skb);
	skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
	tasklet_schedule(&wireless_nlevent_tasklet);
	schedule_work(&wireless_nlevent_work);
}
}


/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */