refactoring of xt_user
[ana-net.git] / src / xt_user.c
blob9eb31da9b3a3f44d9b118992225f278f9d03193c
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;
53 ret = fblock_set_option(fb, msg->option);
54 put_fblock(fb);
56 return ret;
59 static int userctl_replace(struct lananlmsg *lmsg)
61 int ret;
62 struct fblock *fb1, *fb2;
63 struct lananlmsg_replace *msg = (struct lananlmsg_replace *) lmsg->buff;
65 fb1 = search_fblock_n(msg->name1);
66 if (!fb1)
67 return -EINVAL;
68 fb2 = search_fblock_n(msg->name2);
69 if (!fb2) {
70 put_fblock(fb1);
71 return -EINVAL;
74 if (atomic_read(&fb2->refcnt) > 2) {
75 /* Still in use by others */
76 printk(KERN_ERR "[lana] %s is still in use by others. "
77 "Drop refs first!\n", fb2->name);
78 put_fblock(fb1);
79 put_fblock(fb2);
80 return -EBUSY;
83 unregister_fblock_namespace_no_rcu(fb2);
85 if (!strncmp(fb1->factory->type, fb2->factory->type,
86 sizeof(fb1->factory->type)) && !msg->drop_priv)
87 fblock_migrate_p(fb2, fb1);
88 fblock_migrate_r(fb2, fb1);
90 unregister_fblock(fb1);
92 ret = register_fblock(fb2, fb2->idp);
93 put_fblock(fb1);
94 put_fblock(fb2);
96 return ret;
99 static int userctl_subscribe(struct lananlmsg *lmsg)
101 int ret;
102 struct fblock *fb1, *fb2;
103 struct lananlmsg_subscribe *msg = (struct lananlmsg_subscribe *) lmsg->buff;
105 fb1 = search_fblock_n(msg->name1);
106 if (!fb1)
107 return -EINVAL;
108 fb2 = search_fblock_n(msg->name2);
109 if (!fb2) {
110 put_fblock(fb1);
111 return -EINVAL;
114 * fb1 is remote block, fb2 is the one that
115 * wishes to be notified.
117 ret = subscribe_to_remote_fblock(fb2, fb1);
118 put_fblock(fb1);
119 put_fblock(fb2);
121 return ret;
124 static int userctl_unsubscribe(struct lananlmsg *lmsg)
126 struct fblock *fb1, *fb2;
127 struct lananlmsg_unsubscribe *msg =
128 (struct lananlmsg_unsubscribe *) lmsg->buff;
130 fb1 = search_fblock_n(msg->name1);
131 if (!fb1)
132 return -EINVAL;
133 fb2 = search_fblock_n(msg->name2);
134 if (!fb2) {
135 put_fblock(fb1);
136 return -EINVAL;
139 unsubscribe_from_remote_fblock(fb2, fb1);
140 put_fblock(fb1);
141 put_fblock(fb2);
143 return 0;
146 static int userctl_remove(struct lananlmsg *lmsg)
148 struct fblock *fb;
149 struct lananlmsg_rm *msg = (struct lananlmsg_rm *) lmsg->buff;
151 fb = search_fblock_n(msg->name);
152 if (!fb)
153 return -EINVAL;
155 if (atomic_read(&fb->refcnt) > 2) {
156 /* Still in use by others */
157 put_fblock(fb);
158 return -EBUSY;
161 unregister_fblock_namespace(fb);
162 put_fblock(fb);
164 return 0;
167 static int userctl_bind(struct lananlmsg *lmsg)
169 int ret;
170 struct fblock *fb1, *fb2;
171 struct lananlmsg_bind *msg = (struct lananlmsg_bind *) lmsg->buff;
173 fb1 = search_fblock_n(msg->name1);
174 if (!fb1)
175 return -EINVAL;
177 fb2 = search_fblock_n(msg->name2);
178 if (!fb2) {
179 put_fblock(fb1);
180 return -EINVAL;
183 ret = fblock_bind(fb1, fb2);
185 put_fblock(fb1);
186 put_fblock(fb2);
188 return ret;
191 static int userctl_unbind(struct lananlmsg *lmsg)
193 int ret;
194 struct fblock *fb1, *fb2;
195 struct lananlmsg_unbind *msg = (struct lananlmsg_unbind *) lmsg->buff;
197 fb1 = search_fblock_n(msg->name1);
198 if (!fb1)
199 return -EINVAL;
201 fb2 = search_fblock_n(msg->name2);
202 if (!fb2) {
203 put_fblock(fb1);
204 return -EINVAL;
207 ret = fblock_unbind(fb1, fb2);
209 put_fblock(fb1);
210 put_fblock(fb2);
212 return ret;
215 static int __userctl_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
217 int ret = 0;
218 struct lananlmsg *lmsg;
220 if (security_netlink_recv(skb, CAP_NET_ADMIN))
221 return -EPERM;
222 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct lananlmsg)))
223 return 0;
225 lmsg = NLMSG_DATA(nlh);
227 switch (lmsg->cmd) {
228 case NETLINK_USERCTL_CMD_ADD:
229 ret = userctl_add(lmsg);
230 break;
231 case NETLINK_USERCTL_CMD_SET:
232 ret = userctl_set(lmsg);
233 break;
234 case NETLINK_USERCTL_CMD_REPLACE:
235 ret = userctl_replace(lmsg);
236 break;
237 case NETLINK_USERCTL_CMD_SUBSCRIBE:
238 ret = userctl_subscribe(lmsg);
239 break;
240 case NETLINK_USERCTL_CMD_UNSUBSCRIBE:
241 ret = userctl_unsubscribe(lmsg);
242 break;
243 case NETLINK_USERCTL_CMD_RM:
244 ret = userctl_remove(lmsg);
245 break;
246 case NETLINK_USERCTL_CMD_BIND:
247 ret = userctl_bind(lmsg);
248 break;
249 case NETLINK_USERCTL_CMD_UNBIND:
250 ret = userctl_unbind(lmsg);
251 break;
252 default:
253 printk(KERN_INFO "[lana] Unknown command!\n");
254 ret = -ENOENT;
255 break;
258 return ret;
261 static void userctl_rcv(struct sk_buff *skb)
263 netlink_rcv_skb(skb, &__userctl_rcv);
266 int init_userctl_system(void)
268 userctl_sock = netlink_kernel_create(&init_net, NETLINK_USERCTL,
269 USERCTLGRP_MAX, userctl_rcv,
270 NULL, THIS_MODULE);
271 return !userctl_sock ? -ENOMEM : 0;
273 EXPORT_SYMBOL_GPL(init_userctl_system);
275 void cleanup_userctl_system(void)
277 netlink_kernel_release(userctl_sock);
279 EXPORT_SYMBOL_GPL(cleanup_userctl_system);