add tmp to .gitignore
[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 }