xref: /aosp_15_r20/external/musl/src/network/if_nameindex.c (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
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