interface: proto_ip: order by address index first
[project/netifd.git] / proto-shell.c
1 /*
2 * netifd - network interface daemon
3 * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14 #define _GNU_SOURCE
15
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <signal.h>
20
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23
24
25 #include "netifd.h"
26 #include "interface.h"
27 #include "interface-ip.h"
28 #include "proto.h"
29 #include "system.h"
30 #include "handler.h"
31
32 static int proto_fd = -1;
33
34 enum proto_shell_sm {
35 S_IDLE,
36 S_SETUP,
37 S_SETUP_ABORT,
38 S_TEARDOWN,
39 };
40
41 struct proto_shell_handler {
42 struct list_head list;
43 struct proto_handler proto;
44 char *config_buf;
45 char *script_name;
46 bool init_available;
47
48 struct uci_blob_param_list config;
49 };
50
51 struct proto_shell_dependency {
52 struct list_head list;
53
54 struct proto_shell_state *proto;
55 struct interface_user dep;
56
57 union if_addr host;
58 bool v6;
59 bool any;
60
61 char interface[];
62 };
63
64 struct proto_shell_state {
65 struct interface_proto_state proto;
66 struct proto_shell_handler *handler;
67 struct blob_attr *config;
68
69 struct uloop_timeout teardown_timeout;
70
71 /*
72 * Teardown and setup interface again if it is still not up (IFS_UP)
73 * after checkup_interval seconds since previous attempt. This check
74 * will be disabled when the config option "checkup_interval" is
75 * missing or has a negative value
76 */
77 int checkup_interval;
78 struct uloop_timeout checkup_timeout;
79
80 struct netifd_process script_task;
81 struct netifd_process proto_task;
82
83 enum proto_shell_sm sm;
84 bool proto_task_killed;
85 bool renew_pending;
86
87 int last_error;
88
89 struct list_head deps;
90 };
91
92 static void
93 proto_shell_check_dependencies(struct proto_shell_state *state)
94 {
95 struct proto_shell_dependency *dep;
96 bool available = true;
97
98 list_for_each_entry(dep, &state->deps, list) {
99 if (dep->dep.iface)
100 continue;
101
102 available = false;
103 break;
104 }
105
106 interface_set_available(state->proto.iface, available);
107 }
108
109 static void
110 proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface,
111 enum interface_event ev);
112 static void
113 proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface,
114 enum interface_event ev);
115
116 static void
117 proto_shell_update_host_dep(struct proto_shell_dependency *dep)
118 {
119 struct interface *iface = NULL;
120
121 if (dep->dep.iface)
122 goto out;
123
124 if (dep->interface[0]) {
125 iface = vlist_find(&interfaces, dep->interface, iface, node);
126
127 if (!iface || iface->state != IFS_UP)
128 goto out;
129 }
130
131 if (!dep->any)
132 iface = interface_ip_add_target_route(&dep->host, dep->v6, iface);
133
134 if (!iface)
135 goto out;
136
137 interface_remove_user(&dep->dep);
138 dep->dep.cb = proto_shell_if_down_cb;
139 interface_add_user(&dep->dep, iface);
140
141 out:
142 proto_shell_check_dependencies(dep->proto);
143 }
144
145 static void
146 proto_shell_clear_host_dep(struct proto_shell_state *state)
147 {
148 struct proto_shell_dependency *dep, *tmp;
149
150 list_for_each_entry_safe(dep, tmp, &state->deps, list) {
151 interface_remove_user(&dep->dep);
152 list_del(&dep->list);
153 free(dep);
154 }
155 }
156
157 static int
158 proto_shell_handler(struct interface_proto_state *proto,
159 enum interface_proto_cmd cmd, bool force)
160 {
161 struct proto_shell_state *state;
162 struct proto_shell_handler *handler;
163 struct netifd_process *proc;
164 static char error_buf[32];
165 const char *argv[7];
166 char *envp[2];
167 const char *action;
168 char *config;
169 int ret, i = 0, j = 0;
170
171 state = container_of(proto, struct proto_shell_state, proto);
172 handler = state->handler;
173 proc = &state->script_task;
174
175 if (cmd == PROTO_CMD_SETUP) {
176 switch (state->sm) {
177 case S_IDLE:
178 action = "setup";
179 state->last_error = -1;
180 proto_shell_clear_host_dep(state);
181 state->sm = S_SETUP;
182 break;
183
184 default:
185 return -1;
186 }
187 } else if (cmd == PROTO_CMD_RENEW) {
188 if (!(handler->proto.flags & PROTO_FLAG_RENEW_AVAILABLE))
189 return 0;
190
191 if (state->script_task.uloop.pending) {
192 state->renew_pending = true;
193 return 0;
194 }
195
196 state->renew_pending = false;
197 action = "renew";
198 } else {
199 switch (state->sm) {
200 case S_SETUP:
201 if (state->script_task.uloop.pending) {
202 uloop_timeout_set(&state->teardown_timeout, 1000);
203 kill(state->script_task.uloop.pid, SIGTERM);
204 if (state->proto_task.uloop.pending)
205 kill(state->proto_task.uloop.pid, SIGTERM);
206 state->renew_pending = false;
207 state->sm = S_SETUP_ABORT;
208 return 0;
209 }
210 /* if no script task is running */
211 /* fall through */
212 case S_IDLE:
213 action = "teardown";
214 state->renew_pending = false;
215 state->sm = S_TEARDOWN;
216 if (state->last_error >= 0) {
217 snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
218 envp[j++] = error_buf;
219 }
220 uloop_timeout_set(&state->teardown_timeout, 5000);
221 break;
222
223 case S_TEARDOWN:
224 return 0;
225
226 default:
227 return -1;
228 }
229 }
230
231 D(INTERFACE, "run %s for interface '%s'\n", action, proto->iface->name);
232 config = blobmsg_format_json(state->config, true);
233 if (!config)
234 return -1;
235
236 argv[i++] = handler->script_name;
237 argv[i++] = handler->proto.name;
238 argv[i++] = action;
239 argv[i++] = proto->iface->name;
240 argv[i++] = config;
241 if (proto->iface->main_dev.dev)
242 argv[i++] = proto->iface->main_dev.dev->ifname;
243 argv[i] = NULL;
244 envp[j] = NULL;
245
246 ret = netifd_start_process(argv, envp, proc);
247 free(config);
248
249 return ret;
250 }
251
252 static void
253 proto_shell_if_up_cb(struct interface_user *dep, struct interface *iface,
254 enum interface_event ev)
255 {
256 struct proto_shell_dependency *pdep;
257
258 if (ev != IFEV_UP && ev != IFEV_UPDATE)
259 return;
260
261 pdep = container_of(dep, struct proto_shell_dependency, dep);
262 proto_shell_update_host_dep(pdep);
263 }
264
265 static void
266 proto_shell_if_down_cb(struct interface_user *dep, struct interface *iface,
267 enum interface_event ev)
268 {
269 struct proto_shell_dependency *pdep;
270 struct proto_shell_state *state;
271
272 if (ev == IFEV_UP || ev == IFEV_UPDATE)
273 return;
274
275 pdep = container_of(dep, struct proto_shell_dependency, dep);
276 interface_remove_user(dep);
277 dep->cb = proto_shell_if_up_cb;
278 interface_add_user(dep, NULL);
279
280 state = pdep->proto;
281 if (state->sm == S_IDLE) {
282 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
283 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
284 }
285 }
286
287 static void
288 proto_shell_task_finish(struct proto_shell_state *state,
289 struct netifd_process *task)
290 {
291 switch (state->sm) {
292 case S_IDLE:
293 if (task == &state->proto_task)
294 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
295 /* fall through */
296 case S_SETUP:
297 if (task == &state->proto_task)
298 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN,
299 false);
300 else if (task == &state->script_task) {
301 if (state->renew_pending)
302 proto_shell_handler(&state->proto,
303 PROTO_CMD_RENEW, false);
304 else if (!(state->handler->proto.flags & PROTO_FLAG_NO_TASK) &&
305 !state->proto_task.uloop.pending &&
306 state->sm == S_SETUP)
307 proto_shell_handler(&state->proto,
308 PROTO_CMD_TEARDOWN,
309 false);
310
311 /* check up status after setup attempt by this script_task */
312 if (state->sm == S_SETUP && state->checkup_interval > 0) {
313 uloop_timeout_set(&state->checkup_timeout,
314 state->checkup_interval * 1000);
315 }
316 }
317 break;
318
319 case S_SETUP_ABORT:
320 if (state->script_task.uloop.pending ||
321 state->proto_task.uloop.pending)
322 break;
323
324 /* completed aborting all tasks, now idle */
325 uloop_timeout_cancel(&state->teardown_timeout);
326 uloop_timeout_cancel(&state->checkup_timeout);
327 state->sm = S_IDLE;
328 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
329 break;
330
331 case S_TEARDOWN:
332 if (state->script_task.uloop.pending)
333 break;
334
335 if (state->proto_task.uloop.pending) {
336 if (!state->proto_task_killed)
337 kill(state->proto_task.uloop.pid, SIGTERM);
338 break;
339 }
340
341 /* completed tearing down all tasks, now idle */
342 uloop_timeout_cancel(&state->teardown_timeout);
343 uloop_timeout_cancel(&state->checkup_timeout);
344 state->sm = S_IDLE;
345 state->proto.proto_event(&state->proto, IFPEV_DOWN);
346 break;
347 }
348 }
349
350 static void
351 proto_shell_teardown_timeout_cb(struct uloop_timeout *timeout)
352 {
353 struct proto_shell_state *state;
354
355 state = container_of(timeout, struct proto_shell_state, teardown_timeout);
356
357 netifd_kill_process(&state->script_task);
358 netifd_kill_process(&state->proto_task);
359 proto_shell_task_finish(state, NULL);
360 }
361
362 static void
363 proto_shell_script_cb(struct netifd_process *p, int ret)
364 {
365 struct proto_shell_state *state;
366
367 state = container_of(p, struct proto_shell_state, script_task);
368 proto_shell_task_finish(state, p);
369 }
370
371 static void
372 proto_shell_task_cb(struct netifd_process *p, int ret)
373 {
374 struct proto_shell_state *state;
375
376 state = container_of(p, struct proto_shell_state, proto_task);
377
378 if (state->sm == S_IDLE || state->sm == S_SETUP)
379 state->last_error = WEXITSTATUS(ret);
380
381 proto_shell_task_finish(state, p);
382 }
383
384 static void
385 proto_shell_free(struct interface_proto_state *proto)
386 {
387 struct proto_shell_state *state;
388
389 state = container_of(proto, struct proto_shell_state, proto);
390 uloop_timeout_cancel(&state->teardown_timeout);
391 uloop_timeout_cancel(&state->checkup_timeout);
392 proto_shell_clear_host_dep(state);
393 netifd_kill_process(&state->script_task);
394 netifd_kill_process(&state->proto_task);
395 free(state->config);
396 free(state);
397 }
398
399 static void
400 proto_shell_parse_route_list(struct interface *iface, struct blob_attr *attr,
401 bool v6)
402 {
403 struct blob_attr *cur;
404 int rem;
405
406 blobmsg_for_each_attr(cur, attr, rem) {
407 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
408 DPRINTF("Ignore wrong route type: %d\n", blobmsg_type(cur));
409 continue;
410 }
411
412 interface_ip_add_route(iface, cur, v6);
413 }
414 }
415
416 static void
417 proto_shell_parse_neighbor_list(struct interface *iface, struct blob_attr *attr,
418 bool v6)
419 {
420 struct blob_attr *cur;
421 int rem;
422
423 blobmsg_for_each_attr(cur, attr, rem) {
424 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
425 DPRINTF("Ignore wrong neighbor type: %d\n", blobmsg_type(cur));
426 continue;
427 }
428
429 interface_ip_add_neighbor(iface, cur, v6);
430 }
431 }
432
433 static void
434 proto_shell_parse_data(struct interface *iface, struct blob_attr *attr)
435 {
436 struct blob_attr *cur;
437 int rem;
438
439 blobmsg_for_each_attr(cur, attr, rem)
440 interface_add_data(iface, cur);
441 }
442
443 static struct device *
444 proto_shell_create_tunnel(const char *name, struct blob_attr *attr)
445 {
446 struct device *dev;
447 struct blob_buf b;
448
449 memset(&b, 0, sizeof(b));
450 blob_buf_init(&b, 0);
451 blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr));
452 dev = device_create(name, &tunnel_device_type, blob_data(b.head));
453 blob_buf_free(&b);
454
455 return dev;
456 }
457
458 enum {
459 NOTIFY_ACTION,
460 NOTIFY_ERROR,
461 NOTIFY_COMMAND,
462 NOTIFY_ENV,
463 NOTIFY_SIGNAL,
464 NOTIFY_AVAILABLE,
465 NOTIFY_LINK_UP,
466 NOTIFY_IFNAME,
467 NOTIFY_ADDR_EXT,
468 NOTIFY_ROUTES,
469 NOTIFY_ROUTES6,
470 NOTIFY_TUNNEL,
471 NOTIFY_DATA,
472 NOTIFY_KEEP,
473 NOTIFY_HOST,
474 NOTIFY_DNS,
475 NOTIFY_DNS_SEARCH,
476 NOTIFY_NEIGHBORS,
477 NOTIFY_NEIGHBORS6,
478 __NOTIFY_LAST
479 };
480
481 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
482 [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
483 [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY },
484 [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
485 [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY },
486 [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
487 [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL },
488 [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
489 [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
490 [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL },
491 [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY },
492 [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY },
493 [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE },
494 [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
495 [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL },
496 [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING },
497 [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
498 [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
499 [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY},
500 [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY},
501 };
502
503 static int
504 proto_shell_update_link(struct proto_shell_state *state, struct blob_attr *data, struct blob_attr **tb)
505 {
506 struct interface *iface = state->proto.iface;
507 struct blob_attr *cur;
508 struct device *dev;
509 const char *devname;
510 int dev_create = 1;
511 bool addr_ext = false;
512 bool keep = false;
513 bool up;
514
515 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
516 return UBUS_STATUS_PERMISSION_DENIED;
517
518 if (!tb[NOTIFY_LINK_UP])
519 return UBUS_STATUS_INVALID_ARGUMENT;
520
521 up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]);
522 if (!up) {
523 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
524 return 0;
525 }
526
527 if ((cur = tb[NOTIFY_KEEP]) != NULL)
528 keep = blobmsg_get_bool(cur);
529
530 if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
531 addr_ext = blobmsg_get_bool(cur);
532 if (addr_ext)
533 dev_create = 2;
534 }
535
536 if (iface->state != IFS_UP || !iface->l3_dev.dev)
537 keep = false;
538
539 if (!keep) {
540 dev = iface->main_dev.dev;
541 if (tb[NOTIFY_IFNAME]) {
542 keep = false;
543 devname = blobmsg_data(tb[NOTIFY_IFNAME]);
544 if (tb[NOTIFY_TUNNEL])
545 dev = proto_shell_create_tunnel(devname, tb[NOTIFY_TUNNEL]);
546 else
547 dev = device_get(devname, dev_create);
548 }
549
550 if (!dev)
551 return UBUS_STATUS_INVALID_ARGUMENT;
552
553 interface_set_l3_dev(iface, dev);
554 if (device_claim(&iface->l3_dev) < 0)
555 return UBUS_STATUS_UNKNOWN_ERROR;
556
557 device_set_present(dev, true);
558 }
559
560 interface_update_start(iface, keep);
561
562 proto_apply_ip_settings(iface, data, addr_ext);
563
564 if ((cur = tb[NOTIFY_ROUTES]) != NULL)
565 proto_shell_parse_route_list(state->proto.iface, cur, false);
566
567 if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
568 proto_shell_parse_route_list(state->proto.iface, cur, true);
569
570 if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL)
571 proto_shell_parse_neighbor_list(state->proto.iface, cur, false);
572
573 if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL)
574 proto_shell_parse_neighbor_list(state->proto.iface, cur, true);
575
576 if ((cur = tb[NOTIFY_DNS]))
577 interface_add_dns_server_list(&iface->proto_ip, cur);
578
579 if ((cur = tb[NOTIFY_DNS_SEARCH]))
580 interface_add_dns_search_list(&iface->proto_ip, cur);
581
582 if ((cur = tb[NOTIFY_DATA]))
583 proto_shell_parse_data(state->proto.iface, cur);
584
585 interface_update_complete(state->proto.iface);
586
587 if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) {
588 state->proto.proto_event(&state->proto, IFPEV_UP);
589 state->sm = S_IDLE;
590 }
591
592 return 0;
593 }
594
595 static bool
596 fill_string_list(struct blob_attr *attr, char **argv, int max)
597 {
598 struct blob_attr *cur;
599 int argc = 0;
600 int rem;
601
602 if (!attr)
603 goto out;
604
605 blobmsg_for_each_attr(cur, attr, rem) {
606 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
607 return false;
608
609 if (!blobmsg_check_attr(cur, false))
610 return false;
611
612 argv[argc++] = blobmsg_data(cur);
613 if (argc == max - 1)
614 return false;
615 }
616
617 out:
618 argv[argc] = NULL;
619 return true;
620 }
621
622 static int
623 proto_shell_run_command(struct proto_shell_state *state, struct blob_attr **tb)
624 {
625 static char *argv[64];
626 static char *env[32];
627
628 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
629 return UBUS_STATUS_PERMISSION_DENIED;
630
631 if (!tb[NOTIFY_COMMAND])
632 goto error;
633
634 if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv)))
635 goto error;
636
637 if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env)))
638 goto error;
639
640 netifd_start_process((const char **) argv, (char **) env, &state->proto_task);
641
642 return 0;
643
644 error:
645 return UBUS_STATUS_INVALID_ARGUMENT;
646 }
647
648 static int
649 proto_shell_kill_command(struct proto_shell_state *state, struct blob_attr **tb)
650 {
651 unsigned int signal = ~0;
652
653 if (tb[NOTIFY_SIGNAL])
654 signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]);
655
656 if (signal > 31)
657 signal = SIGTERM;
658
659 if (state->proto_task.uloop.pending) {
660 if (signal == SIGTERM || signal == SIGKILL)
661 state->proto_task_killed = true;
662 kill(state->proto_task.uloop.pid, signal);
663 }
664
665 return 0;
666 }
667
668 static int
669 proto_shell_notify_error(struct proto_shell_state *state, struct blob_attr **tb)
670 {
671 struct blob_attr *cur;
672 char *data[16];
673 int n_data = 0;
674 int rem;
675
676 if (!tb[NOTIFY_ERROR])
677 return UBUS_STATUS_INVALID_ARGUMENT;
678
679 blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) {
680 if (n_data + 1 == ARRAY_SIZE(data))
681 goto error;
682
683 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
684 goto error;
685
686 if (!blobmsg_check_attr(cur, false))
687 goto error;
688
689 data[n_data++] = blobmsg_data(cur);
690 }
691
692 if (!n_data)
693 goto error;
694
695 interface_add_error(state->proto.iface, state->handler->proto.name,
696 data[0], (const char **) &data[1], n_data - 1);
697
698 return 0;
699
700 error:
701 return UBUS_STATUS_INVALID_ARGUMENT;
702 }
703
704 static int
705 proto_shell_block_restart(struct proto_shell_state *state, struct blob_attr **tb)
706 {
707 state->proto.iface->autostart = false;
708 return 0;
709 }
710
711 static int
712 proto_shell_set_available(struct proto_shell_state *state, struct blob_attr **tb)
713 {
714 if (!tb[NOTIFY_AVAILABLE])
715 return UBUS_STATUS_INVALID_ARGUMENT;
716
717 interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE]));
718 return 0;
719 }
720
721 static int
722 proto_shell_add_host_dependency(struct proto_shell_state *state, struct blob_attr **tb)
723 {
724 struct proto_shell_dependency *dep;
725 const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : "";
726 const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : "";
727
728 if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
729 return UBUS_STATUS_PERMISSION_DENIED;
730
731 dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1);
732 if (!dep)
733 return UBUS_STATUS_UNKNOWN_ERROR;
734
735 if (!host[0] && ifname[0]) {
736 dep->any = true;
737 } else if (inet_pton(AF_INET, host, &dep->host) < 1) {
738 if (inet_pton(AF_INET6, host, &dep->host) < 1) {
739 free(dep);
740 return UBUS_STATUS_INVALID_ARGUMENT;
741 } else {
742 dep->v6 = true;
743 }
744 }
745
746 dep->proto = state;
747 strcpy(dep->interface, ifname);
748
749 dep->dep.cb = proto_shell_if_up_cb;
750 interface_add_user(&dep->dep, NULL);
751 list_add(&dep->list, &state->deps);
752 proto_shell_update_host_dep(dep);
753 if (!dep->dep.iface)
754 return UBUS_STATUS_NOT_FOUND;
755
756 return 0;
757 }
758
759 static int
760 proto_shell_setup_failed(struct proto_shell_state *state)
761 {
762 int ret = 0;
763
764 switch (state->sm) {
765 case S_IDLE:
766 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
767 /* fall through */
768 case S_SETUP:
769 proto_shell_handler(&state->proto, PROTO_CMD_TEARDOWN, false);
770 break;
771 case S_SETUP_ABORT:
772 case S_TEARDOWN:
773 default:
774 ret = UBUS_STATUS_PERMISSION_DENIED;
775 break;
776 }
777 return ret;
778 }
779
780 static int
781 proto_shell_notify(struct interface_proto_state *proto, struct blob_attr *attr)
782 {
783 struct proto_shell_state *state;
784 struct blob_attr *tb[__NOTIFY_LAST];
785
786 state = container_of(proto, struct proto_shell_state, proto);
787
788 blobmsg_parse(notify_attr, __NOTIFY_LAST, tb, blob_data(attr), blob_len(attr));
789 if (!tb[NOTIFY_ACTION])
790 return UBUS_STATUS_INVALID_ARGUMENT;
791
792 switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
793 case 0:
794 return proto_shell_update_link(state, attr, tb);
795 case 1:
796 return proto_shell_run_command(state, tb);
797 case 2:
798 return proto_shell_kill_command(state, tb);
799 case 3:
800 return proto_shell_notify_error(state, tb);
801 case 4:
802 return proto_shell_block_restart(state, tb);
803 case 5:
804 return proto_shell_set_available(state, tb);
805 case 6:
806 return proto_shell_add_host_dependency(state, tb);
807 case 7:
808 return proto_shell_setup_failed(state);
809 default:
810 return UBUS_STATUS_INVALID_ARGUMENT;
811 }
812 }
813
814 static void
815 proto_shell_checkup_timeout_cb(struct uloop_timeout *timeout)
816 {
817 struct proto_shell_state *state = container_of(timeout, struct
818 proto_shell_state, checkup_timeout);
819 struct interface_proto_state *proto = &state->proto;
820 struct interface *iface = proto->iface;
821
822 if (!iface->autostart)
823 return;
824
825 if (iface->state == IFS_UP)
826 return;
827
828 D(INTERFACE, "Interface '%s' is not up after %d sec\n",
829 iface->name, state->checkup_interval);
830 proto_shell_handler(proto, PROTO_CMD_TEARDOWN, false);
831 }
832
833 static void
834 proto_shell_checkup_attach(struct proto_shell_state *state,
835 const struct blob_attr *attr)
836 {
837 struct blob_attr *tb;
838 struct blobmsg_policy checkup_policy = {
839 .name = "checkup_interval",
840 .type = BLOBMSG_TYPE_INT32
841 };
842
843 blobmsg_parse(&checkup_policy, 1, &tb, blob_data(attr), blob_len(attr));
844 if (!tb) {
845 state->checkup_interval = -1;
846 state->checkup_timeout.cb = NULL;
847 } else {
848 state->checkup_interval = blobmsg_get_u32(tb);
849 state->checkup_timeout.cb = proto_shell_checkup_timeout_cb;
850 }
851 }
852
853 static struct interface_proto_state *
854 proto_shell_attach(const struct proto_handler *h, struct interface *iface,
855 struct blob_attr *attr)
856 {
857 struct proto_shell_state *state;
858
859 state = calloc(1, sizeof(*state));
860 if (!state)
861 return NULL;
862
863 INIT_LIST_HEAD(&state->deps);
864
865 state->config = malloc(blob_pad_len(attr));
866 if (!state->config)
867 goto error;
868
869 memcpy(state->config, attr, blob_pad_len(attr));
870 proto_shell_checkup_attach(state, state->config);
871 state->proto.free = proto_shell_free;
872 state->proto.notify = proto_shell_notify;
873 state->proto.cb = proto_shell_handler;
874 state->teardown_timeout.cb = proto_shell_teardown_timeout_cb;
875 state->script_task.cb = proto_shell_script_cb;
876 state->script_task.dir_fd = proto_fd;
877 state->script_task.log_prefix = iface->name;
878 state->proto_task.cb = proto_shell_task_cb;
879 state->proto_task.dir_fd = proto_fd;
880 state->proto_task.log_prefix = iface->name;
881 state->handler = container_of(h, struct proto_shell_handler, proto);
882
883 return &state->proto;
884
885 error:
886 free(state);
887 return NULL;
888 }
889
890 static void
891 proto_shell_add_handler(const char *script, const char *name, json_object *obj)
892 {
893 struct proto_shell_handler *handler;
894 struct proto_handler *proto;
895 json_object *config, *tmp;
896 char *proto_name, *script_name;
897
898 handler = calloc_a(sizeof(*handler),
899 &proto_name, strlen(name) + 1,
900 &script_name, strlen(script) + 1);
901 if (!handler)
902 return;
903
904 handler->script_name = strcpy(script_name, script);
905
906 proto = &handler->proto;
907 proto->name = strcpy(proto_name, name);
908 proto->config_params = &handler->config;
909 proto->attach = proto_shell_attach;
910
911 tmp = json_get_field(obj, "no-device", json_type_boolean);
912 if (tmp && json_object_get_boolean(tmp))
913 handler->proto.flags |= PROTO_FLAG_NODEV;
914
915 tmp = json_get_field(obj, "no-proto-task", json_type_boolean);
916 if (tmp && json_object_get_boolean(tmp))
917 handler->proto.flags |= PROTO_FLAG_NO_TASK;
918
919 tmp = json_get_field(obj, "available", json_type_boolean);
920 if (tmp && json_object_get_boolean(tmp))
921 handler->proto.flags |= PROTO_FLAG_INIT_AVAILABLE;
922
923 tmp = json_get_field(obj, "renew-handler", json_type_boolean);
924 if (tmp && json_object_get_boolean(tmp))
925 handler->proto.flags |= PROTO_FLAG_RENEW_AVAILABLE;
926
927 tmp = json_get_field(obj, "lasterror", json_type_boolean);
928 if (tmp && json_object_get_boolean(tmp))
929 handler->proto.flags |= PROTO_FLAG_LASTERROR;
930
931 tmp = json_get_field(obj, "teardown-on-l3-link-down", json_type_boolean);
932 if (tmp && json_object_get_boolean(tmp))
933 handler->proto.flags |= PROTO_FLAG_TEARDOWN_ON_L3_LINK_DOWN;
934
935 config = json_get_field(obj, "config", json_type_array);
936 if (config)
937 handler->config_buf = netifd_handler_parse_config(&handler->config, config);
938
939 DPRINTF("Add handler for script %s: %s\n", script, proto->name);
940 add_proto_handler(proto);
941 }
942
943 void proto_shell_init(void)
944 {
945 proto_fd = netifd_open_subdir("proto");
946 if (proto_fd < 0)
947 return;
948
949 netifd_init_script_handlers(proto_fd, proto_shell_add_handler);
950 }