ubus.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  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 <arpa/inet.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include "netifd.h"
  19. #include "interface.h"
  20. #include "proto.h"
  21. #include "ubus.h"
  22. #include "system.h"
  23. #include "wireless.h"
  24. struct ubus_context *ubus_ctx = NULL;
  25. static struct blob_buf b;
  26. static const char *ubus_path;
  27. /* global object */
  28. static int
  29. netifd_handle_restart(struct ubus_context *ctx, struct ubus_object *obj,
  30. struct ubus_request_data *req, const char *method,
  31. struct blob_attr *msg)
  32. {
  33. netifd_restart();
  34. return 0;
  35. }
  36. static int
  37. netifd_handle_reload(struct ubus_context *ctx, struct ubus_object *obj,
  38. struct ubus_request_data *req, const char *method,
  39. struct blob_attr *msg)
  40. {
  41. if (netifd_reload())
  42. return UBUS_STATUS_NOT_FOUND;
  43. return UBUS_STATUS_OK;
  44. }
  45. enum {
  46. HR_TARGET,
  47. HR_V6,
  48. HR_INTERFACE,
  49. __HR_MAX
  50. };
  51. static const struct blobmsg_policy route_policy[__HR_MAX] = {
  52. [HR_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING },
  53. [HR_V6] = { .name = "v6", .type = BLOBMSG_TYPE_BOOL },
  54. [HR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
  55. };
  56. static int
  57. netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
  58. struct ubus_request_data *req, const char *method,
  59. struct blob_attr *msg)
  60. {
  61. struct blob_attr *tb[__HR_MAX];
  62. struct interface *iface = NULL;
  63. union if_addr a;
  64. bool v6 = false;
  65. blobmsg_parse(route_policy, __HR_MAX, tb, blob_data(msg), blob_len(msg));
  66. if (!tb[HR_TARGET])
  67. return UBUS_STATUS_INVALID_ARGUMENT;
  68. if (tb[HR_V6])
  69. v6 = blobmsg_get_bool(tb[HR_V6]);
  70. if (tb[HR_INTERFACE])
  71. iface = vlist_find(&interfaces, blobmsg_data(tb[HR_INTERFACE]), iface, node);
  72. memset(&a, 0, sizeof(a));
  73. if (!inet_pton(v6 ? AF_INET6 : AF_INET, blobmsg_data(tb[HR_TARGET]), &a))
  74. return UBUS_STATUS_INVALID_ARGUMENT;
  75. iface = interface_ip_add_target_route(&a, v6, iface);
  76. if (!iface)
  77. return UBUS_STATUS_NOT_FOUND;
  78. blob_buf_init(&b, 0);
  79. blobmsg_add_string(&b, "interface", iface->name);
  80. ubus_send_reply(ctx, req, b.head);
  81. return 0;
  82. }
  83. static int
  84. netifd_get_proto_handlers(struct ubus_context *ctx, struct ubus_object *obj,
  85. struct ubus_request_data *req, const char *method,
  86. struct blob_attr *msg)
  87. {
  88. blob_buf_init(&b, 0);
  89. proto_dump_handlers(&b);
  90. ubus_send_reply(ctx, req, b.head);
  91. return 0;
  92. }
  93. enum {
  94. DI_NAME,
  95. __DI_MAX
  96. };
  97. static const struct blobmsg_policy dynamic_policy[__DI_MAX] = {
  98. [DI_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  99. };
  100. static int
  101. netifd_add_dynamic(struct ubus_context *ctx, struct ubus_object *obj,
  102. struct ubus_request_data *req, const char *method,
  103. struct blob_attr *msg)
  104. {
  105. struct blob_attr *tb[__DI_MAX];
  106. struct interface *iface;
  107. struct blob_attr *config;
  108. blobmsg_parse(dynamic_policy, __DI_MAX, tb, blob_data(msg), blob_len(msg));
  109. if (!tb[DI_NAME])
  110. return UBUS_STATUS_INVALID_ARGUMENT;
  111. const char *name = blobmsg_get_string(tb[DI_NAME]);
  112. iface = interface_alloc(name, msg, true);
  113. if (!iface)
  114. return UBUS_STATUS_UNKNOWN_ERROR;
  115. config = blob_memdup(msg);
  116. if (!config)
  117. goto error;
  118. if (!interface_add(iface, config))
  119. goto error_free_config;
  120. return UBUS_STATUS_OK;
  121. error_free_config:
  122. free(config);
  123. error:
  124. free(iface);
  125. return UBUS_STATUS_UNKNOWN_ERROR;
  126. }
  127. static struct ubus_method main_object_methods[] = {
  128. { .name = "restart", .handler = netifd_handle_restart },
  129. { .name = "reload", .handler = netifd_handle_reload },
  130. UBUS_METHOD("add_host_route", netifd_add_host_route, route_policy),
  131. { .name = "get_proto_handlers", .handler = netifd_get_proto_handlers },
  132. UBUS_METHOD("add_dynamic", netifd_add_dynamic, dynamic_policy),
  133. };
  134. static struct ubus_object_type main_object_type =
  135. UBUS_OBJECT_TYPE("netifd", main_object_methods);
  136. static struct ubus_object main_object = {
  137. .name = "network",
  138. .type = &main_object_type,
  139. .methods = main_object_methods,
  140. .n_methods = ARRAY_SIZE(main_object_methods),
  141. };
  142. enum {
  143. DEV_NAME,
  144. __DEV_MAX,
  145. };
  146. static const struct blobmsg_policy dev_policy[__DEV_MAX] = {
  147. [DEV_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  148. };
  149. static int
  150. netifd_dev_status(struct ubus_context *ctx, struct ubus_object *obj,
  151. struct ubus_request_data *req, const char *method,
  152. struct blob_attr *msg)
  153. {
  154. struct device *dev = NULL;
  155. struct blob_attr *tb[__DEV_MAX];
  156. blobmsg_parse(dev_policy, __DEV_MAX, tb, blob_data(msg), blob_len(msg));
  157. if (tb[DEV_NAME]) {
  158. dev = device_find(blobmsg_data(tb[DEV_NAME]));
  159. if (!dev)
  160. return UBUS_STATUS_INVALID_ARGUMENT;
  161. }
  162. blob_buf_init(&b, 0);
  163. device_dump_status(&b, dev);
  164. ubus_send_reply(ctx, req, b.head);
  165. return 0;
  166. }
  167. enum {
  168. ALIAS_ATTR_ALIAS,
  169. ALIAS_ATTR_DEV,
  170. __ALIAS_ATTR_MAX,
  171. };
  172. static const struct blobmsg_policy alias_attrs[__ALIAS_ATTR_MAX] = {
  173. [ALIAS_ATTR_ALIAS] = { "alias", BLOBMSG_TYPE_ARRAY },
  174. [ALIAS_ATTR_DEV] = { "device", BLOBMSG_TYPE_STRING },
  175. };
  176. static int
  177. netifd_handle_alias(struct ubus_context *ctx, struct ubus_object *obj,
  178. struct ubus_request_data *req, const char *method,
  179. struct blob_attr *msg)
  180. {
  181. struct device *dev = NULL;
  182. struct blob_attr *tb[__ALIAS_ATTR_MAX];
  183. struct blob_attr *cur;
  184. int rem;
  185. blobmsg_parse(alias_attrs, __ALIAS_ATTR_MAX, tb, blob_data(msg), blob_len(msg));
  186. if (!tb[ALIAS_ATTR_ALIAS])
  187. return UBUS_STATUS_INVALID_ARGUMENT;
  188. if ((cur = tb[ALIAS_ATTR_DEV]) != NULL) {
  189. dev = device_get(blobmsg_data(cur), true);
  190. if (!dev)
  191. return UBUS_STATUS_NOT_FOUND;
  192. }
  193. blobmsg_for_each_attr(cur, tb[ALIAS_ATTR_ALIAS], rem) {
  194. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  195. goto error;
  196. if (!blobmsg_check_attr(cur, false))
  197. goto error;
  198. alias_notify_device(blobmsg_data(cur), dev);
  199. }
  200. return 0;
  201. error:
  202. device_free_unused(dev);
  203. return UBUS_STATUS_INVALID_ARGUMENT;
  204. }
  205. enum {
  206. DEV_STATE_NAME,
  207. DEV_STATE_DEFER,
  208. __DEV_STATE_MAX,
  209. };
  210. static const struct blobmsg_policy dev_state_policy[__DEV_STATE_MAX] = {
  211. [DEV_STATE_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  212. [DEV_STATE_DEFER] = { .name = "defer", .type = BLOBMSG_TYPE_BOOL },
  213. };
  214. static int
  215. netifd_handle_set_state(struct ubus_context *ctx, struct ubus_object *obj,
  216. struct ubus_request_data *req, const char *method,
  217. struct blob_attr *msg)
  218. {
  219. struct device *dev = NULL;
  220. struct blob_attr *tb[__DEV_STATE_MAX];
  221. struct blob_attr *cur;
  222. blobmsg_parse(dev_state_policy, __DEV_STATE_MAX, tb, blob_data(msg), blob_len(msg));
  223. cur = tb[DEV_STATE_NAME];
  224. if (!cur)
  225. return UBUS_STATUS_INVALID_ARGUMENT;
  226. dev = device_find(blobmsg_data(cur));
  227. if (!dev)
  228. return UBUS_STATUS_NOT_FOUND;
  229. cur = tb[DEV_STATE_DEFER];
  230. if (cur)
  231. device_set_deferred(dev, !!blobmsg_get_u8(cur));
  232. return 0;
  233. }
  234. static struct ubus_method dev_object_methods[] = {
  235. UBUS_METHOD("status", netifd_dev_status, dev_policy),
  236. UBUS_METHOD("set_alias", netifd_handle_alias, alias_attrs),
  237. UBUS_METHOD("set_state", netifd_handle_set_state, dev_state_policy),
  238. };
  239. static struct ubus_object_type dev_object_type =
  240. UBUS_OBJECT_TYPE("device", dev_object_methods);
  241. static struct ubus_object dev_object = {
  242. .name = "network.device",
  243. .type = &dev_object_type,
  244. .methods = dev_object_methods,
  245. .n_methods = ARRAY_SIZE(dev_object_methods),
  246. };
  247. static void
  248. netifd_ubus_add_fd(void)
  249. {
  250. ubus_add_uloop(ubus_ctx);
  251. system_fd_set_cloexec(ubus_ctx->sock.fd);
  252. }
  253. static void
  254. netifd_ubus_reconnect_timer(struct uloop_timeout *timeout)
  255. {
  256. static struct uloop_timeout retry = {
  257. .cb = netifd_ubus_reconnect_timer,
  258. };
  259. int t = 2;
  260. if (ubus_reconnect(ubus_ctx, ubus_path) != 0) {
  261. DPRINTF("failed to reconnect, trying again in %d seconds\n", t);
  262. uloop_timeout_set(&retry, t * 1000);
  263. return;
  264. }
  265. DPRINTF("reconnected to ubus, new id: %08x\n", ubus_ctx->local_id);
  266. netifd_ubus_add_fd();
  267. }
  268. static void
  269. netifd_ubus_connection_lost(struct ubus_context *ctx)
  270. {
  271. netifd_ubus_reconnect_timer(NULL);
  272. }
  273. /* per-interface object */
  274. static int
  275. netifd_handle_up(struct ubus_context *ctx, struct ubus_object *obj,
  276. struct ubus_request_data *req, const char *method,
  277. struct blob_attr *msg)
  278. {
  279. struct interface *iface;
  280. iface = container_of(obj, struct interface, ubus);
  281. interface_set_up(iface);
  282. return 0;
  283. }
  284. static int
  285. netifd_handle_down(struct ubus_context *ctx, struct ubus_object *obj,
  286. struct ubus_request_data *req, const char *method,
  287. struct blob_attr *msg)
  288. {
  289. struct interface *iface;
  290. iface = container_of(obj, struct interface, ubus);
  291. interface_set_down(iface);
  292. return 0;
  293. }
  294. static int
  295. netifd_handle_renew(struct ubus_context *ctx, struct ubus_object *obj,
  296. struct ubus_request_data *req, const char *method,
  297. struct blob_attr *msg)
  298. {
  299. struct interface *iface;
  300. iface = container_of(obj, struct interface, ubus);
  301. interface_renew(iface);
  302. return 0;
  303. }
  304. static void
  305. netifd_add_interface_errors(struct blob_buf *b, struct interface *iface)
  306. {
  307. struct interface_error *error;
  308. void *e, *e2, *e3;
  309. int i;
  310. e = blobmsg_open_array(b, "errors");
  311. list_for_each_entry(error, &iface->errors, list) {
  312. e2 = blobmsg_open_table(b, NULL);
  313. blobmsg_add_string(b, "subsystem", error->subsystem);
  314. blobmsg_add_string(b, "code", error->code);
  315. if (error->data[0]) {
  316. e3 = blobmsg_open_array(b, "data");
  317. for (i = 0; error->data[i]; i++)
  318. blobmsg_add_string(b, NULL, error->data[i]);
  319. blobmsg_close_array(b, e3);
  320. }
  321. blobmsg_close_table(b, e2);
  322. }
  323. blobmsg_close_array(b, e);
  324. }
  325. static void
  326. interface_ip_dump_address_list(struct interface_ip_settings *ip, bool v6, bool enabled)
  327. {
  328. struct device_addr *addr;
  329. char *buf;
  330. void *a;
  331. int buflen = 128;
  332. int af;
  333. time_t now = system_get_rtime();
  334. vlist_for_each_element(&ip->addr, addr, node) {
  335. if (addr->enabled != enabled)
  336. continue;
  337. if ((addr->flags & DEVADDR_FAMILY) == DEVADDR_INET4)
  338. af = AF_INET;
  339. else
  340. af = AF_INET6;
  341. if (af != (v6 ? AF_INET6 : AF_INET))
  342. continue;
  343. a = blobmsg_open_table(&b, NULL);
  344. buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
  345. inet_ntop(af, &addr->addr, buf, buflen);
  346. blobmsg_add_string_buffer(&b);
  347. blobmsg_add_u32(&b, "mask", addr->mask);
  348. if (addr->point_to_point) {
  349. buf = blobmsg_alloc_string_buffer(&b, "ptpaddress", buflen);
  350. inet_ntop(af, &addr->point_to_point, buf, buflen);
  351. blobmsg_add_string_buffer(&b);
  352. }
  353. if (addr->preferred_until) {
  354. int preferred = addr->preferred_until - now;
  355. if (preferred < 0)
  356. preferred = 0;
  357. blobmsg_add_u32(&b, "preferred", preferred);
  358. }
  359. if (addr->valid_until)
  360. blobmsg_add_u32(&b, "valid", addr->valid_until - now);
  361. if (addr->pclass)
  362. blobmsg_add_string(&b, "class", addr->pclass);
  363. blobmsg_close_table(&b, a);
  364. }
  365. }
  366. static void
  367. interface_ip_dump_neighbor_list(struct interface_ip_settings *ip, bool enabled)
  368. {
  369. struct device_neighbor *neighbor;
  370. int buflen = 128;
  371. char *buf;
  372. void *r;
  373. int af;
  374. vlist_for_each_element(&ip->neighbor, neighbor, node) {
  375. if (neighbor->enabled != enabled)
  376. continue;
  377. if ((neighbor->flags & DEVADDR_FAMILY) == DEVADDR_INET4)
  378. af = AF_INET;
  379. else
  380. af = AF_INET6;
  381. r = blobmsg_open_table(&b, NULL);
  382. if (neighbor->flags & DEVNEIGH_MAC)
  383. blobmsg_add_string(&b, "mac", format_macaddr(neighbor->macaddr));
  384. buf = blobmsg_alloc_string_buffer(&b , "address", buflen);
  385. inet_ntop(af, &neighbor->addr, buf, buflen);
  386. blobmsg_add_string_buffer(&b);
  387. if (neighbor->proxy)
  388. blobmsg_add_u32(&b, "proxy", neighbor->proxy);
  389. if (neighbor->router)
  390. blobmsg_add_u32(&b, "router", neighbor->router);
  391. blobmsg_close_table(&b, r);
  392. }
  393. }
  394. static void
  395. interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled)
  396. {
  397. struct device_route *route;
  398. int buflen = 128;
  399. char *buf;
  400. void *r;
  401. int af;
  402. time_t now = system_get_rtime();
  403. vlist_for_each_element(&ip->route, route, node) {
  404. if (route->enabled != enabled)
  405. continue;
  406. if ((ip->no_defaultroute == enabled) && !route->mask)
  407. continue;
  408. if ((route->flags & DEVADDR_FAMILY) == DEVADDR_INET4)
  409. af = AF_INET;
  410. else
  411. af = AF_INET6;
  412. r = blobmsg_open_table(&b, NULL);
  413. buf = blobmsg_alloc_string_buffer(&b, "target", buflen);
  414. inet_ntop(af, &route->addr, buf, buflen);
  415. blobmsg_add_string_buffer(&b);
  416. blobmsg_add_u32(&b, "mask", route->mask);
  417. buf = blobmsg_alloc_string_buffer(&b, "nexthop", buflen);
  418. inet_ntop(af, &route->nexthop, buf, buflen);
  419. blobmsg_add_string_buffer(&b);
  420. if (route->flags & DEVROUTE_TYPE)
  421. blobmsg_add_u32(&b, "type", route->type);
  422. if (route->flags & DEVROUTE_PROTO)
  423. blobmsg_add_u32(&b, "proto", route->proto);
  424. if (route->flags & DEVROUTE_MTU)
  425. blobmsg_add_u32(&b, "mtu", route->mtu);
  426. if (route->flags & DEVROUTE_METRIC)
  427. blobmsg_add_u32(&b, "metric", route->metric);
  428. if (route->flags & DEVROUTE_TABLE)
  429. blobmsg_add_u32(&b, "table", route->table);
  430. if (route->valid_until)
  431. blobmsg_add_u32(&b, "valid", route->valid_until - now);
  432. buf = blobmsg_alloc_string_buffer(&b, "source", buflen);
  433. inet_ntop(af, &route->source, buf, buflen);
  434. snprintf(buf + strlen(buf), buflen - strlen(buf), "/%u", route->sourcemask);
  435. blobmsg_add_string_buffer(&b);
  436. blobmsg_close_table(&b, r);
  437. }
  438. }
  439. static void
  440. interface_ip_dump_prefix_list(struct interface_ip_settings *ip)
  441. {
  442. struct device_prefix *prefix;
  443. char *buf;
  444. void *a, *c;
  445. const int buflen = INET6_ADDRSTRLEN;
  446. time_t now = system_get_rtime();
  447. vlist_for_each_element(&ip->prefix, prefix, node) {
  448. a = blobmsg_open_table(&b, NULL);
  449. buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
  450. inet_ntop(AF_INET6, &prefix->addr, buf, buflen);
  451. blobmsg_add_string_buffer(&b);
  452. blobmsg_add_u32(&b, "mask", prefix->length);
  453. if (prefix->preferred_until) {
  454. int preferred = prefix->preferred_until - now;
  455. if (preferred < 0)
  456. preferred = 0;
  457. blobmsg_add_u32(&b, "preferred", preferred);
  458. }
  459. if (prefix->valid_until)
  460. blobmsg_add_u32(&b, "valid", prefix->valid_until - now);
  461. blobmsg_add_string(&b, "class", prefix->pclass);
  462. c = blobmsg_open_table(&b, "assigned");
  463. struct device_prefix_assignment *assign;
  464. list_for_each_entry(assign, &prefix->assignments, head) {
  465. if (!assign->name[0])
  466. continue;
  467. struct in6_addr addr = prefix->addr;
  468. addr.s6_addr32[1] |= htonl(assign->assigned);
  469. void *d = blobmsg_open_table(&b, assign->name);
  470. buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
  471. inet_ntop(AF_INET6, &addr, buf, buflen);
  472. blobmsg_add_string_buffer(&b);
  473. blobmsg_add_u32(&b, "mask", assign->length);
  474. blobmsg_close_table(&b, d);
  475. }
  476. blobmsg_close_table(&b, c);
  477. blobmsg_close_table(&b, a);
  478. }
  479. }
  480. static void
  481. interface_ip_dump_prefix_assignment_list(struct interface *iface)
  482. {
  483. void *a;
  484. char *buf;
  485. const int buflen = INET6_ADDRSTRLEN;
  486. time_t now = system_get_rtime();
  487. struct device_prefix *prefix;
  488. list_for_each_entry(prefix, &prefixes, head) {
  489. struct device_prefix_assignment *assign;
  490. list_for_each_entry(assign, &prefix->assignments, head) {
  491. if (strcmp(assign->name, iface->name))
  492. continue;
  493. struct in6_addr addr = prefix->addr;
  494. addr.s6_addr32[1] |= htonl(assign->assigned);
  495. a = blobmsg_open_table(&b, NULL);
  496. buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
  497. inet_ntop(AF_INET6, &addr, buf, buflen);
  498. blobmsg_add_string_buffer(&b);
  499. blobmsg_add_u32(&b, "mask", assign->length);
  500. if (prefix->preferred_until) {
  501. int preferred = prefix->preferred_until - now;
  502. if (preferred < 0)
  503. preferred = 0;
  504. blobmsg_add_u32(&b, "preferred", preferred);
  505. }
  506. if (prefix->valid_until)
  507. blobmsg_add_u32(&b, "valid", prefix->valid_until - now);
  508. void *c = blobmsg_open_table(&b, "local-address");
  509. if (assign->enabled) {
  510. buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
  511. inet_ntop(AF_INET6, &assign->addr, buf, buflen);
  512. blobmsg_add_string_buffer(&b);
  513. blobmsg_add_u32(&b, "mask", assign->length);
  514. }
  515. blobmsg_close_table(&b, c);
  516. blobmsg_close_table(&b, a);
  517. }
  518. }
  519. }
  520. static void
  521. interface_ip_dump_dns_server_list(struct interface_ip_settings *ip, bool enabled)
  522. {
  523. struct dns_server *dns;
  524. int buflen = 128;
  525. char *buf;
  526. vlist_simple_for_each_element(&ip->dns_servers, dns, node) {
  527. if (ip->no_dns == enabled)
  528. continue;
  529. buf = blobmsg_alloc_string_buffer(&b, NULL, buflen);
  530. inet_ntop(dns->af, &dns->addr, buf, buflen);
  531. blobmsg_add_string_buffer(&b);
  532. }
  533. }
  534. static void
  535. interface_ip_dump_dns_search_list(struct interface_ip_settings *ip, bool enabled)
  536. {
  537. struct dns_search_domain *dns;
  538. vlist_simple_for_each_element(&ip->dns_search, dns, node) {
  539. if (ip->no_dns == enabled)
  540. continue;
  541. blobmsg_add_string(&b, NULL, dns->name);
  542. }
  543. }
  544. static void
  545. netifd_dump_status(struct interface *iface)
  546. {
  547. struct interface_data *data;
  548. struct device *dev;
  549. void *a, *inactive;
  550. blobmsg_add_u8(&b, "up", iface->state == IFS_UP);
  551. blobmsg_add_u8(&b, "pending", iface->state == IFS_SETUP);
  552. blobmsg_add_u8(&b, "available", iface->available);
  553. blobmsg_add_u8(&b, "autostart", iface->autostart);
  554. blobmsg_add_u8(&b, "dynamic", iface->dynamic);
  555. if (iface->state == IFS_UP) {
  556. time_t cur = system_get_rtime();
  557. blobmsg_add_u32(&b, "uptime", cur - iface->start_time);
  558. if (iface->l3_dev.dev)
  559. blobmsg_add_string(&b, "l3_device", iface->l3_dev.dev->ifname);
  560. }
  561. if (iface->proto_handler)
  562. blobmsg_add_string(&b, "proto", iface->proto_handler->name);
  563. dev = iface->main_dev.dev;
  564. if (dev && !dev->hidden && iface->proto_handler &&
  565. !(iface->proto_handler->flags & PROTO_FLAG_NODEV))
  566. blobmsg_add_string(&b, "device", dev->ifname);
  567. if (iface->state == IFS_UP) {
  568. if (iface->updated) {
  569. a = blobmsg_open_array(&b, "updated");
  570. if (iface->updated & IUF_ADDRESS)
  571. blobmsg_add_string(&b, NULL, "addresses");
  572. if (iface->updated & IUF_ROUTE)
  573. blobmsg_add_string(&b, NULL, "routes");
  574. if (iface->updated & IUF_PREFIX)
  575. blobmsg_add_string(&b, NULL, "prefixes");
  576. if (iface->updated & IUF_DATA)
  577. blobmsg_add_string(&b, NULL, "data");
  578. blobmsg_close_array(&b, a);
  579. }
  580. if (iface->ip4table)
  581. blobmsg_add_u32(&b, "ip4table", iface->ip4table);
  582. if (iface->ip6table)
  583. blobmsg_add_u32(&b, "ip6table", iface->ip6table);
  584. blobmsg_add_u32(&b, "metric", iface->metric);
  585. blobmsg_add_u32(&b, "dns_metric", iface->dns_metric);
  586. blobmsg_add_u8(&b, "delegation", !iface->proto_ip.no_delegation);
  587. if (iface->assignment_weight)
  588. blobmsg_add_u32(&b, "ip6weight", iface->assignment_weight);
  589. a = blobmsg_open_array(&b, "ipv4-address");
  590. interface_ip_dump_address_list(&iface->config_ip, false, true);
  591. interface_ip_dump_address_list(&iface->proto_ip, false, true);
  592. blobmsg_close_array(&b, a);
  593. a = blobmsg_open_array(&b, "ipv6-address");
  594. interface_ip_dump_address_list(&iface->config_ip, true, true);
  595. interface_ip_dump_address_list(&iface->proto_ip, true, true);
  596. blobmsg_close_array(&b, a);
  597. a = blobmsg_open_array(&b, "ipv6-prefix");
  598. interface_ip_dump_prefix_list(&iface->config_ip);
  599. interface_ip_dump_prefix_list(&iface->proto_ip);
  600. blobmsg_close_array(&b, a);
  601. a = blobmsg_open_array(&b, "ipv6-prefix-assignment");
  602. interface_ip_dump_prefix_assignment_list(iface);
  603. blobmsg_close_array(&b, a);
  604. a = blobmsg_open_array(&b, "route");
  605. interface_ip_dump_route_list(&iface->config_ip, true);
  606. interface_ip_dump_route_list(&iface->proto_ip, true);
  607. blobmsg_close_array(&b, a);
  608. a = blobmsg_open_array(&b, "dns-server");
  609. interface_ip_dump_dns_server_list(&iface->config_ip, true);
  610. interface_ip_dump_dns_server_list(&iface->proto_ip, true);
  611. blobmsg_close_array(&b, a);
  612. a = blobmsg_open_array(&b, "dns-search");
  613. interface_ip_dump_dns_search_list(&iface->config_ip, true);
  614. interface_ip_dump_dns_search_list(&iface->proto_ip, true);
  615. blobmsg_close_array(&b, a);
  616. a = blobmsg_open_array(&b, "neighbors");
  617. interface_ip_dump_neighbor_list(&iface->config_ip, true);
  618. interface_ip_dump_neighbor_list(&iface->proto_ip, true);
  619. blobmsg_close_array(&b, a);
  620. inactive = blobmsg_open_table(&b, "inactive");
  621. a = blobmsg_open_array(&b, "ipv4-address");
  622. interface_ip_dump_address_list(&iface->config_ip, false, false);
  623. interface_ip_dump_address_list(&iface->proto_ip, false, false);
  624. blobmsg_close_array(&b, a);
  625. a = blobmsg_open_array(&b, "ipv6-address");
  626. interface_ip_dump_address_list(&iface->config_ip, true, false);
  627. interface_ip_dump_address_list(&iface->proto_ip, true, false);
  628. blobmsg_close_array(&b, a);
  629. a = blobmsg_open_array(&b, "route");
  630. interface_ip_dump_route_list(&iface->config_ip, false);
  631. interface_ip_dump_route_list(&iface->proto_ip, false);
  632. blobmsg_close_array(&b, a);
  633. a = blobmsg_open_array(&b, "dns-server");
  634. interface_ip_dump_dns_server_list(&iface->config_ip, false);
  635. interface_ip_dump_dns_server_list(&iface->proto_ip, false);
  636. blobmsg_close_array(&b, a);
  637. a = blobmsg_open_array(&b, "dns-search");
  638. interface_ip_dump_dns_search_list(&iface->config_ip, false);
  639. interface_ip_dump_dns_search_list(&iface->proto_ip, false);
  640. blobmsg_close_array(&b, a);
  641. a = blobmsg_open_array(&b, "neighbors");
  642. interface_ip_dump_neighbor_list(&iface->config_ip, false);
  643. interface_ip_dump_neighbor_list(&iface->proto_ip, false);
  644. blobmsg_close_array(&b, a);
  645. blobmsg_close_table(&b, inactive);
  646. }
  647. a = blobmsg_open_table(&b, "data");
  648. avl_for_each_element(&iface->data, data, node)
  649. blobmsg_add_blob(&b, data->data);
  650. blobmsg_close_table(&b, a);
  651. if (!list_empty(&iface->errors))
  652. netifd_add_interface_errors(&b, iface);
  653. }
  654. static int
  655. netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj,
  656. struct ubus_request_data *req, const char *method,
  657. struct blob_attr *msg)
  658. {
  659. struct interface *iface = container_of(obj, struct interface, ubus);
  660. blob_buf_init(&b, 0);
  661. netifd_dump_status(iface);
  662. ubus_send_reply(ctx, req, b.head);
  663. return 0;
  664. }
  665. static int
  666. netifd_handle_dump(struct ubus_context *ctx, struct ubus_object *obj,
  667. struct ubus_request_data *req, const char *method,
  668. struct blob_attr *msg)
  669. {
  670. blob_buf_init(&b, 0);
  671. void *a = blobmsg_open_array(&b, "interface");
  672. struct interface *iface;
  673. vlist_for_each_element(&interfaces, iface, node) {
  674. void *i = blobmsg_open_table(&b, NULL);
  675. blobmsg_add_string(&b, "interface", iface->name);
  676. netifd_dump_status(iface);
  677. blobmsg_close_table(&b, i);
  678. }
  679. blobmsg_close_array(&b, a);
  680. ubus_send_reply(ctx, req, b.head);
  681. return 0;
  682. }
  683. enum {
  684. DEV_LINK_NAME,
  685. DEV_LINK_EXT,
  686. __DEV_LINK_MAX,
  687. };
  688. static const struct blobmsg_policy dev_link_policy[__DEV_LINK_MAX] = {
  689. [DEV_LINK_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  690. [DEV_LINK_EXT] = { .name = "link-ext", .type = BLOBMSG_TYPE_BOOL },
  691. };
  692. static int
  693. netifd_iface_handle_device(struct ubus_context *ctx, struct ubus_object *obj,
  694. struct ubus_request_data *req, const char *method,
  695. struct blob_attr *msg)
  696. {
  697. struct blob_attr *tb[__DEV_LINK_MAX];
  698. struct blob_attr *cur;
  699. struct interface *iface;
  700. bool add = !strncmp(method, "add", 3);
  701. bool link_ext = true;
  702. iface = container_of(obj, struct interface, ubus);
  703. blobmsg_parse(dev_link_policy, __DEV_LINK_MAX, tb, blob_data(msg), blob_len(msg));
  704. if (!tb[DEV_LINK_NAME])
  705. return UBUS_STATUS_INVALID_ARGUMENT;
  706. cur = tb[DEV_LINK_EXT];
  707. if (cur)
  708. link_ext = blobmsg_get_bool(cur);
  709. return interface_handle_link(iface, blobmsg_data(tb[DEV_LINK_NAME]), add, link_ext);
  710. }
  711. static int
  712. netifd_iface_notify_proto(struct ubus_context *ctx, struct ubus_object *obj,
  713. struct ubus_request_data *req, const char *method,
  714. struct blob_attr *msg)
  715. {
  716. struct interface *iface;
  717. iface = container_of(obj, struct interface, ubus);
  718. if (!iface->proto || !iface->proto->notify)
  719. return UBUS_STATUS_NOT_SUPPORTED;
  720. return iface->proto->notify(iface->proto, msg);
  721. }
  722. static void
  723. netifd_iface_do_remove(struct uloop_timeout *timeout)
  724. {
  725. struct interface *iface;
  726. iface = container_of(timeout, struct interface, remove_timer);
  727. vlist_delete(&interfaces, &iface->node);
  728. }
  729. static int
  730. netifd_iface_remove(struct ubus_context *ctx, struct ubus_object *obj,
  731. struct ubus_request_data *req, const char *method,
  732. struct blob_attr *msg)
  733. {
  734. struct interface *iface;
  735. iface = container_of(obj, struct interface, ubus);
  736. if (iface->remove_timer.cb)
  737. return UBUS_STATUS_INVALID_ARGUMENT;
  738. iface->remove_timer.cb = netifd_iface_do_remove;
  739. uloop_timeout_set(&iface->remove_timer, 100);
  740. return 0;
  741. }
  742. static int
  743. netifd_handle_iface_prepare(struct ubus_context *ctx, struct ubus_object *obj,
  744. struct ubus_request_data *req, const char *method,
  745. struct blob_attr *msg)
  746. {
  747. struct interface *iface;
  748. struct device *dev;
  749. const struct device_hotplug_ops *ops;
  750. iface = container_of(obj, struct interface, ubus);
  751. dev = iface->main_dev.dev;
  752. if (!dev)
  753. return 0;
  754. ops = dev->hotplug_ops;
  755. if (!ops)
  756. return 0;
  757. return ops->prepare(dev);
  758. }
  759. static int
  760. netifd_handle_set_data(struct ubus_context *ctx, struct ubus_object *obj,
  761. struct ubus_request_data *req, const char *method,
  762. struct blob_attr *msg)
  763. {
  764. struct interface *iface;
  765. iface = container_of(obj, struct interface, ubus);
  766. return interface_parse_data(iface, msg);
  767. }
  768. static struct ubus_method iface_object_methods[] = {
  769. { .name = "up", .handler = netifd_handle_up },
  770. { .name = "down", .handler = netifd_handle_down },
  771. { .name = "renew", .handler = netifd_handle_renew },
  772. { .name = "status", .handler = netifd_handle_status },
  773. { .name = "prepare", .handler = netifd_handle_iface_prepare },
  774. { .name = "dump", .handler = netifd_handle_dump },
  775. UBUS_METHOD("add_device", netifd_iface_handle_device, dev_link_policy ),
  776. UBUS_METHOD("remove_device", netifd_iface_handle_device, dev_link_policy ),
  777. { .name = "notify_proto", .handler = netifd_iface_notify_proto },
  778. { .name = "remove", .handler = netifd_iface_remove },
  779. { .name = "set_data", .handler = netifd_handle_set_data },
  780. };
  781. static struct ubus_object_type iface_object_type =
  782. UBUS_OBJECT_TYPE("netifd_iface", iface_object_methods);
  783. static struct ubus_object iface_object = {
  784. .name = "network.interface",
  785. .type = &iface_object_type,
  786. .n_methods = ARRAY_SIZE(iface_object_methods),
  787. };
  788. static void netifd_add_object(struct ubus_object *obj)
  789. {
  790. int ret = ubus_add_object(ubus_ctx, obj);
  791. if (ret != 0)
  792. fprintf(stderr, "Failed to publish object '%s': %s\n", obj->name, ubus_strerror(ret));
  793. }
  794. static const struct blobmsg_policy iface_policy = {
  795. .name = "interface",
  796. .type = BLOBMSG_TYPE_STRING,
  797. };
  798. static int
  799. netifd_handle_iface(struct ubus_context *ctx, struct ubus_object *obj,
  800. struct ubus_request_data *req, const char *method,
  801. struct blob_attr *msg)
  802. {
  803. struct interface *iface;
  804. struct blob_attr *tb;
  805. int i;
  806. blobmsg_parse(&iface_policy, 1, &tb, blob_data(msg), blob_len(msg));
  807. if (!tb)
  808. return UBUS_STATUS_INVALID_ARGUMENT;
  809. iface = vlist_find(&interfaces, blobmsg_data(tb), iface, node);
  810. if (!iface)
  811. return UBUS_STATUS_NOT_FOUND;
  812. for (i = 0; i < ARRAY_SIZE(iface_object_methods); i++) {
  813. ubus_handler_t cb;
  814. if (strcmp(method, iface_object_methods[i].name) != 0)
  815. continue;
  816. cb = iface_object_methods[i].handler;
  817. return cb(ctx, &iface->ubus, req, method, msg);
  818. }
  819. return UBUS_STATUS_INVALID_ARGUMENT;
  820. }
  821. static void netifd_add_iface_object(void)
  822. {
  823. struct ubus_method *methods;
  824. int i;
  825. methods = calloc(1, sizeof(iface_object_methods));
  826. if (!methods)
  827. return;
  828. memcpy(methods, iface_object_methods, sizeof(iface_object_methods));
  829. iface_object.methods = methods;
  830. for (i = 0; i < ARRAY_SIZE(iface_object_methods); i++) {
  831. if (methods[i].handler == netifd_handle_dump)
  832. continue;
  833. methods[i].handler = netifd_handle_iface;
  834. methods[i].policy = &iface_policy;
  835. methods[i].n_policy = 1;
  836. }
  837. netifd_add_object(&iface_object);
  838. }
  839. static struct wireless_device *
  840. get_wdev(struct blob_attr *msg, int *ret)
  841. {
  842. struct blobmsg_policy wdev_policy = {
  843. .name = "device",
  844. .type = BLOBMSG_TYPE_STRING,
  845. };
  846. struct blob_attr *dev_attr;
  847. struct wireless_device *wdev = NULL;
  848. blobmsg_parse(&wdev_policy, 1, &dev_attr, blob_data(msg), blob_len(msg));
  849. if (!dev_attr) {
  850. *ret = UBUS_STATUS_INVALID_ARGUMENT;
  851. return NULL;
  852. }
  853. wdev = vlist_find(&wireless_devices, blobmsg_data(dev_attr), wdev, node);
  854. if (!wdev) {
  855. *ret = UBUS_STATUS_NOT_FOUND;
  856. return NULL;
  857. }
  858. *ret = 0;
  859. return wdev;
  860. }
  861. static int
  862. netifd_handle_wdev_up(struct ubus_context *ctx, struct ubus_object *obj,
  863. struct ubus_request_data *req, const char *method,
  864. struct blob_attr *msg)
  865. {
  866. struct wireless_device *wdev;
  867. int ret;
  868. wdev = get_wdev(msg, &ret);
  869. if (ret == UBUS_STATUS_NOT_FOUND)
  870. return ret;
  871. if (wdev) {
  872. wireless_device_set_up(wdev);
  873. } else {
  874. vlist_for_each_element(&wireless_devices, wdev, node)
  875. wireless_device_set_up(wdev);
  876. }
  877. return 0;
  878. }
  879. static int
  880. netifd_handle_wdev_down(struct ubus_context *ctx, struct ubus_object *obj,
  881. struct ubus_request_data *req, const char *method,
  882. struct blob_attr *msg)
  883. {
  884. struct wireless_device *wdev;
  885. int ret;
  886. wdev = get_wdev(msg, &ret);
  887. if (ret == UBUS_STATUS_NOT_FOUND)
  888. return ret;
  889. if (wdev) {
  890. wireless_device_set_down(wdev);
  891. } else {
  892. vlist_for_each_element(&wireless_devices, wdev, node)
  893. wireless_device_set_down(wdev);
  894. }
  895. return 0;
  896. }
  897. static int
  898. netifd_handle_wdev_status(struct ubus_context *ctx, struct ubus_object *obj,
  899. struct ubus_request_data *req, const char *method,
  900. struct blob_attr *msg)
  901. {
  902. struct wireless_device *wdev;
  903. int ret;
  904. wdev = get_wdev(msg, &ret);
  905. if (ret == UBUS_STATUS_NOT_FOUND)
  906. return ret;
  907. blob_buf_init(&b, 0);
  908. if (wdev) {
  909. wireless_device_status(wdev, &b);
  910. } else {
  911. vlist_for_each_element(&wireless_devices, wdev, node)
  912. wireless_device_status(wdev, &b);
  913. }
  914. ubus_send_reply(ctx, req, b.head);
  915. return 0;
  916. }
  917. static int
  918. netifd_handle_wdev_get_validate(struct ubus_context *ctx, struct ubus_object *obj,
  919. struct ubus_request_data *req, const char *method,
  920. struct blob_attr *msg)
  921. {
  922. struct wireless_device *wdev;
  923. int ret;
  924. wdev = get_wdev(msg, &ret);
  925. if (ret == UBUS_STATUS_NOT_FOUND)
  926. return ret;
  927. blob_buf_init(&b, 0);
  928. if (wdev) {
  929. wireless_device_get_validate(wdev, &b);
  930. } else {
  931. vlist_for_each_element(&wireless_devices, wdev, node)
  932. wireless_device_get_validate(wdev, &b);
  933. }
  934. ubus_send_reply(ctx, req, b.head);
  935. return 0;
  936. }
  937. static int
  938. netifd_handle_wdev_notify(struct ubus_context *ctx, struct ubus_object *obj,
  939. struct ubus_request_data *req, const char *method,
  940. struct blob_attr *msg)
  941. {
  942. struct wireless_device *wdev;
  943. int ret;
  944. wdev = get_wdev(msg, &ret);
  945. if (!wdev)
  946. return ret;
  947. return wireless_device_notify(wdev, msg, req);
  948. }
  949. static struct ubus_method wireless_object_methods[] = {
  950. { .name = "up", .handler = netifd_handle_wdev_up },
  951. { .name = "down", .handler = netifd_handle_wdev_down },
  952. { .name = "status", .handler = netifd_handle_wdev_status },
  953. { .name = "notify", .handler = netifd_handle_wdev_notify },
  954. { .name = "get_validate", .handler = netifd_handle_wdev_get_validate },
  955. };
  956. static struct ubus_object_type wireless_object_type =
  957. UBUS_OBJECT_TYPE("netifd_iface", wireless_object_methods);
  958. static struct ubus_object wireless_object = {
  959. .name = "network.wireless",
  960. .type = &wireless_object_type,
  961. .methods = wireless_object_methods,
  962. .n_methods = ARRAY_SIZE(wireless_object_methods),
  963. };
  964. int
  965. netifd_ubus_init(const char *path)
  966. {
  967. uloop_init();
  968. ubus_path = path;
  969. ubus_ctx = ubus_connect(path);
  970. if (!ubus_ctx)
  971. return -EIO;
  972. DPRINTF("connected as %08x\n", ubus_ctx->local_id);
  973. ubus_ctx->connection_lost = netifd_ubus_connection_lost;
  974. netifd_ubus_add_fd();
  975. netifd_add_object(&main_object);
  976. netifd_add_object(&dev_object);
  977. netifd_add_object(&wireless_object);
  978. netifd_add_iface_object();
  979. return 0;
  980. }
  981. void
  982. netifd_ubus_done(void)
  983. {
  984. ubus_free(ubus_ctx);
  985. }
  986. void
  987. netifd_ubus_interface_event(struct interface *iface, bool up)
  988. {
  989. blob_buf_init(&b, 0);
  990. blobmsg_add_string(&b, "action", up ? "ifup" : "ifdown");
  991. blobmsg_add_string(&b, "interface", iface->name);
  992. ubus_send_event(ubus_ctx, "network.interface", b.head);
  993. }
  994. void
  995. netifd_ubus_interface_notify(struct interface *iface, bool up)
  996. {
  997. const char *event = (up) ? "interface.update" : "interface.down";
  998. blob_buf_init(&b, 0);
  999. blobmsg_add_string(&b, "interface", iface->name);
  1000. netifd_dump_status(iface);
  1001. ubus_notify(ubus_ctx, &iface_object, event, b.head, -1);
  1002. ubus_notify(ubus_ctx, &iface->ubus, event, b.head, -1);
  1003. }
  1004. void
  1005. netifd_ubus_add_interface(struct interface *iface)
  1006. {
  1007. struct ubus_object *obj = &iface->ubus;
  1008. char *name = NULL;
  1009. if (asprintf(&name, "%s.interface.%s", main_object.name, iface->name) == -1)
  1010. return;
  1011. obj->name = name;
  1012. obj->type = &iface_object_type;
  1013. obj->methods = iface_object_methods;
  1014. obj->n_methods = ARRAY_SIZE(iface_object_methods);
  1015. if (ubus_add_object(ubus_ctx, &iface->ubus)) {
  1016. DPRINTF("failed to publish ubus object for interface '%s'\n", iface->name);
  1017. free(name);
  1018. obj->name = NULL;
  1019. }
  1020. }
  1021. void
  1022. netifd_ubus_remove_interface(struct interface *iface)
  1023. {
  1024. if (!iface->ubus.name)
  1025. return;
  1026. ubus_remove_object(ubus_ctx, &iface->ubus);
  1027. free((void *) iface->ubus.name);
  1028. }