1*c9945492SAndroid Build Coastguard Worker #define _GNU_SOURCE
2*c9945492SAndroid Build Coastguard Worker #include <net/if.h>
3*c9945492SAndroid Build Coastguard Worker #include <errno.h>
4*c9945492SAndroid Build Coastguard Worker #include <unistd.h>
5*c9945492SAndroid Build Coastguard Worker #include <stdlib.h>
6*c9945492SAndroid Build Coastguard Worker #include <string.h>
7*c9945492SAndroid Build Coastguard Worker #include <pthread.h>
8*c9945492SAndroid Build Coastguard Worker #include "netlink.h"
9*c9945492SAndroid Build Coastguard Worker
10*c9945492SAndroid Build Coastguard Worker #define IFADDRS_HASH_SIZE 64
11*c9945492SAndroid Build Coastguard Worker
12*c9945492SAndroid Build Coastguard Worker struct ifnamemap {
13*c9945492SAndroid Build Coastguard Worker unsigned int hash_next;
14*c9945492SAndroid Build Coastguard Worker unsigned int index;
15*c9945492SAndroid Build Coastguard Worker unsigned char namelen;
16*c9945492SAndroid Build Coastguard Worker char name[IFNAMSIZ];
17*c9945492SAndroid Build Coastguard Worker };
18*c9945492SAndroid Build Coastguard Worker
19*c9945492SAndroid Build Coastguard Worker struct ifnameindexctx {
20*c9945492SAndroid Build Coastguard Worker unsigned int num, allocated, str_bytes;
21*c9945492SAndroid Build Coastguard Worker struct ifnamemap *list;
22*c9945492SAndroid Build Coastguard Worker unsigned int hash[IFADDRS_HASH_SIZE];
23*c9945492SAndroid Build Coastguard Worker };
24*c9945492SAndroid Build Coastguard Worker
netlink_msg_to_nameindex(void * pctx,struct nlmsghdr * h)25*c9945492SAndroid Build Coastguard Worker static int netlink_msg_to_nameindex(void *pctx, struct nlmsghdr *h)
26*c9945492SAndroid Build Coastguard Worker {
27*c9945492SAndroid Build Coastguard Worker struct ifnameindexctx *ctx = pctx;
28*c9945492SAndroid Build Coastguard Worker struct ifnamemap *map;
29*c9945492SAndroid Build Coastguard Worker struct rtattr *rta;
30*c9945492SAndroid Build Coastguard Worker unsigned int i;
31*c9945492SAndroid Build Coastguard Worker int index, type, namelen, bucket;
32*c9945492SAndroid Build Coastguard Worker
33*c9945492SAndroid Build Coastguard Worker if (h->nlmsg_type == RTM_NEWLINK) {
34*c9945492SAndroid Build Coastguard Worker struct ifinfomsg *ifi = NLMSG_DATA(h);
35*c9945492SAndroid Build Coastguard Worker index = ifi->ifi_index;
36*c9945492SAndroid Build Coastguard Worker type = IFLA_IFNAME;
37*c9945492SAndroid Build Coastguard Worker rta = NLMSG_RTA(h, sizeof(*ifi));
38*c9945492SAndroid Build Coastguard Worker } else {
39*c9945492SAndroid Build Coastguard Worker struct ifaddrmsg *ifa = NLMSG_DATA(h);
40*c9945492SAndroid Build Coastguard Worker index = ifa->ifa_index;
41*c9945492SAndroid Build Coastguard Worker type = IFA_LABEL;
42*c9945492SAndroid Build Coastguard Worker rta = NLMSG_RTA(h, sizeof(*ifa));
43*c9945492SAndroid Build Coastguard Worker }
44*c9945492SAndroid Build Coastguard Worker for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
45*c9945492SAndroid Build Coastguard Worker if (rta->rta_type != type) continue;
46*c9945492SAndroid Build Coastguard Worker
47*c9945492SAndroid Build Coastguard Worker namelen = RTA_DATALEN(rta) - 1;
48*c9945492SAndroid Build Coastguard Worker if (namelen > IFNAMSIZ) return 0;
49*c9945492SAndroid Build Coastguard Worker
50*c9945492SAndroid Build Coastguard Worker /* suppress duplicates */
51*c9945492SAndroid Build Coastguard Worker bucket = index % IFADDRS_HASH_SIZE;
52*c9945492SAndroid Build Coastguard Worker i = ctx->hash[bucket];
53*c9945492SAndroid Build Coastguard Worker while (i) {
54*c9945492SAndroid Build Coastguard Worker map = &ctx->list[i-1];
55*c9945492SAndroid Build Coastguard Worker if (map->index == index &&
56*c9945492SAndroid Build Coastguard Worker map->namelen == namelen &&
57*c9945492SAndroid Build Coastguard Worker memcmp(map->name, RTA_DATA(rta), namelen) == 0)
58*c9945492SAndroid Build Coastguard Worker return 0;
59*c9945492SAndroid Build Coastguard Worker i = map->hash_next;
60*c9945492SAndroid Build Coastguard Worker }
61*c9945492SAndroid Build Coastguard Worker
62*c9945492SAndroid Build Coastguard Worker if (ctx->num >= ctx->allocated) {
63*c9945492SAndroid Build Coastguard Worker size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8;
64*c9945492SAndroid Build Coastguard Worker if (a > SIZE_MAX/sizeof *map) return -1;
65*c9945492SAndroid Build Coastguard Worker map = realloc(ctx->list, a * sizeof *map);
66*c9945492SAndroid Build Coastguard Worker if (!map) return -1;
67*c9945492SAndroid Build Coastguard Worker ctx->list = map;
68*c9945492SAndroid Build Coastguard Worker ctx->allocated = a;
69*c9945492SAndroid Build Coastguard Worker }
70*c9945492SAndroid Build Coastguard Worker map = &ctx->list[ctx->num];
71*c9945492SAndroid Build Coastguard Worker map->index = index;
72*c9945492SAndroid Build Coastguard Worker map->namelen = namelen;
73*c9945492SAndroid Build Coastguard Worker memcpy(map->name, RTA_DATA(rta), namelen);
74*c9945492SAndroid Build Coastguard Worker ctx->str_bytes += namelen + 1;
75*c9945492SAndroid Build Coastguard Worker ctx->num++;
76*c9945492SAndroid Build Coastguard Worker map->hash_next = ctx->hash[bucket];
77*c9945492SAndroid Build Coastguard Worker ctx->hash[bucket] = ctx->num;
78*c9945492SAndroid Build Coastguard Worker return 0;
79*c9945492SAndroid Build Coastguard Worker }
80*c9945492SAndroid Build Coastguard Worker return 0;
81*c9945492SAndroid Build Coastguard Worker }
82*c9945492SAndroid Build Coastguard Worker
if_nameindex()83*c9945492SAndroid Build Coastguard Worker struct if_nameindex *if_nameindex()
84*c9945492SAndroid Build Coastguard Worker {
85*c9945492SAndroid Build Coastguard Worker struct ifnameindexctx _ctx, *ctx = &_ctx;
86*c9945492SAndroid Build Coastguard Worker struct if_nameindex *ifs = 0, *d;
87*c9945492SAndroid Build Coastguard Worker struct ifnamemap *s;
88*c9945492SAndroid Build Coastguard Worker char *p;
89*c9945492SAndroid Build Coastguard Worker int i;
90*c9945492SAndroid Build Coastguard Worker int cs;
91*c9945492SAndroid Build Coastguard Worker
92*c9945492SAndroid Build Coastguard Worker pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
93*c9945492SAndroid Build Coastguard Worker memset(ctx, 0, sizeof(*ctx));
94*c9945492SAndroid Build Coastguard Worker if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err;
95*c9945492SAndroid Build Coastguard Worker
96*c9945492SAndroid Build Coastguard Worker ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes);
97*c9945492SAndroid Build Coastguard Worker if (!ifs) goto err;
98*c9945492SAndroid Build Coastguard Worker
99*c9945492SAndroid Build Coastguard Worker p = (char*)(ifs + ctx->num + 1);
100*c9945492SAndroid Build Coastguard Worker for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) {
101*c9945492SAndroid Build Coastguard Worker d->if_index = s->index;
102*c9945492SAndroid Build Coastguard Worker d->if_name = p;
103*c9945492SAndroid Build Coastguard Worker memcpy(p, s->name, s->namelen);
104*c9945492SAndroid Build Coastguard Worker p += s->namelen;
105*c9945492SAndroid Build Coastguard Worker *p++ = 0;
106*c9945492SAndroid Build Coastguard Worker }
107*c9945492SAndroid Build Coastguard Worker d->if_index = 0;
108*c9945492SAndroid Build Coastguard Worker d->if_name = 0;
109*c9945492SAndroid Build Coastguard Worker err:
110*c9945492SAndroid Build Coastguard Worker pthread_setcancelstate(cs, 0);
111*c9945492SAndroid Build Coastguard Worker free(ctx->list);
112*c9945492SAndroid Build Coastguard Worker errno = ENOBUFS;
113*c9945492SAndroid Build Coastguard Worker return ifs;
114*c9945492SAndroid Build Coastguard Worker }
115