X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fnetwork%2Fif_nameindex.c;h=2deaef769600e5bb6b67d613eb3b3e1f65597383;hb=7b712844e38bdfc1ef728e257fb8616c16ec4cc8;hp=cdb956cb9500d3643969545a2a48e9866fcb825e;hpb=68c58223672465202958a5da16f19f64f32acf74;p=musl diff --git a/src/network/if_nameindex.c b/src/network/if_nameindex.c index cdb956cb..2deaef76 100644 --- a/src/network/if_nameindex.c +++ b/src/network/if_nameindex.c @@ -1,57 +1,114 @@ #define _GNU_SOURCE #include -#include -#include -#include #include -#include "syscall.h" +#include +#include +#include +#include +#include "netlink.h" -#include +#define IFADDRS_HASH_SIZE 64 -static void *do_nameindex(int s, size_t n) -{ - size_t i, len, k; - struct ifconf conf; - struct if_nameindex *idx; +struct ifnamemap { + unsigned int hash_next; + unsigned int index; + unsigned char namelen; + char name[IFNAMSIZ]; +}; - idx = malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq))); - if (!idx) return 0; +struct ifnameindexctx { + unsigned int num, allocated, str_bytes; + struct ifnamemap *list; + unsigned int hash[IFADDRS_HASH_SIZE]; +}; - conf.ifc_buf = (void *)&idx[n]; - conf.ifc_len = len = n * sizeof(struct ifreq); - if (ioctl(s, SIOCGIFCONF, &conf) < 0) { - free(idx); - return 0; - } - if (conf.ifc_len == len) { - free(idx); - return (void *)-1; +static int netlink_msg_to_nameindex(void *pctx, struct nlmsghdr *h) +{ + struct ifnameindexctx *ctx = pctx; + struct ifnamemap *map; + struct rtattr *rta; + unsigned int i; + int index, type, namelen, bucket; + + if (h->nlmsg_type == RTM_NEWLINK) { + struct ifinfomsg *ifi = NLMSG_DATA(h); + index = ifi->ifi_index; + type = IFLA_IFNAME; + rta = NLMSG_RTA(h, sizeof(*ifi)); + } else { + struct ifaddrmsg *ifa = NLMSG_DATA(h); + index = ifa->ifa_index; + type = IFA_LABEL; + rta = NLMSG_RTA(h, sizeof(*ifa)); } + for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) { + if (rta->rta_type != type) continue; + + namelen = RTA_DATALEN(rta) - 1; + if (namelen > IFNAMSIZ) return 0; - n = conf.ifc_len / sizeof(struct ifreq); - for (i=k=0; ihash[bucket]; + while (i) { + map = &ctx->list[i-1]; + if (map->index == index && + map->namelen == namelen && + memcmp(map->name, RTA_DATA(rta), namelen) == 0) + return 0; + i = map->hash_next; } - idx[i-k].if_index = conf.ifc_req[i].ifr_ifindex; - idx[i-k].if_name = conf.ifc_req[i].ifr_name; - } - idx[i-k].if_name = 0; - idx[i-k].if_index = 0; - return idx; + if (ctx->num >= ctx->allocated) { + size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8; + if (a > SIZE_MAX/sizeof *map) return -1; + map = realloc(ctx->list, a * sizeof *map); + if (!map) return -1; + ctx->list = map; + ctx->allocated = a; + } + map = &ctx->list[ctx->num]; + map->index = index; + map->namelen = namelen; + memcpy(map->name, RTA_DATA(rta), namelen); + ctx->str_bytes += namelen + 1; + ctx->num++; + map->hash_next = ctx->hash[bucket]; + ctx->hash[bucket] = ctx->num; + return 0; + } + return 0; } struct if_nameindex *if_nameindex() { - size_t n; - void *p = 0; - int s = socket(AF_UNIX, SOCK_DGRAM, 0); - if (s>=0) { - for (n=0; (p=do_nameindex(s, n)) == (void *)-1; n++); - __syscall(SYS_close, s); + struct ifnameindexctx _ctx, *ctx = &_ctx; + struct if_nameindex *ifs = 0, *d; + struct ifnamemap *s; + char *p; + int i; + int cs; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + memset(ctx, 0, sizeof(*ctx)); + if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err; + + ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes); + if (!ifs) goto err; + + p = (char*)(ifs + ctx->num + 1); + for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) { + d->if_index = s->index; + d->if_name = p; + memcpy(p, s->name, s->namelen); + p += s->namelen; + *p++ = 0; } + d->if_index = 0; + d->if_name = 0; +err: + pthread_setcancelstate(cs, 0); + free(ctx->list); errno = ENOBUFS; - return p; + return ifs; }