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)
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>
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
;
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
)
49 struct vlink_subsys
*vs
;
54 for (i
= 0, slot
= -1; i
< MAX_VLINK_SUBSYSTEMS
; ++i
) {
55 if (!vlink_subsystem_table
[i
] && slot
== -1)
57 else if (!vlink_subsystem_table
[i
])
60 vs
= vlink_subsystem_table
[i
];
61 if (n
->type
== vs
->type
) {
69 vlink_subsystem_table
[slot
] = n
;
70 __module_get(THIS_MODULE
);
73 return slot
== -1 ? -ENOMEM
: 0;
75 EXPORT_SYMBOL_GPL(vlink_subsys_register
);
77 void vlink_subsys_unregister(struct vlink_subsys
*n
)
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
;
87 module_put(THIS_MODULE
);
93 EXPORT_SYMBOL_GPL(vlink_subsys_unregister
);
95 static struct vlink_subsys
*__vlink_subsys_find(u16 type
)
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
];
105 struct vlink_subsys
*vlink_subsys_find(u16 type
)
107 struct vlink_subsys
*ret
;
109 ret
= __vlink_subsys_find(type
);
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
;
123 while (*hb
!= NULL
) {
124 if (cb
->priority
> (*hb
)->priority
)
133 int vlink_add_callback(struct vlink_subsys
*n
,
134 struct vlink_callback
*cb
)
140 down_write(&n
->rwsem
);
141 ret
= __vlink_add_callback(n
, cb
);
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
)
152 struct vlink_callback
*arg
;
156 ret
= vlink_add_callback(n
, arg
);
159 arg
= va_arg(ap
, struct vlink_callback
*);
164 EXPORT_SYMBOL_GPL(vlink_add_callbacks_va
);
166 int vlink_add_callbacks(struct vlink_subsys
*n
,
167 struct vlink_callback
*cb
, ...)
173 ret
= vlink_add_callbacks_va(n
, cb
, vl
);
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
;
188 while (*hb
!= NULL
) {
199 int vlink_rm_callback(struct vlink_subsys
*n
,
200 struct vlink_callback
*cb
)
205 down_write(&n
->rwsem
);
206 ret
= __vlink_rm_callback(n
, cb
);
210 EXPORT_SYMBOL_GPL(vlink_rm_callback
);
212 void vlink_subsys_unregister_batch(struct vlink_subsys
*n
)
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
;
223 module_put(THIS_MODULE
);
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
)
238 struct vlink_callback
*hb
, *hn
;
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
);
259 static int __vlink_rcv(struct sk_buff
*skb
, struct nlmsghdr
*nlh
)
262 struct vlinknlmsg
*vmsg
;
263 struct vlink_subsys
*sys
;
265 if (security_netlink_recv(skb
, CAP_NET_ADMIN
))
268 if (nlh
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct vlinknlmsg
)))
271 sys
= __vlink_subsys_find(nlh
->nlmsg_type
);
275 vmsg
= NLMSG_DATA(nlh
);
277 down_read(&sys
->rwsem
);
278 ret
= __vlink_invoke(sys
, vmsg
, nlh
);
279 up_read(&sys
->rwsem
);
284 static void vlink_rcv(struct sk_buff
*skb
)
287 netlink_rcv_skb(skb
, &__vlink_rcv
);
291 static int vlink_procfs(char *page
, char **start
, off_t offset
,
292 int count
, int *eof
, void *data
)
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
);
307 /* FIXME: fits in page? */
312 int init_vlink_system(void)
316 vlink_subsystem_table
= kzalloc(sizeof(*vlink_subsystem_table
) *
317 MAX_VLINK_SUBSYSTEMS
, GFP_KERNEL
);
318 if (!vlink_subsystem_table
)
320 vlink_sock
= netlink_kernel_create(&init_net
, NETLINK_VLINK
,
321 VLINKNLGRP_MAX
, vlink_rcv
,
327 vlink_proc
= create_proc_read_entry("vlink", 0400, lana_proc_dir
,
333 netlink_kernel_release(vlink_sock
);
335 kfree(vlink_subsystem_table
);
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
);