• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/netifd/proto-ext.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 #include "proto-ext.h"
 25 #include "system.h"
 26 #include "handler.h"
 27 
 28 static void
 29 proto_ext_check_dependencies(struct proto_ext_state *state)
 30 {
 31         struct proto_ext_dep *dep;
 32         bool available = true;
 33 
 34         list_for_each_entry(dep, &state->deps, list) {
 35                 if (dep->dep.iface)
 36                         continue;
 37 
 38                 available = false;
 39                 break;
 40         }
 41 
 42         interface_set_available(state->proto.iface, available);
 43 }
 44 
 45 static void
 46 proto_ext_if_up_cb(struct interface_user *dep, struct interface *iface,
 47                    enum interface_event ev);
 48 static void
 49 proto_ext_if_down_cb(struct interface_user *dep, struct interface *iface,
 50                      enum interface_event ev);
 51 
 52 static void
 53 proto_ext_update_host_dep(struct proto_ext_dep *dep)
 54 {
 55         struct interface *iface = NULL;
 56 
 57         if (dep->dep.iface)
 58                 goto out;
 59 
 60         if (dep->interface[0]) {
 61                 iface = vlist_find(&interfaces, dep->interface, iface, node);
 62 
 63                 if (!iface || iface->state != IFS_UP)
 64                         goto out;
 65         }
 66 
 67         if (!dep->any)
 68                 iface = interface_ip_add_target_route(&dep->host, dep->v6, iface, false);
 69 
 70         if (!iface)
 71                 goto out;
 72 
 73         interface_remove_user(&dep->dep);
 74         dep->dep.cb = proto_ext_if_down_cb;
 75         interface_add_user(&dep->dep, iface);
 76 
 77 out:
 78         proto_ext_check_dependencies(dep->proto);
 79 }
 80 
 81 static void
 82 proto_ext_clear_host_dep(struct proto_ext_state *state)
 83 {
 84         struct proto_ext_dep *dep, *tmp;
 85 
 86         list_for_each_entry_safe(dep, tmp, &state->deps, list) {
 87                 interface_remove_user(&dep->dep);
 88                 list_del(&dep->list);
 89                 free(dep);
 90         }
 91 }
 92 
 93 static void
 94 proto_ext_if_up_cb(struct interface_user *dep, struct interface *iface,
 95                    enum interface_event ev)
 96 {
 97         struct proto_ext_dep *pdep;
 98 
 99         if (ev != IFEV_UP && ev != IFEV_UPDATE)
100                 return;
101 
102         pdep = container_of(dep, struct proto_ext_dep, dep);
103         proto_ext_update_host_dep(pdep);
104 }
105 
106 static void
107 proto_ext_if_down_cb(struct interface_user *dep, struct interface *iface,
108                      enum interface_event ev)
109 {
110         struct proto_ext_dep *pdep;
111         struct proto_ext_state *state;
112 
113         if (ev != IFEV_UP_FAILED && ev != IFEV_DOWN && ev != IFEV_FREE)
114                 return;
115 
116         pdep = container_of(dep, struct proto_ext_dep, dep);
117         interface_remove_user(dep);
118         dep->cb = proto_ext_if_up_cb;
119         interface_add_user(dep, NULL);
120 
121         state = pdep->proto;
122         if (state->sm == S_IDLE) {
123                 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
124                 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false);
125         }
126 }
127 
128 static void
129 proto_ext_task_finish(struct proto_ext_state *state,
130                       struct netifd_process *task)
131 {
132         switch (state->sm) {
133         case S_IDLE:
134                 if (task == &state->proto_task)
135                         state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
136                 fallthrough;
137         case S_SETUP:
138                 if (task == &state->proto_task)
139                         state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN,
140                                         false);
141                 else if (task == &state->script_task) {
142                         if (state->renew_pending)
143                                 state->proto.cb(&state->proto,
144                                                 PROTO_CMD_RENEW, false);
145                         else if (!(state->proto.handler->flags & PROTO_FLAG_NO_TASK) &&
146                                  !state->proto_task.uloop.pending &&
147                                  state->sm == S_SETUP)
148                                 state->proto.cb(&state->proto,
149                                                 PROTO_CMD_TEARDOWN,
150                                                 false);
151 
152                         if (state->sm == S_SETUP && state->checkup_interval > 0) {
153                                 uloop_timeout_set(&state->checkup_timeout,
154                                                   state->checkup_interval * 1000);
155                         }
156                 }
157                 break;
158 
159         case S_SETUP_ABORT:
160                 if (state->script_task.uloop.pending ||
161                     state->proto_task.uloop.pending)
162                         break;
163 
164                 uloop_timeout_cancel(&state->teardown_timeout);
165                 uloop_timeout_cancel(&state->checkup_timeout);
166                 state->sm = S_IDLE;
167                 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false);
168                 break;
169 
170         case S_TEARDOWN:
171                 if (state->script_task.uloop.pending)
172                         break;
173 
174                 if (state->proto_task.uloop.pending) {
175                         if (!state->proto_task_killed)
176                                 kill(state->proto_task.uloop.pid, SIGTERM);
177                         break;
178                 }
179 
180                 uloop_timeout_cancel(&state->teardown_timeout);
181                 uloop_timeout_cancel(&state->checkup_timeout);
182                 state->sm = S_IDLE;
183                 state->proto.proto_event(&state->proto, IFPEV_DOWN);
184                 break;
185         }
186 }
187 
188 static void
189 proto_ext_teardown_timeout_cb(struct uloop_timeout *timeout)
190 {
191         struct proto_ext_state *state;
192 
193         state = container_of(timeout, struct proto_ext_state, teardown_timeout);
194 
195         netifd_kill_process(&state->script_task);
196         netifd_kill_process(&state->proto_task);
197         proto_ext_task_finish(state, NULL);
198 }
199 
200 static void
201 proto_ext_script_cb(struct netifd_process *p, int ret)
202 {
203         struct proto_ext_state *state;
204 
205         state = container_of(p, struct proto_ext_state, script_task);
206         proto_ext_task_finish(state, p);
207 }
208 
209 static void
210 proto_ext_task_cb(struct netifd_process *p, int ret)
211 {
212         struct proto_ext_state *state;
213 
214         state = container_of(p, struct proto_ext_state, proto_task);
215 
216         if (state->sm == S_IDLE || state->sm == S_SETUP)
217                 state->last_error = WEXITSTATUS(ret);
218 
219         proto_ext_task_finish(state, p);
220 }
221 
222 void
223 proto_ext_free(struct interface_proto_state *proto)
224 {
225         struct proto_ext_state *state;
226 
227         state = container_of(proto, struct proto_ext_state, proto);
228         uloop_timeout_cancel(&state->teardown_timeout);
229         uloop_timeout_cancel(&state->checkup_timeout);
230         proto_ext_clear_host_dep(state);
231         netifd_kill_process(&state->script_task);
232         netifd_kill_process(&state->proto_task);
233         free(state->config);
234         free(state);
235 }
236 
237 static void
238 proto_ext_parse_route_list(struct interface *iface, struct blob_attr *attr,
239                            bool v6)
240 {
241         struct blob_attr *cur;
242         size_t rem;
243 
244         blobmsg_for_each_attr(cur, attr, rem) {
245                 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
246                         D(INTERFACE, "Ignore wrong route type: %d", blobmsg_type(cur));
247                         continue;
248                 }
249 
250                 interface_ip_add_route(iface, cur, v6);
251         }
252 }
253 
254 static void
255 proto_ext_parse_neighbor_list(struct interface *iface, struct blob_attr *attr,
256                               bool v6)
257 {
258         struct blob_attr *cur;
259         size_t rem;
260 
261         blobmsg_for_each_attr(cur, attr, rem) {
262                 if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE) {
263                         D(INTERFACE, "Ignore wrong neighbor type: %d", blobmsg_type(cur));
264                         continue;
265                 }
266 
267                 interface_ip_add_neighbor(iface, cur, v6);
268         }
269 }
270 
271 static void
272 proto_ext_parse_data(struct interface *iface, struct blob_attr *attr)
273 {
274         struct blob_attr *cur;
275         size_t rem;
276 
277         blobmsg_for_each_attr(cur, attr, rem)
278                 interface_add_data(iface, cur);
279 }
280 
281 static struct device *
282 proto_ext_create_tunnel(const char *name, struct blob_attr *attr)
283 {
284         struct device *dev;
285         struct blob_buf b;
286 
287         memset(&b, 0, sizeof(b));
288         blob_buf_init(&b, 0);
289         blob_put(&b, 0, blobmsg_data(attr), blobmsg_data_len(attr));
290         dev = device_create(name, &tunnel_device_type, blob_data(b.head));
291         blob_buf_free(&b);
292 
293         return dev;
294 }
295 
296 enum {
297         NOTIFY_ACTION,
298         NOTIFY_ERROR,
299         NOTIFY_COMMAND,
300         NOTIFY_ENV,
301         NOTIFY_SIGNAL,
302         NOTIFY_AVAILABLE,
303         NOTIFY_LINK_UP,
304         NOTIFY_IFNAME,
305         NOTIFY_ADDR_EXT,
306         NOTIFY_ROUTES,
307         NOTIFY_ROUTES6,
308         NOTIFY_TUNNEL,
309         NOTIFY_DATA,
310         NOTIFY_KEEP,
311         NOTIFY_HOST,
312         NOTIFY_DNS,
313         NOTIFY_DNS_SEARCH,
314         NOTIFY_NEIGHBORS,
315         NOTIFY_NEIGHBORS6,
316         __NOTIFY_LAST
317 };
318 
319 static const struct blobmsg_policy notify_attr[__NOTIFY_LAST] = {
320         [NOTIFY_ACTION] = { .name = "action", .type = BLOBMSG_TYPE_INT32 },
321         [NOTIFY_ERROR] = { .name = "error", .type = BLOBMSG_TYPE_ARRAY },
322         [NOTIFY_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_ARRAY },
323         [NOTIFY_ENV] = { .name = "env", .type = BLOBMSG_TYPE_ARRAY },
324         [NOTIFY_SIGNAL] = { .name = "signal", .type = BLOBMSG_TYPE_INT32 },
325         [NOTIFY_AVAILABLE] = { .name = "available", .type = BLOBMSG_TYPE_BOOL },
326         [NOTIFY_LINK_UP] = { .name = "link-up", .type = BLOBMSG_TYPE_BOOL },
327         [NOTIFY_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
328         [NOTIFY_ADDR_EXT] = { .name = "address-external", .type = BLOBMSG_TYPE_BOOL },
329         [NOTIFY_ROUTES] = { .name = "routes", .type = BLOBMSG_TYPE_ARRAY },
330         [NOTIFY_ROUTES6] = { .name = "routes6", .type = BLOBMSG_TYPE_ARRAY },
331         [NOTIFY_TUNNEL] = { .name = "tunnel", .type = BLOBMSG_TYPE_TABLE },
332         [NOTIFY_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
333         [NOTIFY_KEEP] = { .name = "keep", .type = BLOBMSG_TYPE_BOOL },
334         [NOTIFY_HOST] = { .name = "host", .type = BLOBMSG_TYPE_STRING },
335         [NOTIFY_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
336         [NOTIFY_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
337         [NOTIFY_NEIGHBORS]= {.name = "neighbor", .type = BLOBMSG_TYPE_ARRAY},
338         [NOTIFY_NEIGHBORS6]= {.name = "neighbor6", .type = BLOBMSG_TYPE_ARRAY},
339 };
340 
341 static int
342 proto_ext_update_link(struct proto_ext_state *state, struct blob_attr *data, struct blob_attr **tb)
343 {
344         struct interface *iface = state->proto.iface;
345         struct blob_attr *cur;
346         struct device *dev;
347         const char *devname;
348         int dev_create = 1;
349         bool addr_ext = false;
350         bool keep = false;
351         bool up;
352 
353         if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
354                 return UBUS_STATUS_PERMISSION_DENIED;
355 
356         if (!tb[NOTIFY_LINK_UP])
357                 return UBUS_STATUS_INVALID_ARGUMENT;
358 
359         up = blobmsg_get_bool(tb[NOTIFY_LINK_UP]);
360         if (!up) {
361                 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
362                 return 0;
363         }
364 
365         if ((cur = tb[NOTIFY_KEEP]) != NULL)
366                 keep = blobmsg_get_bool(cur);
367 
368         if ((cur = tb[NOTIFY_ADDR_EXT]) != NULL) {
369                 addr_ext = blobmsg_get_bool(cur);
370                 if (addr_ext)
371                         dev_create = 2;
372         }
373 
374         if (iface->state != IFS_UP || !iface->l3_dev.dev)
375                 keep = false;
376 
377         if (!keep) {
378                 dev = iface->main_dev.dev;
379                 if (tb[NOTIFY_IFNAME]) {
380                         keep = false;
381                         devname = blobmsg_data(tb[NOTIFY_IFNAME]);
382                         if (tb[NOTIFY_TUNNEL])
383                                 dev = proto_ext_create_tunnel(devname, tb[NOTIFY_TUNNEL]);
384                         else
385                                 dev = device_get(devname, dev_create);
386                 }
387 
388                 if (!dev)
389                         return UBUS_STATUS_INVALID_ARGUMENT;
390 
391                 interface_set_l3_dev(iface, dev);
392                 if (device_claim(&iface->l3_dev) < 0)
393                         return UBUS_STATUS_UNKNOWN_ERROR;
394 
395                 device_set_present(dev, true);
396         }
397 
398         interface_update_start(iface, keep);
399 
400         proto_apply_ip_settings(iface, data, addr_ext);
401 
402         if ((cur = tb[NOTIFY_ROUTES]) != NULL)
403                 proto_ext_parse_route_list(state->proto.iface, cur, false);
404 
405         if ((cur = tb[NOTIFY_ROUTES6]) != NULL)
406                 proto_ext_parse_route_list(state->proto.iface, cur, true);
407 
408         if ((cur = tb[NOTIFY_NEIGHBORS]) != NULL)
409                 proto_ext_parse_neighbor_list(state->proto.iface, cur, false);
410 
411         if ((cur = tb[NOTIFY_NEIGHBORS6]) != NULL)
412                 proto_ext_parse_neighbor_list(state->proto.iface, cur, true);
413 
414         if ((cur = tb[NOTIFY_DNS]))
415                 interface_add_dns_server_list(&iface->proto_ip, cur);
416 
417         if ((cur = tb[NOTIFY_DNS_SEARCH]))
418                 interface_add_dns_search_list(&iface->proto_ip, cur);
419 
420         if ((cur = tb[NOTIFY_DATA]))
421                 proto_ext_parse_data(state->proto.iface, cur);
422 
423         interface_update_complete(state->proto.iface);
424 
425         if ((state->sm != S_SETUP_ABORT) && (state->sm != S_TEARDOWN)) {
426                 state->proto.proto_event(&state->proto, IFPEV_UP);
427                 state->sm = S_IDLE;
428         }
429 
430         return 0;
431 }
432 
433 static bool
434 fill_string_list(struct blob_attr *attr, char **argv, int max)
435 {
436         struct blob_attr *cur;
437         int argc = 0;
438         size_t rem;
439 
440         if (!attr)
441                 goto out;
442 
443         blobmsg_for_each_attr(cur, attr, rem) {
444                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
445                         return false;
446 
447                 if (!blobmsg_check_attr(cur, false))
448                         return false;
449 
450                 argv[argc++] = blobmsg_data(cur);
451                 if (argc == max - 1)
452                         return false;
453         }
454 
455 out:
456         argv[argc] = NULL;
457         return true;
458 }
459 
460 static int
461 proto_ext_run_command(struct proto_ext_state *state, struct blob_attr **tb)
462 {
463         static char *argv[64];
464         static char *env[32];
465 
466         if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
467                 return UBUS_STATUS_PERMISSION_DENIED;
468 
469         if (!tb[NOTIFY_COMMAND])
470                 goto error;
471 
472         if (!fill_string_list(tb[NOTIFY_COMMAND], argv, ARRAY_SIZE(argv)))
473                 goto error;
474 
475         if (!fill_string_list(tb[NOTIFY_ENV], env, ARRAY_SIZE(env)))
476                 goto error;
477 
478         netifd_start_process((const char **) argv, (char **) env, &state->proto_task);
479 
480         return 0;
481 
482 error:
483         return UBUS_STATUS_INVALID_ARGUMENT;
484 }
485 
486 static int
487 proto_ext_kill_command(struct proto_ext_state *state, struct blob_attr **tb)
488 {
489         unsigned int signal = ~0;
490 
491         if (tb[NOTIFY_SIGNAL])
492                 signal = blobmsg_get_u32(tb[NOTIFY_SIGNAL]);
493 
494         if (signal > 31)
495                 signal = SIGTERM;
496 
497         if (state->proto_task.uloop.pending) {
498                 if (signal == SIGTERM || signal == SIGKILL)
499                         state->proto_task_killed = true;
500                 kill(state->proto_task.uloop.pid, signal);
501         }
502 
503         return 0;
504 }
505 
506 static int
507 proto_ext_notify_error(struct proto_ext_state *state, struct blob_attr **tb)
508 {
509         struct blob_attr *cur;
510         char *data[16];
511         int n_data = 0;
512         size_t rem;
513 
514         if (!tb[NOTIFY_ERROR])
515                 return UBUS_STATUS_INVALID_ARGUMENT;
516 
517         blobmsg_for_each_attr(cur, tb[NOTIFY_ERROR], rem) {
518                 if (n_data + 1 == ARRAY_SIZE(data))
519                         goto error;
520 
521                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
522                         goto error;
523 
524                 if (!blobmsg_check_attr(cur, false))
525                         goto error;
526 
527                 data[n_data++] = blobmsg_data(cur);
528         }
529 
530         if (!n_data)
531                 goto error;
532 
533         interface_add_error(state->proto.iface, state->proto.handler->name,
534                         data[0], (const char **) &data[1], n_data - 1);
535 
536         return 0;
537 
538 error:
539         return UBUS_STATUS_INVALID_ARGUMENT;
540 }
541 
542 static int
543 proto_ext_block_restart(struct proto_ext_state *state, struct blob_attr **tb)
544 {
545         state->proto.iface->autostart = false;
546         return 0;
547 }
548 
549 static int
550 proto_ext_set_available(struct proto_ext_state *state, struct blob_attr **tb)
551 {
552         if (!tb[NOTIFY_AVAILABLE])
553                 return UBUS_STATUS_INVALID_ARGUMENT;
554 
555         interface_set_available(state->proto.iface, blobmsg_get_bool(tb[NOTIFY_AVAILABLE]));
556         return 0;
557 }
558 
559 static int
560 proto_ext_add_host_dependency(struct proto_ext_state *state, struct blob_attr **tb)
561 {
562         struct proto_ext_dep *dep;
563         const char *ifname = tb[NOTIFY_IFNAME] ? blobmsg_data(tb[NOTIFY_IFNAME]) : "";
564         const char *host = tb[NOTIFY_HOST] ? blobmsg_data(tb[NOTIFY_HOST]) : "";
565 
566         if (state->sm == S_TEARDOWN || state->sm == S_SETUP_ABORT)
567                 return UBUS_STATUS_PERMISSION_DENIED;
568 
569         dep = calloc(1, sizeof(*dep) + strlen(ifname) + 1);
570         if (!dep)
571                 return UBUS_STATUS_UNKNOWN_ERROR;
572 
573         if (!host[0] && ifname[0]) {
574                 dep->any = true;
575         } else if (inet_pton(AF_INET, host, &dep->host) < 1) {
576                 if (inet_pton(AF_INET6, host, &dep->host) < 1) {
577                         free(dep);
578                         return UBUS_STATUS_INVALID_ARGUMENT;
579                 } else {
580                         dep->v6 = true;
581                 }
582         }
583 
584         dep->proto = state;
585         strcpy(dep->interface, ifname);
586 
587         dep->dep.cb = proto_ext_if_up_cb;
588         interface_add_user(&dep->dep, NULL);
589         list_add(&dep->list, &state->deps);
590         proto_ext_update_host_dep(dep);
591         if (!dep->dep.iface)
592                 return UBUS_STATUS_NOT_FOUND;
593 
594         return 0;
595 }
596 
597 static int
598 proto_ext_setup_failed(struct proto_ext_state *state)
599 {
600         int ret = 0;
601 
602         switch (state->sm) {
603         case S_IDLE:
604                 state->proto.proto_event(&state->proto, IFPEV_LINK_LOST);
605                 fallthrough;
606         case S_SETUP:
607                 state->proto.cb(&state->proto, PROTO_CMD_TEARDOWN, false);
608                 break;
609         case S_SETUP_ABORT:
610         case S_TEARDOWN:
611         default:
612                 ret = UBUS_STATUS_PERMISSION_DENIED;
613                 break;
614         }
615         return ret;
616 }
617 
618 int
619 proto_ext_notify(struct interface_proto_state *proto, struct blob_attr *attr)
620 {
621         struct proto_ext_state *state;
622         struct blob_attr *tb[__NOTIFY_LAST];
623 
624         state = container_of(proto, struct proto_ext_state, proto);
625 
626         blobmsg_parse_attr(notify_attr, __NOTIFY_LAST, tb, attr);
627         if (!tb[NOTIFY_ACTION])
628                 return UBUS_STATUS_INVALID_ARGUMENT;
629 
630         switch(blobmsg_get_u32(tb[NOTIFY_ACTION])) {
631         case 0:
632                 return proto_ext_update_link(state, attr, tb);
633         case 1:
634                 return proto_ext_run_command(state, tb);
635         case 2:
636                 return proto_ext_kill_command(state, tb);
637         case 3:
638                 return proto_ext_notify_error(state, tb);
639         case 4:
640                 return proto_ext_block_restart(state, tb);
641         case 5:
642                 return proto_ext_set_available(state, tb);
643         case 6:
644                 return proto_ext_add_host_dependency(state, tb);
645         case 7:
646                 return proto_ext_setup_failed(state);
647         default:
648                 return UBUS_STATUS_INVALID_ARGUMENT;
649         }
650 }
651 
652 static void
653 proto_ext_checkup_timeout_cb(struct uloop_timeout *timeout)
654 {
655         struct proto_ext_state *state = container_of(timeout, struct
656                         proto_ext_state, checkup_timeout);
657         struct interface_proto_state *proto = &state->proto;
658         struct interface *iface = proto->iface;
659 
660         if (!iface->autostart)
661                 return;
662 
663         if (iface->state == IFS_UP)
664                 return;
665 
666         D(INTERFACE, "Interface '%s' is not up after %d sec",
667                         iface->name, state->checkup_interval);
668         state->proto.cb(proto, PROTO_CMD_TEARDOWN, false);
669 }
670 
671 static void
672 proto_ext_checkup_attach(struct proto_ext_state *state,
673                 const struct blob_attr *attr)
674 {
675         struct blob_attr *tb;
676         struct blobmsg_policy checkup_policy = {
677                 .name = "checkup_interval",
678                 .type = BLOBMSG_TYPE_INT32
679         };
680 
681         blobmsg_parse_attr(&checkup_policy, 1, &tb, (struct blob_attr *)attr);
682         if (!tb) {
683                 state->checkup_interval = -1;
684                 state->checkup_timeout.cb = NULL;
685         } else {
686                 state->checkup_interval = blobmsg_get_u32(tb);
687                 state->checkup_timeout.cb = proto_ext_checkup_timeout_cb;
688         }
689 }
690 
691 void
692 proto_ext_state_init(struct proto_ext_state *state,
693                      struct interface *iface, struct blob_attr *attr,
694                      int dir_fd)
695 {
696         INIT_LIST_HEAD(&state->deps);
697 
698         state->config = malloc(blob_pad_len(attr));
699         if (!state->config)
700                 return;
701 
702         memcpy(state->config, attr, blob_pad_len(attr));
703         proto_ext_checkup_attach(state, state->config);
704         state->proto.free = proto_ext_free;
705         state->proto.notify = proto_ext_notify;
706         state->teardown_timeout.cb = proto_ext_teardown_timeout_cb;
707         state->script_task.cb = proto_ext_script_cb;
708         state->script_task.dir_fd = dir_fd;
709         state->script_task.log_prefix = iface->name;
710         state->proto_task.cb = proto_ext_task_cb;
711         state->proto_task.dir_fd = dir_fd;
712         state->proto_task.log_prefix = iface->name;
713 }
714 
715 int
716 proto_ext_run(struct proto_ext_state *state,
717               enum interface_proto_cmd cmd, bool force,
718               proto_ext_handler_cb start_cb)
719 {
720         struct interface_proto_state *proto = &state->proto;
721         static char error_buf[32];
722         char *envp[2];
723         const char *action;
724         char *config;
725         int ret, j = 0;
726 
727         if (cmd == PROTO_CMD_SETUP) {
728                 switch (state->sm) {
729                 case S_IDLE:
730                         action = "setup";
731                         state->last_error = -1;
732                         proto_ext_clear_host_dep(state);
733                         state->sm = S_SETUP;
734                         break;
735 
736                 default:
737                         return -1;
738                 }
739         } else if (cmd == PROTO_CMD_RENEW) {
740                 if (!(proto->handler->flags & PROTO_FLAG_RENEW_AVAILABLE))
741                         return 0;
742 
743                 if (state->script_task.uloop.pending) {
744                         state->renew_pending = true;
745                         return 0;
746                 }
747 
748                 state->renew_pending = false;
749                 action = "renew";
750         } else {
751                 switch (state->sm) {
752                 case S_SETUP:
753                         if (state->script_task.uloop.pending) {
754                                 uloop_timeout_set(&state->teardown_timeout, 1000);
755                                 kill(state->script_task.uloop.pid, SIGTERM);
756                                 if (state->proto_task.uloop.pending)
757                                         kill(state->proto_task.uloop.pid, SIGTERM);
758                                 state->renew_pending = false;
759                                 state->sm = S_SETUP_ABORT;
760                                 return 0;
761                         }
762                 fallthrough;
763                 case S_IDLE:
764                         action = "teardown";
765                         state->renew_pending = false;
766                         state->sm = S_TEARDOWN;
767                         if (state->last_error >= 0) {
768                                 snprintf(error_buf, sizeof(error_buf), "ERROR=%d", state->last_error);
769                                 envp[j++] = error_buf;
770                         }
771                         uloop_timeout_set(&state->teardown_timeout, 5000);
772                         break;
773 
774                 case S_TEARDOWN:
775                         return 0;
776 
777                 default:
778                         return -1;
779                 }
780         }
781 
782         D(INTERFACE, "run %s for interface '%s'", action, proto->iface->name);
783         config = blobmsg_format_json(state->config, true);
784         if (!config)
785                 return -1;
786 
787         envp[j] = NULL;
788 
789         ret = start_cb(state, action, config, envp);
790         free(config);
791 
792         return ret;
793 }
794 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt