proto-shell.c 23 KB

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