add support for killing running proto-shell tasks with an arbitrary signal and waitin...
[project/netifd.git] / ubus.c
1 #define _GNU_SOURCE
2
3 #include <string.h>
4 #include <stdio.h>
5
6 #include "netifd.h"
7 #include "interface.h"
8 #include "proto.h"
9 #include "ubus.h"
10 #include "system.h"
11
12 static struct ubus_context *ctx = NULL;
13 static struct blob_buf b;
14
15 /* global object */
16
17 static int
18 netifd_handle_restart(struct ubus_context *ctx, struct ubus_object *obj,
19 struct ubus_request_data *req, const char *method,
20 struct blob_attr *msg)
21 {
22 netifd_restart();
23 return 0;
24 }
25
26 static int
27 netifd_handle_reload(struct ubus_context *ctx, struct ubus_object *obj,
28 struct ubus_request_data *req, const char *method,
29 struct blob_attr *msg)
30 {
31 netifd_reload();
32 return 0;
33 }
34
35 static struct ubus_method main_object_methods[] = {
36 { .name = "restart", .handler = netifd_handle_restart },
37 { .name = "reload", .handler = netifd_handle_reload },
38 };
39
40 static struct ubus_object_type main_object_type =
41 UBUS_OBJECT_TYPE("netifd", main_object_methods);
42
43 static struct ubus_object main_object = {
44 .name = "network",
45 .type = &main_object_type,
46 .methods = main_object_methods,
47 .n_methods = ARRAY_SIZE(main_object_methods),
48 };
49
50 enum {
51 DEV_NAME,
52 __DEV_MAX,
53 };
54
55 static const struct blobmsg_policy dev_policy[__DEV_MAX] = {
56 [DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
57 };
58
59 static int
60 netifd_dev_status(struct ubus_context *ctx, struct ubus_object *obj,
61 struct ubus_request_data *req, const char *method,
62 struct blob_attr *msg)
63 {
64 struct device *dev = NULL;
65 struct blob_attr *tb[__DEV_MAX];
66
67 blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg));
68
69 if (tb[DEV_NAME]) {
70 dev = device_get(blobmsg_data(tb[DEV_NAME]), false);
71 if (!dev)
72 return UBUS_STATUS_INVALID_ARGUMENT;
73 }
74
75 blob_buf_init(&b, 0);
76 device_dump_status(&b, dev);
77 ubus_send_reply(ctx, req, b.head);
78
79 return 0;
80 }
81
82 static struct ubus_method dev_object_methods[] = {
83 UBUS_METHOD("status", netifd_dev_status, dev_policy)
84 };
85
86 static struct ubus_object_type dev_object_type =
87 UBUS_OBJECT_TYPE("device", dev_object_methods);
88
89 static struct ubus_object dev_object = {
90 .name = "network.device",
91 .type = &dev_object_type,
92 .methods = dev_object_methods,
93 .n_methods = ARRAY_SIZE(dev_object_methods),
94 };
95
96 int
97 netifd_ubus_init(const char *path)
98 {
99 int ret;
100
101 ctx = ubus_connect(path);
102 if (!ctx)
103 return -EIO;
104
105 DPRINTF("connected as %08x\n", ctx->local_id);
106 uloop_init();
107 ubus_add_uloop(ctx);
108
109 ret = ubus_add_object(ctx, &main_object);
110 if (ret)
111 goto out;
112
113 ret = ubus_add_object(ctx, &dev_object);
114
115 out:
116 if (ret != 0)
117 fprintf(stderr, "Failed to publish object: %s\n", ubus_strerror(ret));
118 return ret;
119 }
120
121 void
122 netifd_ubus_done(void)
123 {
124 ubus_free(ctx);
125 }
126
127
128 /* per-interface object */
129
130 static int
131 netifd_handle_up(struct ubus_context *ctx, struct ubus_object *obj,
132 struct ubus_request_data *req, const char *method,
133 struct blob_attr *msg)
134 {
135 struct interface *iface;
136
137 iface = container_of(obj, struct interface, ubus);
138 interface_set_up(iface);
139
140 return 0;
141 }
142
143 static int
144 netifd_handle_down(struct ubus_context *ctx, struct ubus_object *obj,
145 struct ubus_request_data *req, const char *method,
146 struct blob_attr *msg)
147 {
148 struct interface *iface;
149
150 iface = container_of(obj, struct interface, ubus);
151 interface_set_down(iface);
152
153 return 0;
154 }
155
156 static void
157 netifd_add_interface_errors(struct blob_buf *b, struct interface *iface)
158 {
159 struct interface_error *error;
160 void *e, *e2, *e3;
161 int i;
162
163 e = blobmsg_open_array(b, "errors");
164 list_for_each_entry(error, &iface->errors, list) {
165 e2 = blobmsg_open_table(b, NULL);
166
167 blobmsg_add_string(b, "subsystem", error->subsystem);
168 blobmsg_add_string(b, "code", error->code);
169 if (error->data[0]) {
170 e3 = blobmsg_open_array(b, "data");
171 for (i = 0; error->data[i]; i++)
172 blobmsg_add_string(b, NULL, error->data[i]);
173 blobmsg_close_array(b, e3);
174 }
175
176 blobmsg_close_table(b, e2);
177 }
178 blobmsg_close_array(b, e);
179 }
180
181 static int
182 netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj,
183 struct ubus_request_data *req, const char *method,
184 struct blob_attr *msg)
185 {
186 struct interface *iface;
187
188 iface = container_of(obj, struct interface, ubus);
189
190 blob_buf_init(&b, 0);
191 blobmsg_add_u8(&b, "up", iface->state == IFS_UP);
192 blobmsg_add_u8(&b, "pending", iface->state == IFS_SETUP);
193 blobmsg_add_u8(&b, "available", iface->available);
194 blobmsg_add_u8(&b, "autostart", iface->autostart);
195
196 if (iface->state == IFS_UP) {
197 time_t cur = system_get_rtime();
198 blobmsg_add_u32(&b, "uptime", cur - iface->start_time);
199 }
200
201 if (iface->main_dev.dev) {
202 struct device *dev = iface->main_dev.dev;
203 const char *field;
204 void *devinfo;
205
206 /* use a different field for virtual devices */
207 if (dev->avl.key)
208 field = "device";
209 else
210 field = "link";
211
212 devinfo = blobmsg_open_table(&b, field);
213 blobmsg_add_string(&b, "name", dev->ifname);
214
215 blobmsg_close_table(&b, devinfo);
216 }
217
218 if (!list_is_empty(&iface->errors))
219 netifd_add_interface_errors(&b, iface);
220
221 ubus_send_reply(ctx, req, b.head);
222
223 return 0;
224 }
225
226 static int
227 netifd_iface_handle_device(struct ubus_context *ctx, struct ubus_object *obj,
228 struct ubus_request_data *req, const char *method,
229 struct blob_attr *msg)
230 {
231 struct interface *iface;
232 struct device *dev, *main_dev;
233 struct blob_attr *tb[__DEV_MAX];
234 bool add = !strncmp(method, "add", 3);
235 int ret;
236
237 iface = container_of(obj, struct interface, ubus);
238
239 blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg));
240
241 if (!tb[DEV_NAME])
242 return UBUS_STATUS_INVALID_ARGUMENT;
243
244 main_dev = iface->main_dev.dev;
245 if (!main_dev)
246 return UBUS_STATUS_NOT_FOUND;
247
248 if (!main_dev->hotplug_ops)
249 return UBUS_STATUS_NOT_SUPPORTED;
250
251 dev = device_get(blobmsg_data(tb[DEV_NAME]), add);
252 if (!dev)
253 return UBUS_STATUS_NOT_FOUND;
254
255 if (main_dev != dev) {
256 if (add)
257 ret = main_dev->hotplug_ops->add(main_dev, dev);
258 else
259 ret = main_dev->hotplug_ops->del(main_dev, dev);
260 if (ret)
261 ret = UBUS_STATUS_UNKNOWN_ERROR;
262 } else {
263 ret = UBUS_STATUS_INVALID_ARGUMENT;
264 }
265
266 if (add)
267 device_free_unused(dev);
268
269 return ret;
270 }
271
272
273 static int
274 netifd_iface_notify_proto(struct ubus_context *ctx, struct ubus_object *obj,
275 struct ubus_request_data *req, const char *method,
276 struct blob_attr *msg)
277 {
278 struct interface *iface;
279
280 iface = container_of(obj, struct interface, ubus);
281
282 if (!iface->proto || !iface->proto->notify)
283 return UBUS_STATUS_NOT_SUPPORTED;
284
285 return iface->proto->notify(iface->proto, msg);
286 }
287
288 static void
289 netifd_iface_do_remove(struct uloop_timeout *timeout)
290 {
291 struct interface *iface;
292
293 iface = container_of(timeout, struct interface, remove_timer);
294 vlist_delete(&interfaces, &iface->node);
295 }
296
297 static int
298 netifd_iface_remove(struct ubus_context *ctx, struct ubus_object *obj,
299 struct ubus_request_data *req, const char *method,
300 struct blob_attr *msg)
301 {
302 struct interface *iface;
303
304 iface = container_of(obj, struct interface, ubus);
305 if (iface->remove_timer.cb)
306 return UBUS_STATUS_INVALID_ARGUMENT;
307
308 iface->remove_timer.cb = netifd_iface_do_remove;
309 uloop_timeout_set(&iface->remove_timer, 100);
310 return 0;
311 }
312
313 static struct ubus_method iface_object_methods[] = {
314 { .name = "up", .handler = netifd_handle_up },
315 { .name = "down", .handler = netifd_handle_down },
316 { .name = "status", .handler = netifd_handle_status },
317 { .name = "add_device", .handler = netifd_iface_handle_device,
318 .policy = dev_policy, .n_policy = __DEV_MAX },
319 { .name = "remove_device", .handler = netifd_iface_handle_device,
320 .policy = dev_policy, .n_policy = __DEV_MAX },
321 { .name = "notify_proto", .handler = netifd_iface_notify_proto },
322 { .name = "remove", .handler = netifd_iface_remove }
323 };
324
325 static struct ubus_object_type iface_object_type =
326 UBUS_OBJECT_TYPE("netifd_iface", iface_object_methods);
327
328
329 void
330 netifd_ubus_interface_event(struct interface *iface, bool up)
331 {
332 blob_buf_init(&b, 0);
333 blobmsg_add_string(&b, "action", up ? "ifup" : "ifdown");
334 blobmsg_add_string(&b, "interface", iface->name);
335 ubus_send_event(ctx, "network.interface", b.head);
336 }
337
338 void
339 netifd_ubus_add_interface(struct interface *iface)
340 {
341 struct ubus_object *obj = &iface->ubus;
342 char *name = NULL;
343
344 asprintf(&name, "%s.interface.%s", main_object.name, iface->name);
345 if (!name)
346 return;
347
348 obj->name = name;
349 obj->type = &iface_object_type;
350 obj->methods = iface_object_methods;
351 obj->n_methods = ARRAY_SIZE(iface_object_methods);
352 if (ubus_add_object(ctx, &iface->ubus)) {
353 DPRINTF("failed to publish ubus object for interface '%s'\n", iface->name);
354 free(name);
355 obj->name = NULL;
356 }
357 }
358
359 void
360 netifd_ubus_remove_interface(struct interface *iface)
361 {
362 if (!iface->ubus.name)
363 return;
364
365 ubus_remove_object(ctx, &iface->ubus);
366 free((void *) iface->ubus.name);
367 }