pf_lana: release lock in sendmsg after ppe has finished
[ana-net.git] / src / xt_vlink.c
blob04e1814e02fb6c9ba060f63ec224018ae08ca2da
1 /*
2 * Lightweight Autonomic Network Architecture
4 * LANA vlink control messages via netlink socket. This allows userspace
5 * applications like 'vlink' to control the whole LANA vlink layer. Each
6 * vlink type (e.g. Ethernet, Bluetooth, ...) gets its own subsystem with
7 * its operations. Access via a single socket type (NETLINK_VLINK). We are
8 * furthermore not in fast-path here.
10 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
11 * Swiss federal institute of technology (ETH Zurich)
12 * Subject to the GPL.
15 #include <linux/module.h>
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/socket.h>
19 #include <linux/slab.h>
20 #include <linux/net.h>
21 #include <linux/skbuff.h>
22 #include <linux/proc_fs.h>
23 #include <net/netlink.h>
24 #include <net/sock.h>
26 #include "xt_vlink.h"
28 static DEFINE_MUTEX(vlink_mutex);
29 static struct sock *vlink_sock = NULL;
30 static struct vlink_subsys **vlink_subsystem_table = NULL;
31 extern struct proc_dir_entry *lana_proc_dir;
32 static struct proc_dir_entry *vlink_proc;
34 void vlink_lock(void)
36 mutex_lock(&vlink_mutex);
38 EXPORT_SYMBOL_GPL(vlink_lock);
40 void vlink_unlock(void)
42 mutex_unlock(&vlink_mutex);
44 EXPORT_SYMBOL_GPL(vlink_unlock);
46 int vlink_subsys_register(struct vlink_subsys *n)
48 int i, slot;
49 struct vlink_subsys *vs;
51 if (!n)
52 return -EINVAL;
53 vlink_lock();
54 for (i = 0, slot = -1; i < MAX_VLINK_SUBSYSTEMS; ++i) {
55 if (!vlink_subsystem_table[i] && slot == -1)
56 slot = i;
57 else if (!vlink_subsystem_table[i])
58 continue;
59 else {
60 vs = vlink_subsystem_table[i];
61 if (n->type == vs->type) {
62 vlink_unlock();
63 return -EBUSY;
67 if (slot != -1) {
68 n->id = slot;
69 vlink_subsystem_table[slot] = n;
70 __module_get(THIS_MODULE);
72 vlink_unlock();
73 return slot == -1 ? -ENOMEM : 0;
75 EXPORT_SYMBOL_GPL(vlink_subsys_register);
77 void vlink_subsys_unregister(struct vlink_subsys *n)
79 int i;
80 if (!n)
81 return;
82 vlink_lock();
83 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
84 if (vlink_subsystem_table[i] == n && i == n->id) {
85 vlink_subsystem_table[i] = NULL;
86 n->id = 0;
87 module_put(THIS_MODULE);
88 break;
91 vlink_unlock();
93 EXPORT_SYMBOL_GPL(vlink_subsys_unregister);
95 static struct vlink_subsys *__vlink_subsys_find(u16 type)
97 int i;
98 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i)
99 if (vlink_subsystem_table[i])
100 if (vlink_subsystem_table[i]->type == type)
101 return vlink_subsystem_table[i];
102 return NULL;
105 struct vlink_subsys *vlink_subsys_find(u16 type)
107 struct vlink_subsys *ret;
108 vlink_lock();
109 ret = __vlink_subsys_find(type);
110 vlink_unlock();
111 return ret;
113 EXPORT_SYMBOL_GPL(vlink_subsys_find);
115 static int __vlink_add_callback(struct vlink_subsys *n,
116 struct vlink_callback *cb)
118 struct vlink_callback **hb;
120 if (!cb)
121 return -EINVAL;
122 hb = &n->head;
123 while (*hb != NULL) {
124 if (cb->priority > (*hb)->priority)
125 break;
126 hb = &((*hb)->next);
128 cb->next = *hb;
129 *hb = cb;
130 return 0;
133 int vlink_add_callback(struct vlink_subsys *n,
134 struct vlink_callback *cb)
136 int ret;
138 if (!n)
139 return -EINVAL;
140 down_write(&n->rwsem);
141 ret = __vlink_add_callback(n, cb);
142 up_write(&n->rwsem);
144 return ret;
146 EXPORT_SYMBOL_GPL(vlink_add_callback);
148 int vlink_add_callbacks_va(struct vlink_subsys *n,
149 struct vlink_callback *cb, va_list ap)
151 int ret = 0;
152 struct vlink_callback *arg;
154 arg = cb;
155 while (arg) {
156 ret = vlink_add_callback(n, arg);
157 if (ret)
158 break;
159 arg = va_arg(ap, struct vlink_callback *);
162 return ret;
164 EXPORT_SYMBOL_GPL(vlink_add_callbacks_va);
166 int vlink_add_callbacks(struct vlink_subsys *n,
167 struct vlink_callback *cb, ...)
169 int ret;
170 va_list vl;
172 va_start(vl, cb);
173 ret = vlink_add_callbacks_va(n, cb, vl);
174 va_end(vl);
176 return ret;
178 EXPORT_SYMBOL_GPL(vlink_add_callbacks);
180 static int __vlink_rm_callback(struct vlink_subsys *n,
181 struct vlink_callback *cb)
183 struct vlink_callback **hb;
185 if (!cb)
186 return -EINVAL;
187 hb = &n->head;
188 while (*hb != NULL) {
189 if (*hb == cb) {
190 *hb = cb->next;
191 return 0;
193 hb = &((*hb)->next);
196 return -ENOENT;
199 int vlink_rm_callback(struct vlink_subsys *n,
200 struct vlink_callback *cb)
202 int ret;
203 if (!n)
204 return -EINVAL;
205 down_write(&n->rwsem);
206 ret = __vlink_rm_callback(n, cb);
207 up_write(&n->rwsem);
208 return ret;
210 EXPORT_SYMBOL_GPL(vlink_rm_callback);
212 void vlink_subsys_unregister_batch(struct vlink_subsys *n)
214 int i;
216 if (!n)
217 return;
218 vlink_lock();
219 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
220 if (vlink_subsystem_table[i] == n && i == n->id) {
221 vlink_subsystem_table[i] = NULL;
222 n->id = 0;
223 module_put(THIS_MODULE);
224 break;
227 vlink_unlock();
228 while (n-> head != NULL)
229 vlink_rm_callback(n, n->head);
231 EXPORT_SYMBOL_GPL(vlink_subsys_unregister_batch);
233 static int __vlink_invoke(struct vlink_subsys *n,
234 struct vlinknlmsg *vmsg,
235 struct nlmsghdr *nlh)
237 int ret = 0, nret;
238 struct vlink_callback *hb, *hn;
240 hb = n->head;
241 while (hb) {
242 hn = hb->next;
243 nret = 0;
244 ret = hb->rx(vmsg, nlh);
245 if ((ret & NETLINK_VLINK_RX_EMERG) == NETLINK_VLINK_RX_EMERG ||
246 (nret = (ret & NETLINK_VLINK_RX_STOP) == NETLINK_VLINK_RX_STOP)) {
247 if (vmsg->cmd == VLINKNLCMD_START_HOOK_DEVICE && nret)
248 __module_get(n->owner);
249 if (vmsg->cmd == VLINKNLCMD_STOP_HOOK_DEVICE && nret)
250 module_put(n->owner);
251 break;
253 hb = hn;
256 return ret;
259 static int __vlink_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
261 int ret;
262 struct vlinknlmsg *vmsg;
263 struct vlink_subsys *sys;
265 if (security_netlink_recv(skb, CAP_NET_ADMIN))
266 return -EPERM;
268 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct vlinknlmsg)))
269 return 0;
271 sys = __vlink_subsys_find(nlh->nlmsg_type);
272 if (!sys)
273 return -EINVAL;
275 vmsg = NLMSG_DATA(nlh);
277 down_read(&sys->rwsem);
278 ret = __vlink_invoke(sys, vmsg, nlh);
279 up_read(&sys->rwsem);
281 return ret;
284 static void vlink_rcv(struct sk_buff *skb)
286 vlink_lock();
287 netlink_rcv_skb(skb, &__vlink_rcv);
288 vlink_unlock();
291 static int vlink_procfs(char *page, char **start, off_t offset,
292 int count, int *eof, void *data)
294 int i;
295 off_t len = 0;
297 vlink_lock();
298 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
299 if (vlink_subsystem_table[i])
300 len += sprintf(page + len, "%s %u %u\n",
301 vlink_subsystem_table[i]->name,
302 vlink_subsystem_table[i]->type,
303 vlink_subsystem_table[i]->id);
305 vlink_unlock();
307 /* FIXME: fits in page? */
308 *eof = 1;
309 return len;
312 int init_vlink_system(void)
314 int ret;
316 vlink_subsystem_table = kzalloc(sizeof(*vlink_subsystem_table) *
317 MAX_VLINK_SUBSYSTEMS, GFP_KERNEL);
318 if (!vlink_subsystem_table)
319 return -ENOMEM;
320 vlink_sock = netlink_kernel_create(&init_net, NETLINK_VLINK,
321 VLINKNLGRP_MAX, vlink_rcv,
322 NULL, THIS_MODULE);
323 if (!vlink_sock) {
324 ret = -ENOMEM;
325 goto err;
327 vlink_proc = create_proc_read_entry("vlink", 0400, lana_proc_dir,
328 vlink_procfs, NULL);
329 if (!vlink_proc)
330 goto err2;
331 return 0;
332 err2:
333 netlink_kernel_release(vlink_sock);
334 err:
335 kfree(vlink_subsystem_table);
336 return ret;
339 void cleanup_vlink_system(void)
341 remove_proc_entry("vlink", lana_proc_dir);
342 netlink_kernel_release(vlink_sock);
343 kfree(vlink_subsystem_table);