10 #define IFADDRS_HASH_SIZE 64
13 unsigned int hash_next
;
15 unsigned char namelen
;
19 struct ifnameindexctx
{
20 unsigned int num
, allocated
, str_bytes
;
21 struct ifnamemap
*list
;
22 unsigned int hash
[IFADDRS_HASH_SIZE
];
25 static int netlink_msg_to_nameindex(void *pctx
, struct nlmsghdr
*h
)
27 struct ifnameindexctx
*ctx
= pctx
;
28 struct ifnamemap
*map
;
31 int index
, type
, namelen
, bucket
;
33 if (h
->nlmsg_type
== RTM_NEWLINK
) {
34 struct ifinfomsg
*ifi
= NLMSG_DATA(h
);
35 index
= ifi
->ifi_index
;
37 rta
= NLMSG_RTA(h
, sizeof(*ifi
));
39 struct ifaddrmsg
*ifa
= NLMSG_DATA(h
);
40 index
= ifa
->ifa_index
;
42 rta
= NLMSG_RTA(h
, sizeof(*ifa
));
44 for (; NLMSG_RTAOK(rta
, h
); rta
= RTA_NEXT(rta
)) {
45 if (rta
->rta_type
!= type
) continue;
47 namelen
= RTA_DATALEN(rta
) - 1;
48 if (namelen
> IFNAMSIZ
) return 0;
50 /* suppress duplicates */
51 bucket
= index
% IFADDRS_HASH_SIZE
;
52 i
= ctx
->hash
[bucket
];
54 map
= &ctx
->list
[i
-1];
55 if (map
->index
== index
&&
56 map
->namelen
== namelen
&&
57 memcmp(map
->name
, RTA_DATA(rta
), namelen
) == 0)
62 if (ctx
->num
>= ctx
->allocated
) {
63 size_t a
= ctx
->allocated
? ctx
->allocated
* 2 + 1 : 8;
64 if (a
> SIZE_MAX
/sizeof *map
) return -1;
65 map
= realloc(ctx
->list
, a
* sizeof *map
);
70 map
= &ctx
->list
[ctx
->num
];
72 map
->namelen
= namelen
;
73 memcpy(map
->name
, RTA_DATA(rta
), namelen
);
74 ctx
->str_bytes
+= namelen
+ 1;
76 map
->hash_next
= ctx
->hash
[bucket
];
77 ctx
->hash
[bucket
] = ctx
->num
;
83 struct if_nameindex
*if_nameindex()
85 struct ifnameindexctx _ctx
, *ctx
= &_ctx
;
86 struct if_nameindex
*ifs
= 0, *d
;
92 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
93 memset(ctx
, 0, sizeof(*ctx
));
94 if (__rtnetlink_enumerate(AF_UNSPEC
, AF_INET
, netlink_msg_to_nameindex
, ctx
) < 0) goto err
;
96 ifs
= malloc(sizeof(struct if_nameindex
[ctx
->num
+1]) + ctx
->str_bytes
);
99 p
= (char*)(ifs
+ ctx
->num
+ 1);
100 for (i
= ctx
->num
, d
= ifs
, s
= ctx
->list
; i
; i
--, s
++, d
++) {
101 d
->if_index
= s
->index
;
103 memcpy(p
, s
->name
, s
->namelen
);
110 pthread_setcancelstate(cs
, 0);