Added RCU sync on unloading
[ana-net.git] / src / xt_user.c
blobc46ecbec4bd5ee397f313e9ea5866bd30339c892
1 /*
2 * Lightweight Autonomic Network Architecture
4 * LANA NETLINK handler for Functional Block userspace control.
6 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
7 * Swiss federal institute of technology (ETH Zurich)
8 * Subject to the GPL.
9 */
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/socket.h>
15 #include <linux/net.h>
16 #include <linux/skbuff.h>
17 #include <linux/rcupdate.h>
18 #include <net/netlink.h>
19 #include <net/sock.h>
21 #include "xt_idp.h"
22 #include "xt_user.h"
23 #include "xt_fblock.h"
24 #include "xt_builder.h"
26 static struct sock *userctl_sock = NULL;
28 static int userctl_add(struct lananlmsg *lmsg)
30 struct fblock *fb;
31 struct lananlmsg_add *msg = (struct lananlmsg_add *) lmsg->buff;
33 fb = search_fblock_n(msg->name);
34 if (fb) {
35 put_fblock(fb);
36 return -EINVAL;
39 fb = build_fblock_object(msg->type, msg->name);
41 return !fb ? -ENOMEM : 0;
44 static int userctl_set(struct lananlmsg *lmsg)
46 int ret;
47 struct fblock *fb;
48 struct lananlmsg_set *msg = (struct lananlmsg_set *) lmsg->buff;
50 fb = search_fblock_n(msg->name);
51 if (!fb)
52 return -EINVAL;
54 ret = fblock_set_option(fb, msg->option);
56 put_fblock(fb);
58 return ret;
61 static int userctl_replace(struct lananlmsg *lmsg)
63 int ret;
64 struct fblock *fb1, *fb2;
65 struct lananlmsg_replace *msg = (struct lananlmsg_replace *) lmsg->buff;
68 * XXX: vlink blocks may not be replaced during runtime, since they
69 * are directly bound to hardware. Fuckup? Yes or no? Too many side
70 * effects. These blocks should not be changed anyway.
73 fb1 = search_fblock_n(msg->name1);
74 if (!fb1 || !fb1->factory)
75 return -EINVAL;
77 fb2 = search_fblock_n(msg->name2);
78 if (!fb2 || !fb2->factory) {
79 put_fblock(fb1);
80 return -EINVAL;
83 if (atomic_read(&fb2->refcnt) > 2) {
84 /* Still in use by others */
85 printk(KERN_ERR "[lana] %s is still in use by others. "
86 "Drop refs first!\n", fb2->name);
87 put_fblock(fb1);
88 put_fblock(fb2);
89 return -EBUSY;
92 unregister_fblock_namespace_no_rcu(fb2);
94 if (!strncmp(fb1->factory->type, fb2->factory->type,
95 sizeof(fb1->factory->type)) && !msg->drop_priv)
96 fblock_migrate_p(fb2, fb1);
97 fblock_migrate_r(fb2, fb1);
99 unregister_fblock(fb1);
101 ret = register_fblock(fb2, fb2->idp);
103 put_fblock(fb1);
104 put_fblock(fb2);
106 return ret;
109 static int userctl_subscribe(struct lananlmsg *lmsg)
111 int ret;
112 struct fblock *fb1, *fb2;
113 struct lananlmsg_tuple *msg = (struct lananlmsg_tuple *) lmsg->buff;
115 fb1 = search_fblock_n(msg->name1);
116 if (!fb1)
117 return -EINVAL;
119 fb2 = search_fblock_n(msg->name2);
120 if (!fb2) {
121 put_fblock(fb1);
122 return -EINVAL;
125 * fb1 is remote block, fb2 is the one that
126 * wishes to be notified.
128 ret = subscribe_to_remote_fblock(fb2, fb1);
130 put_fblock(fb1);
131 put_fblock(fb2);
133 return ret;
136 static int userctl_unsubscribe(struct lananlmsg *lmsg)
138 struct fblock *fb1, *fb2;
139 struct lananlmsg_tuple *msg = (struct lananlmsg_tuple *) lmsg->buff;
141 fb1 = search_fblock_n(msg->name1);
142 if (!fb1)
143 return -EINVAL;
145 fb2 = search_fblock_n(msg->name2);
146 if (!fb2) {
147 put_fblock(fb1);
148 return -EINVAL;
151 unsubscribe_from_remote_fblock(fb2, fb1);
153 put_fblock(fb1);
154 put_fblock(fb2);
156 return 0;
159 static int userctl_remove(struct lananlmsg *lmsg)
161 struct fblock *fb;
162 struct lananlmsg_rm *msg = (struct lananlmsg_rm *) lmsg->buff;
164 fb = search_fblock_n(msg->name);
165 if (!fb)
166 return -EINVAL;
167 if (!fb->factory) {
168 /* vlink types have no factory */
169 put_fblock(fb);
170 return -EINVAL;
173 if (atomic_read(&fb->refcnt) > 2) {
174 /* Still in use by others */
175 put_fblock(fb);
176 return -EBUSY;
179 unregister_fblock_namespace(fb);
180 put_fblock(fb);
182 return 0;
185 static int userctl_bind(struct lananlmsg *lmsg)
187 int ret;
188 struct fblock *fb1, *fb2;
189 struct lananlmsg_tuple *msg = (struct lananlmsg_tuple *) lmsg->buff;
191 fb1 = search_fblock_n(msg->name1);
192 if (!fb1)
193 return -EINVAL;
195 fb2 = search_fblock_n(msg->name2);
196 if (!fb2) {
197 put_fblock(fb1);
198 return -EINVAL;
201 ret = fblock_bind(fb1, fb2);
203 put_fblock(fb1);
204 put_fblock(fb2);
206 return ret;
209 static int userctl_unbind(struct lananlmsg *lmsg)
211 int ret;
212 struct fblock *fb1, *fb2;
213 struct lananlmsg_tuple *msg = (struct lananlmsg_tuple *) lmsg->buff;
215 fb1 = search_fblock_n(msg->name1);
216 if (!fb1)
217 return -EINVAL;
219 fb2 = search_fblock_n(msg->name2);
220 if (!fb2) {
221 put_fblock(fb1);
222 return -EINVAL;
225 ret = fblock_unbind(fb1, fb2);
227 put_fblock(fb1);
228 put_fblock(fb2);
230 return ret;
233 static int __userctl_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
235 int ret = 0;
236 struct lananlmsg *lmsg;
238 if (security_netlink_recv(skb, CAP_NET_ADMIN))
239 return -EPERM;
240 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct lananlmsg)))
241 return 0;
243 lmsg = NLMSG_DATA(nlh);
245 switch (lmsg->cmd) {
246 case NETLINK_USERCTL_CMD_ADD:
247 ret = userctl_add(lmsg);
248 break;
249 case NETLINK_USERCTL_CMD_SET:
250 ret = userctl_set(lmsg);
251 break;
252 case NETLINK_USERCTL_CMD_REPLACE:
253 ret = userctl_replace(lmsg);
254 break;
255 case NETLINK_USERCTL_CMD_SUBSCRIBE:
256 ret = userctl_subscribe(lmsg);
257 break;
258 case NETLINK_USERCTL_CMD_UNSUBSCRIBE:
259 ret = userctl_unsubscribe(lmsg);
260 break;
261 case NETLINK_USERCTL_CMD_RM:
262 ret = userctl_remove(lmsg);
263 break;
264 case NETLINK_USERCTL_CMD_BIND:
265 ret = userctl_bind(lmsg);
266 break;
267 case NETLINK_USERCTL_CMD_UNBIND:
268 ret = userctl_unbind(lmsg);
269 break;
270 default:
271 printk(KERN_INFO "[lana] Unknown command!\n");
272 ret = -ENOENT;
273 break;
276 return ret;
279 static void userctl_rcv(struct sk_buff *skb)
281 netlink_rcv_skb(skb, &__userctl_rcv);
284 int init_userctl_system(void)
286 userctl_sock = netlink_kernel_create(&init_net, NETLINK_USERCTL,
287 USERCTLGRP_MAX, userctl_rcv,
288 NULL, THIS_MODULE);
289 return !userctl_sock ? -ENOMEM : 0;
291 EXPORT_SYMBOL_GPL(init_userctl_system);
293 void cleanup_userctl_system(void)
295 netlink_kernel_release(userctl_sock);
297 EXPORT_SYMBOL_GPL(cleanup_userctl_system);