use sk_receive_skb instead of sk_backlog_rcv
[ana-net.git] / src / xt_user.c
blob20b044e97055f8473db9a9f5c3d048dc6742ae6e
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_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
30 int ret = 0;
31 struct lananlmsg *lmsg;
33 if (security_netlink_recv(skb, CAP_NET_ADMIN))
34 return -EPERM;
35 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct lananlmsg)))
36 return 0;
38 lmsg = NLMSG_DATA(nlh);
40 switch (lmsg->cmd) {
41 case NETLINK_USERCTL_CMD_ADD: {
42 struct fblock *fb;
43 struct lananlmsg_add *msg =
44 (struct lananlmsg_add *) lmsg->buff;
45 fb = search_fblock_n(msg->name);
46 if (fb) {
47 put_fblock(fb);
48 return -EINVAL;
50 fb = build_fblock_object(msg->type, msg->name);
51 if (!fb)
52 return -ENOMEM;
53 } break;
54 case NETLINK_USERCTL_CMD_SET: {
55 struct fblock *fb;
56 struct lananlmsg_set *msg =
57 (struct lananlmsg_set *) lmsg->buff;
58 fb = search_fblock_n(msg->name);
59 if (!fb)
60 return -EINVAL;
61 ret = fblock_set_option(fb, msg->option);
62 put_fblock(fb);
63 } break;
64 case NETLINK_USERCTL_CMD_REPLACE: {
65 struct fblock *fb1, *fb2;
66 struct lananlmsg_replace *msg =
67 (struct lananlmsg_replace *) lmsg->buff;
68 fb1 = search_fblock_n(msg->name1);
69 if (!fb1)
70 return -EINVAL;
71 fb2 = search_fblock_n(msg->name2);
72 if (!fb2) {
73 put_fblock(fb1);
74 return -EINVAL;
76 if (atomic_read(&fb2->refcnt) > 2) {
77 /* Still in use by others */
78 put_fblock(fb1);
79 printk(KERN_ERR "[lana] %s is still in use by others. "
80 "Drop refs first!\n", fb2->name);
81 put_fblock(fb2);
82 return -EBUSY;
84 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);
89 unregister_fblock(fb1);
90 ret = register_fblock(fb2, fb2->idp);
91 put_fblock(fb1);
92 put_fblock(fb2);
93 } break;
94 case NETLINK_USERCTL_CMD_SUBSCRIBE: {
95 struct fblock *fb1, *fb2;
96 struct lananlmsg_subscribe *msg =
97 (struct lananlmsg_subscribe *) lmsg->buff;
98 fb1 = search_fblock_n(msg->name1);
99 if (!fb1)
100 return -EINVAL;
101 fb2 = search_fblock_n(msg->name2);
102 if (!fb2) {
103 put_fblock(fb1);
104 return -EINVAL;
107 * fb1 is remote block, fb2 is the one that
108 * wishes to be notified.
110 ret = subscribe_to_remote_fblock(fb2, fb1);
111 put_fblock(fb1);
112 put_fblock(fb2);
113 } break;
114 case NETLINK_USERCTL_CMD_UNSUBSCRIBE: {
115 struct fblock *fb1, *fb2;
116 struct lananlmsg_unsubscribe *msg =
117 (struct lananlmsg_unsubscribe *) lmsg->buff;
118 fb1 = search_fblock_n(msg->name1);
119 if (!fb1)
120 return -EINVAL;
121 fb2 = search_fblock_n(msg->name2);
122 if (!fb2) {
123 put_fblock(fb1);
124 return -EINVAL;
126 unsubscribe_from_remote_fblock(fb2, fb1);
127 put_fblock(fb1);
128 put_fblock(fb2);
129 } break;
130 case NETLINK_USERCTL_CMD_RM: {
131 struct fblock *fb;
132 struct lananlmsg_rm *msg =
133 (struct lananlmsg_rm *) lmsg->buff;
134 fb = search_fblock_n(msg->name);
135 if (!fb)
136 return -EINVAL;
137 if (atomic_read(&fb->refcnt) > 2) {
138 /* Still in use by others */
139 put_fblock(fb);
140 return -EBUSY;
142 unregister_fblock_namespace(fb);
143 put_fblock(fb);
144 } break;
145 case NETLINK_USERCTL_CMD_BIND: {
146 struct fblock *fb1, *fb2;
147 struct lananlmsg_bind *msg =
148 (struct lananlmsg_bind *) lmsg->buff;
149 fb1 = search_fblock_n(msg->name1);
150 if (!fb1)
151 return -EINVAL;
152 fb2 = search_fblock_n(msg->name2);
153 if (!fb2) {
154 put_fblock(fb1);
155 return -EINVAL;
157 ret = fblock_bind(fb1, fb2);
158 if (ret) {
159 put_fblock(fb1);
160 put_fblock(fb2);
161 return ret;
163 put_fblock(fb1);
164 put_fblock(fb2);
165 } break;
166 case NETLINK_USERCTL_CMD_UNBIND: {
167 struct fblock *fb1, *fb2;
168 struct lananlmsg_unbind *msg =
169 (struct lananlmsg_unbind *) lmsg->buff;
170 fb1 = search_fblock_n(msg->name1);
171 if (!fb1)
172 return -EINVAL;
173 fb2 = search_fblock_n(msg->name2);
174 if (!fb2) {
175 put_fblock(fb1);
176 return -EINVAL;
178 ret = fblock_unbind(fb1, fb2);
179 if (ret) {
180 put_fblock(fb1);
181 put_fblock(fb2);
182 return ret;
184 put_fblock(fb1);
185 put_fblock(fb2);
186 } break;
187 default:
188 printk("[lana] Unknown command!\n");
189 break;
192 return ret;
195 static void userctl_rcv(struct sk_buff *skb)
197 netlink_rcv_skb(skb, &__userctl_rcv);
200 int init_userctl_system(void)
202 userctl_sock = netlink_kernel_create(&init_net, NETLINK_USERCTL,
203 USERCTLGRP_MAX, userctl_rcv,
204 NULL, THIS_MODULE);
205 if (!userctl_sock)
206 return -ENOMEM;
207 return 0;
209 EXPORT_SYMBOL_GPL(init_userctl_system);
211 void cleanup_userctl_system(void)
213 netlink_kernel_release(userctl_sock);
215 EXPORT_SYMBOL_GPL(cleanup_userctl_system);