fixed compile warnings, removed unused enum
[ana-net.git] / src / xt_vlink.c
blob22288157eab0413e3a27a9f79a40333789591ec7
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;
71 vlink_unlock();
72 return slot == -1 ? -ENOMEM : 0;
74 EXPORT_SYMBOL_GPL(vlink_subsys_register);
76 void vlink_subsys_unregister(struct vlink_subsys *n)
78 int i;
79 if (!n)
80 return;
81 vlink_lock();
82 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
83 if (vlink_subsystem_table[i] == n && i == n->id) {
84 vlink_subsystem_table[i] = NULL;
85 n->id = 0;
86 break;
89 vlink_unlock();
91 EXPORT_SYMBOL_GPL(vlink_subsys_unregister);
93 static struct vlink_subsys *__vlink_subsys_find(u16 type)
95 int i;
96 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i)
97 if (vlink_subsystem_table[i])
98 if (vlink_subsystem_table[i]->type == type)
99 return vlink_subsystem_table[i];
100 return NULL;
103 struct vlink_subsys *vlink_subsys_find(u16 type)
105 struct vlink_subsys *ret;
106 vlink_lock();
107 ret = __vlink_subsys_find(type);
108 vlink_unlock();
109 return ret;
111 EXPORT_SYMBOL_GPL(vlink_subsys_find);
113 static int __vlink_add_callback(struct vlink_subsys *n,
114 struct vlink_callback *cb)
116 struct vlink_callback **hb;
118 if (!cb)
119 return -EINVAL;
120 hb = &n->head;
121 while (*hb != NULL) {
122 if (cb->priority > (*hb)->priority)
123 break;
124 hb = &((*hb)->next);
126 cb->next = *hb;
127 *hb = cb;
128 return 0;
131 int vlink_add_callback(struct vlink_subsys *n,
132 struct vlink_callback *cb)
134 int ret;
136 if (!n)
137 return -EINVAL;
138 down_write(&n->rwsem);
139 ret = __vlink_add_callback(n, cb);
140 up_write(&n->rwsem);
142 return ret;
144 EXPORT_SYMBOL_GPL(vlink_add_callback);
146 int vlink_add_callbacks_va(struct vlink_subsys *n,
147 struct vlink_callback *cb, va_list ap)
149 int ret = 0;
150 struct vlink_callback *arg;
152 arg = cb;
153 while (arg) {
154 ret = vlink_add_callback(n, arg);
155 if (ret)
156 break;
157 arg = va_arg(ap, struct vlink_callback *);
160 return ret;
162 EXPORT_SYMBOL_GPL(vlink_add_callbacks_va);
164 int vlink_add_callbacks(struct vlink_subsys *n,
165 struct vlink_callback *cb, ...)
167 int ret;
168 va_list vl;
170 va_start(vl, cb);
171 ret = vlink_add_callbacks_va(n, cb, vl);
172 va_end(vl);
174 return ret;
176 EXPORT_SYMBOL_GPL(vlink_add_callbacks);
178 static int __vlink_rm_callback(struct vlink_subsys *n,
179 struct vlink_callback *cb)
181 struct vlink_callback **hb;
183 if (!cb)
184 return -EINVAL;
185 hb = &n->head;
186 while (*hb != NULL) {
187 if (*hb == cb) {
188 *hb = cb->next;
189 return 0;
191 hb = &((*hb)->next);
194 return -ENOENT;
197 int vlink_rm_callback(struct vlink_subsys *n,
198 struct vlink_callback *cb)
200 int ret;
201 if (!n)
202 return -EINVAL;
203 down_write(&n->rwsem);
204 ret = __vlink_rm_callback(n, cb);
205 up_write(&n->rwsem);
206 return ret;
208 EXPORT_SYMBOL_GPL(vlink_rm_callback);
210 void vlink_subsys_unregister_batch(struct vlink_subsys *n)
212 int i;
214 if (!n)
215 return;
216 vlink_lock();
217 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
218 if (vlink_subsystem_table[i] == n && i == n->id) {
219 vlink_subsystem_table[i] = NULL;
220 n->id = 0;
221 break;
224 vlink_unlock();
225 while (n-> head != NULL)
226 vlink_rm_callback(n, n->head);
228 EXPORT_SYMBOL_GPL(vlink_subsys_unregister_batch);
230 static int __vlink_invoke(struct vlink_subsys *n,
231 struct vlinknlmsg *vmsg,
232 struct nlmsghdr *nlh)
234 int ret = 0;
235 struct vlink_callback *hb, *hn;
237 hb = n->head;
238 while (hb) {
239 hn = hb->next;
241 ret = hb->rx(vmsg, nlh);
242 if ((ret & NETLINK_VLINK_RX_EMERG) ==
243 NETLINK_VLINK_RX_EMERG ||
244 (ret & NETLINK_VLINK_RX_STOP) ==
245 NETLINK_VLINK_RX_STOP)
246 break;
247 hb = hn;
250 return ret;
253 static int __vlink_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
255 int ret;
256 struct vlinknlmsg *vmsg;
257 struct vlink_subsys *sys;
259 if (security_netlink_recv(skb, CAP_NET_ADMIN))
260 return -EPERM;
262 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct vlinknlmsg)))
263 return 0;
265 sys = __vlink_subsys_find(nlh->nlmsg_type);
266 if (!sys)
267 return -EINVAL;
269 vmsg = NLMSG_DATA(nlh);
271 down_read(&sys->rwsem);
272 ret = __vlink_invoke(sys, vmsg, nlh);
273 up_read(&sys->rwsem);
275 return ret;
278 static void vlink_rcv(struct sk_buff *skb)
280 vlink_lock();
281 netlink_rcv_skb(skb, &__vlink_rcv);
282 vlink_unlock();
285 static int vlink_procfs(char *page, char **start, off_t offset,
286 int count, int *eof, void *data)
288 int i;
289 off_t len = 0;
291 len += sprintf(page + len, "name type id\n");
292 vlink_lock();
293 for (i = 0; i < MAX_VLINK_SUBSYSTEMS; ++i) {
294 if (vlink_subsystem_table[i])
295 len += sprintf(page + len, "%s %u %u\n",
296 vlink_subsystem_table[i]->name,
297 vlink_subsystem_table[i]->type,
298 vlink_subsystem_table[i]->id);
300 vlink_unlock();
302 /* FIXME: fits in page? */
303 *eof = 1;
304 return len;
307 int init_vlink_system(void)
309 int ret;
311 vlink_subsystem_table = kzalloc(sizeof(*vlink_subsystem_table) *
312 MAX_VLINK_SUBSYSTEMS, GFP_KERNEL);
313 if (!vlink_subsystem_table)
314 return -ENOMEM;
315 vlink_sock = netlink_kernel_create(&init_net, NETLINK_VLINK,
316 VLINKNLGRP_MAX, vlink_rcv,
317 NULL, THIS_MODULE);
318 if (!vlink_sock) {
319 ret = -ENOMEM;
320 goto err;
322 vlink_proc = create_proc_read_entry("vlink", 0400, lana_proc_dir,
323 vlink_procfs, NULL);
324 if (!vlink_proc)
325 goto err2;
326 return 0;
327 err2:
328 netlink_kernel_release(vlink_sock);
329 err:
330 kfree(vlink_subsystem_table);
331 return ret;
334 void cleanup_vlink_system(void)
336 remove_proc_entry("vlink", lana_proc_dir);
337 netlink_kernel_release(vlink_sock);
338 kfree(vlink_subsystem_table);