diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/rpcd-mod-luci/Makefile | 2 | ||||
-rw-r--r-- | libs/rpcd-mod-luci/src/luci.c | 277 |
2 files changed, 220 insertions, 59 deletions
diff --git a/libs/rpcd-mod-luci/Makefile b/libs/rpcd-mod-luci/Makefile index a39ec3b224..7909d4a7b3 100644 --- a/libs/rpcd-mod-luci/Makefile +++ b/libs/rpcd-mod-luci/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=rpcd-mod-luci -PKG_VERSION:=20201107 +PKG_VERSION:=20210614 PKG_MAINTAINER:=Jo-Philipp Wich <jo@mein.io> PKG_LICENSE:=Apache-2.0 diff --git a/libs/rpcd-mod-luci/src/luci.c b/libs/rpcd-mod-luci/src/luci.c index 131384d76d..eb6f58803e 100644 --- a/libs/rpcd-mod-luci/src/luci.c +++ b/libs/rpcd-mod-luci/src/luci.c @@ -31,6 +31,7 @@ #include <net/if.h> #include <arpa/inet.h> #include <sys/types.h> +#include <netinet/in.h> #include <netinet/ether.h> #include <linux/rtnetlink.h> #include <linux/if_packet.h> @@ -222,6 +223,14 @@ readstr(const char *fmt, ...) return data; } +static bool +ea_empty(struct ether_addr *ea) +{ + struct ether_addr empty = { 0 }; + + return !memcmp(ea, &empty, sizeof(empty)); +} + static char * ea2str(struct ether_addr *ea) { @@ -452,9 +461,9 @@ lease_next(void) char *p; int n; - memset(&e, 0, sizeof(e)); - while (lease_state.off < lease_state.num) { + memset(&e, 0, sizeof(e)); + while (fgets(e.buf, sizeof(e.buf), lease_state.files[lease_state.off].fh)) { if (lease_state.files[lease_state.off].odhcpd) { strtok(e.buf, " \t\n"); /* # */ @@ -765,6 +774,30 @@ rpc_luci_parse_network_device_sys(const char *name, struct ifaddrs *ifaddr) blobmsg_add_u8(&blob, "pointtopoint", ifa_flags & IFF_POINTOPOINT); blobmsg_close_table(&blob, o2); + o2 = blobmsg_open_table(&blob, "link"); + + p = readstr("/sys/class/net/%s/speed", name); + if (*p) + blobmsg_add_u32(&blob, "speed", atoi(p)); + + p = readstr("/sys/class/net/%s/duplex", name); + if (*p) + blobmsg_add_string(&blob, "duplex", p); + + n = atoi(readstr("/sys/class/net/%s/carrier", name)); + blobmsg_add_u8(&blob, "carrier", n == 1); + + n = atoi(readstr("/sys/class/net/%s/carrier_changes", name)); + blobmsg_add_u32(&blob, "changes", n); + + n = atoi(readstr("/sys/class/net/%s/carrier_up_count", name)); + blobmsg_add_u32(&blob, "up_count", n); + + n = atoi(readstr("/sys/class/net/%s/carrier_down_count", name)); + blobmsg_add_u32(&blob, "down_count", n); + + blobmsg_close_table(&blob, o2); + blobmsg_close_table(&blob, o); } @@ -879,6 +912,9 @@ static bool rpc_luci_get_iwinfo(struct blob_buf *buf, const char *devname, if (!iw->hwmodelist(devname, &nret)) { a = blobmsg_open_array(buf, "hwmodes"); + if (nret & IWINFO_80211_AX) + blobmsg_add_string(buf, NULL, "ax"); + if (nret & IWINFO_80211_AC) blobmsg_add_string(buf, NULL, "ac"); @@ -921,6 +957,18 @@ static bool rpc_luci_get_iwinfo(struct blob_buf *buf, const char *devname, if (nret & IWINFO_HTMODE_VHT160) blobmsg_add_string(buf, NULL, "VHT160"); + if (nret & IWINFO_HTMODE_HE20) + blobmsg_add_string(buf, NULL, "HE20"); + + if (nret & IWINFO_HTMODE_HE40) + blobmsg_add_string(buf, NULL, "HE40"); + + if (nret & IWINFO_HTMODE_HE80) + blobmsg_add_string(buf, NULL, "HE80"); + + if (nret & IWINFO_HTMODE_HE160) + blobmsg_add_string(buf, NULL, "HE160"); + blobmsg_close_array(buf, a); } @@ -1135,11 +1183,48 @@ rpc_luci_get_wireless_devices(struct ubus_context *ctx, struct host_hint { struct avl_node avl; char *hostname; - struct in_addr ip; - struct in6_addr ip6; + struct avl_tree ipaddrs; + struct avl_tree ip6addrs; +}; + +/* used to ignore priority with avl_find_element */ +#define HOST_HINT_PRIO_IGNORE -1 + +/* higher (larger) priority addresses are listed first */ +#define HOST_HINT_PRIO_NL 10 /* neighbor table */ +#define HOST_HINT_PRIO_ETHER 50 /* /etc/ethers */ +#define HOST_HINT_PRIO_LEASEFILE 100 /* dhcp leasefile */ +#define HOST_HINT_PRIO_IFADDRS 200 /* getifaddrs() */ +#define HOST_HINT_PRIO_STATIC_LEASE 250 /* uci static leases */ + +struct host_hint_addr { + struct avl_node avl; + int af; + int prio; + union { + struct in_addr in; + struct in6_addr in6; + } addr; }; static int +host_hint_addr_avl_cmp(const void *k1, const void *k2, void *ptr) +{ + struct host_hint_addr *a1 = (struct host_hint_addr *)k1; + struct host_hint_addr *a2 = (struct host_hint_addr *)k2; + + if (a1->prio != a2->prio && + a1->prio != HOST_HINT_PRIO_IGNORE && + a2->prio != HOST_HINT_PRIO_IGNORE) + return a1->prio < a2->prio ? 1 : -1; + + if (a1->af != a2->af) + return a1->af < a2->af ? -1 : 1; + + return memcmp(&a1->addr, &a2->addr, sizeof(a1->addr)); +} + +static int nl_cb_done(struct nl_msg *msg, void *arg) { struct reply_context *rctx = arg; @@ -1174,12 +1259,69 @@ rpc_luci_get_host_hint(struct reply_context *rctx, struct ether_addr *ea) return NULL; hint->avl.key = strcpy(p, mac); + avl_init(&hint->ipaddrs, host_hint_addr_avl_cmp, false, NULL); + avl_init(&hint->ip6addrs, host_hint_addr_avl_cmp, false, NULL); avl_insert(&rctx->avl, &hint->avl); } return hint; } +static void +rpc_luci_add_host_hint_addr(struct host_hint *hint, int af, int prio, void *addr) +{ + struct host_hint_addr e, *a; + struct avl_tree *addrs = af == AF_INET ? &hint->ipaddrs : &hint->ip6addrs; + + if (!addr) + return; + + memset(&e, 0, sizeof(e)); + e.af = af; + /* ignore prio when comparing against existing addresses */ + e.prio = HOST_HINT_PRIO_IGNORE; + + if (af == AF_INET) + memcpy(&e.addr.in, (struct in_addr *)addr, sizeof(e.addr.in)); + else + memcpy(&e.addr.in6, (struct in6_addr *)addr, sizeof(e.addr.in6)); + + a = avl_find_element(addrs, &e, a, avl); + + if (a) { + /* update prio of existing address if higher */ + if (prio <= a->prio) + return; + + avl_delete(addrs, &a->avl); + a->prio = prio; + avl_insert(addrs, &a->avl); + return; + } + + a = calloc(1, sizeof(*a)); + + if (!a) + return; + + memcpy(a, &e, sizeof(*a)); + a->prio = prio; + a->avl.key = a; + avl_insert(addrs, &a->avl); +} + +static void +rpc_luci_add_host_hint_ipaddr(struct host_hint *hint, int prio, struct in_addr *addr) +{ + return rpc_luci_add_host_hint_addr(hint, AF_INET, prio, (void *)addr); +} + +static void +rpc_luci_add_host_hint_ip6addr(struct host_hint *hint, int prio, struct in6_addr *addr) +{ + return rpc_luci_add_host_hint_addr(hint, AF_INET6, prio, (void *)addr); +} + static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg) { struct reply_context *rctx = arg; @@ -1213,9 +1355,9 @@ static int nl_cb_dump_neigh(struct nl_msg *msg, void *arg) return NL_SKIP; if (nd->ndm_family == AF_INET) - hint->ip = *(struct in_addr *)dst; + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_NL, (struct in_addr *)dst); else - hint->ip6 = *(struct in6_addr *)dst; + rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_NL, (struct in6_addr *)dst); return NL_SKIP; } @@ -1298,8 +1440,7 @@ rpc_luci_get_host_hints_ether(struct reply_context *rctx) continue; if (inet_pton(AF_INET, p, &in) == 1) { - if (hint->ip.s_addr == 0) - hint->ip = in; + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_ETHER, &in); } else if (*p && !hint->hostname) { hint->hostname = strdup(p); @@ -1315,13 +1456,13 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx) struct uci_ptr ptr = { .package = "dhcp" }; struct uci_context *uci = NULL; struct uci_package *pkg = NULL; - struct in6_addr empty = {}; struct lease_entry *lease; struct host_hint *hint; struct uci_element *e, *l; struct uci_section *s; struct in_addr in; char *p, *n; + int i; uci = uci_alloc_context(); @@ -1379,8 +1520,8 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx) if (!hint) continue; - if (hint->ip.s_addr == 0 && in.s_addr != 0) - hint->ip = in; + if (in.s_addr != 0) + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_STATIC_LEASE, &in); if (n && !hint->hostname) hint->hostname = strdup(n); @@ -1393,8 +1534,8 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx) if (!hint) continue; - if (hint->ip.s_addr == 0 && in.s_addr != 0) - hint->ip = in; + if (in.s_addr != 0) + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_STATIC_LEASE, &in); if (n && !hint->hostname) hint->hostname = strdup(n); @@ -1405,16 +1546,20 @@ rpc_luci_get_host_hints_uci(struct reply_context *rctx) lease_open(); while ((lease = lease_next()) != NULL) { + if (ea_empty(&lease->mac)) + continue; + hint = rpc_luci_get_host_hint(rctx, &lease->mac); if (!hint) continue; - if (lease->af == AF_INET && lease->n_addr && hint->ip.s_addr == 0) - hint->ip = lease->addr[0].in; - else if (lease->af == AF_INET6 && lease->n_addr && - !memcmp(&hint->ip6, &empty, sizeof(empty))) - hint->ip6 = lease->addr[0].in6; + for (i = 0; i < lease->n_addr; i++) { + if (lease->af == AF_INET) + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_LEASEFILE, &lease->addr[i].in); + else if (lease->af == AF_INET6) + rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_LEASEFILE, &lease->addr[i].in6); + } if (lease->hostname && !hint->hostname) hint->hostname = strdup(lease->hostname); @@ -1430,8 +1575,6 @@ out: static void rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx) { - struct ether_addr empty_ea = {}; - struct in6_addr empty_in6 = {}; struct ifaddrs *ifaddr, *ifa; struct sockaddr_ll *sll; struct avl_tree devices; @@ -1487,18 +1630,17 @@ rpc_luci_get_host_hints_ifaddrs(struct reply_context *rctx) freeifaddrs(ifaddr); avl_remove_all_elements(&devices, device, avl, nextdevice) { - if (memcmp(&device->ea, &empty_ea, sizeof(empty_ea)) && - (memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) || + if (!ea_empty(&device->ea) && + (!IN6_IS_ADDR_UNSPECIFIED(&device->in6) || device->in.s_addr != 0)) { hint = rpc_luci_get_host_hint(rctx, &device->ea); if (hint) { - if (hint->ip.s_addr == 0 && device->in.s_addr != 0) - hint->ip = device->in; + if (device->in.s_addr != 0) + rpc_luci_add_host_hint_ipaddr(hint, HOST_HINT_PRIO_IFADDRS, &device->in); - if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6)) == 0 && - memcmp(&device->in6, &empty_in6, sizeof(empty_in6)) != 0) - hint->ip6 = device->in6; + if (!IN6_IS_ADDR_UNSPECIFIED(&device->in6)) + rpc_luci_add_host_hint_ip6addr(hint, HOST_HINT_PRIO_IFADDRS, &device->in6); } } @@ -1514,6 +1656,7 @@ rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type, struct blob_attr *msg) { struct reply_context *rctx = req->priv; + struct host_hint_addr *addr; struct host_hint *hint; struct blob_attr *cur; struct in6_addr in6; @@ -1527,23 +1670,23 @@ rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type, if (inet_pton(AF_INET6, blobmsg_name(cur), &in6) == 1) { avl_for_each_element(&rctx->avl, hint, avl) { - if (!memcmp(&hint->ip6, &in6, sizeof(in6))) { - if (hint->hostname) + avl_for_each_element(&hint->ip6addrs, addr, avl) { + if (!memcmp(&addr->addr.in6, &in6, sizeof(in6))) { free(hint->hostname); - - hint->hostname = strdup(blobmsg_get_string(cur)); - break; + hint->hostname = strdup(blobmsg_get_string(cur)); + break; + } } } } else if (inet_pton(AF_INET, blobmsg_name(cur), &in) == 1) { avl_for_each_element(&rctx->avl, hint, avl) { - if (!memcmp(&hint->ip, &in, sizeof(in))) { - if (hint->hostname) + avl_for_each_element(&hint->ipaddrs, addr, avl) { + if (addr->addr.in.s_addr == in.s_addr) { free(hint->hostname); - - hint->hostname = strdup(blobmsg_get_string(cur)); - break; + hint->hostname = strdup(blobmsg_get_string(cur)); + break; + } } } } @@ -1556,10 +1699,10 @@ rpc_luci_get_host_hints_rrdns_cb(struct ubus_request *req, int type, static void rpc_luci_get_host_hints_rrdns(struct reply_context *rctx) { - struct in6_addr empty_in6 = {}; char buf[INET6_ADDRSTRLEN]; struct blob_buf req = {}; struct host_hint *hint; + struct host_hint_addr *addr; int n = 0; void *a; @@ -1568,15 +1711,19 @@ rpc_luci_get_host_hints_rrdns(struct reply_context *rctx) a = blobmsg_open_array(&req, "addrs"); avl_for_each_element(&rctx->avl, hint, avl) { - if (hint->ip.s_addr != 0) { - inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf)); - blobmsg_add_string(&req, NULL, buf); - n++; + avl_for_each_element(&hint->ipaddrs, addr, avl) { + if (addr->addr.in.s_addr != 0) { + inet_ntop(AF_INET, &addr->addr.in, buf, sizeof(buf)); + blobmsg_add_string(&req, NULL, buf); + n++; + } } - else if (memcmp(&hint->ip6, &empty_in6, sizeof(empty_in6))) { - inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf)); - blobmsg_add_string(&req, NULL, buf); - n++; + avl_for_each_element(&hint->ip6addrs, addr, avl) { + if (!IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6)) { + inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)); + blobmsg_add_string(&req, NULL, buf); + n++; + } } } @@ -1601,24 +1748,40 @@ static int rpc_luci_get_host_hints_finish(struct reply_context *rctx) { struct host_hint *hint, *nexthint; + struct host_hint_addr *addr, *nextaddr; char buf[INET6_ADDRSTRLEN]; struct in6_addr in6 = {}; - struct in_addr in = {}; - void *o; + void *o, *a; avl_remove_all_elements(&rctx->avl, hint, avl, nexthint) { o = blobmsg_open_table(&rctx->blob, hint->avl.key); - if (memcmp(&hint->ip, &in, sizeof(in))) { - inet_ntop(AF_INET, &hint->ip, buf, sizeof(buf)); - blobmsg_add_string(&rctx->blob, "ipv4", buf); + a = blobmsg_open_array(&rctx->blob, "ipaddrs"); + + avl_remove_all_elements(&hint->ipaddrs, addr, avl, nextaddr) { + if (addr->addr.in.s_addr != 0) { + inet_ntop(AF_INET, &addr->addr.in, buf, sizeof(buf)); + blobmsg_add_string(&rctx->blob, NULL, buf); + } + + free(addr); } - if (memcmp(&hint->ip6, &in6, sizeof(in6))) { - inet_ntop(AF_INET6, &hint->ip6, buf, sizeof(buf)); - blobmsg_add_string(&rctx->blob, "ipv6", buf); + blobmsg_close_array(&rctx->blob, a); + + a = blobmsg_open_array(&rctx->blob, "ip6addrs"); + + avl_remove_all_elements(&hint->ip6addrs, addr, avl, nextaddr) { + if (memcmp(&addr->addr.in6, &in6, sizeof(in6))) { + inet_ntop(AF_INET6, &addr->addr.in6, buf, sizeof(buf)); + blobmsg_add_string(&rctx->blob, NULL, buf); + } + + free(addr); } + blobmsg_close_array(&rctx->blob, a); + if (hint->hostname) blobmsg_add_string(&rctx->blob, "name", hint->hostname); @@ -1659,7 +1822,6 @@ rpc_luci_get_duid_hints(struct ubus_context *ctx, struct ubus_object *obj, { struct { struct avl_node avl; } *e, *next; char s[INET6_ADDRSTRLEN], *p; - struct ether_addr empty = {}; struct lease_entry *lease; struct avl_tree avl; void *o, *a; @@ -1701,7 +1863,7 @@ rpc_luci_get_duid_hints(struct ubus_context *ctx, struct ubus_object *obj, if (lease->hostname) blobmsg_add_string(&blob, "hostname", lease->hostname); - if (memcmp(&lease->mac, &empty, sizeof(empty))) + if (!ea_empty(&lease->mac)) blobmsg_add_string(&blob, "macaddr", ea2str(&lease->mac)); blobmsg_close_table(&blob, o); @@ -1750,7 +1912,6 @@ rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj, struct blob_attr *msg) { struct blob_attr *tb[__RPC_L_MAX]; - struct ether_addr emptymac = {}; struct lease_entry *lease; char s[INET6_ADDRSTRLEN]; int af, family = 0; @@ -1802,7 +1963,7 @@ rpc_luci_get_dhcp_leases(struct ubus_context *ctx, struct ubus_object *obj, if (lease->hostname) blobmsg_add_string(&blob, "hostname", lease->hostname); - if (memcmp(&lease->mac, &emptymac, sizeof(emptymac))) + if (!ea_empty(&lease->mac)) blobmsg_add_string(&blob, "macaddr", ea2str(&lease->mac)); if (lease->duid) |