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