PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

lib/libc/net/getifaddrs.c

http://www.minix3.org/
C | 305 lines | 244 code | 33 blank | 28 comment | 63 complexity | 7b06683bc751cc29f45d23543a7207a6 MD5 | raw file
Possible License(s): MIT, WTFPL, AGPL-1.0, BSD-3-Clause, GPL-3.0, LGPL-2.0, JSON, 0BSD
  1. /* $NetBSD: getifaddrs.c,v 1.13 2010/11/05 16:23:56 pooka Exp $ */
  2. /*
  3. * Copyright (c) 1995, 1999
  4. * Berkeley Software Design, Inc. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
  13. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  14. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  15. * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
  16. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  17. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  18. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  19. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  20. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  21. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  22. * SUCH DAMAGE.
  23. *
  24. * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
  25. */
  26. #include <sys/cdefs.h>
  27. #if defined(LIBC_SCCS) && !defined(lint)
  28. __RCSID("$NetBSD: getifaddrs.c,v 1.13 2010/11/05 16:23:56 pooka Exp $");
  29. #endif /* LIBC_SCCS and not lint */
  30. #ifndef RUMP_ACTION
  31. #include "namespace.h"
  32. #endif
  33. #include <sys/types.h>
  34. #include <sys/ioctl.h>
  35. #include <sys/socket.h>
  36. #include <net/if.h>
  37. #include <sys/param.h>
  38. #include <net/route.h>
  39. #include <sys/sysctl.h>
  40. #include <net/if_dl.h>
  41. #include <assert.h>
  42. #include <errno.h>
  43. #include <ifaddrs.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #if defined(__weak_alias) && !defined(RUMP_ACTION)
  47. __weak_alias(getifaddrs,_getifaddrs)
  48. __weak_alias(freeifaddrs,_freeifaddrs)
  49. #endif
  50. #ifdef RUMP_ACTION
  51. #include <rump/rump_syscalls.h>
  52. #define sysctl(a,b,c,d,e,f) rump_sys___sysctl(a,b,c,d,e,f)
  53. #endif
  54. #define SALIGN (sizeof(long) - 1)
  55. #define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
  56. int
  57. getifaddrs(struct ifaddrs **pif)
  58. {
  59. int icnt = 1;
  60. int dcnt = 0;
  61. int ncnt = 0;
  62. int mib[6];
  63. size_t needed;
  64. char *buf;
  65. char *next;
  66. struct ifaddrs cif;
  67. char *p, *p0;
  68. struct rt_msghdr *rtm;
  69. struct if_msghdr *ifm;
  70. struct ifa_msghdr *ifam;
  71. struct sockaddr *sa;
  72. struct ifaddrs *ifa, *ift;
  73. u_short idx = 0;
  74. int i;
  75. size_t len, alen;
  76. char *data;
  77. char *names;
  78. _DIAGASSERT(pif != NULL);
  79. mib[0] = CTL_NET;
  80. mib[1] = PF_ROUTE;
  81. mib[2] = 0; /* protocol */
  82. mib[3] = 0; /* wildcard address family */
  83. mib[4] = NET_RT_IFLIST;
  84. mib[5] = 0; /* no flags */
  85. if (sysctl(mib, __arraycount(mib), NULL, &needed, NULL, 0) < 0)
  86. return (-1);
  87. if ((buf = malloc(needed)) == NULL)
  88. return (-1);
  89. if (sysctl(mib, __arraycount(mib), buf, &needed, NULL, 0) < 0) {
  90. free(buf);
  91. return (-1);
  92. }
  93. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  94. rtm = (struct rt_msghdr *)(void *)next;
  95. if (rtm->rtm_version != RTM_VERSION)
  96. continue;
  97. switch (rtm->rtm_type) {
  98. case RTM_IFINFO:
  99. ifm = (struct if_msghdr *)(void *)rtm;
  100. if (ifm->ifm_addrs & RTA_IFP) {
  101. const struct sockaddr_dl *dl;
  102. idx = ifm->ifm_index;
  103. ++icnt;
  104. dl = (struct sockaddr_dl *)(void *)(ifm + 1);
  105. dcnt += SA_RLEN((const struct sockaddr *)(const void *)dl) +
  106. ALIGNBYTES;
  107. dcnt += sizeof(ifm->ifm_data);
  108. ncnt += dl->sdl_nlen + 1;
  109. } else
  110. idx = 0;
  111. break;
  112. case RTM_NEWADDR:
  113. ifam = (struct ifa_msghdr *)(void *)rtm;
  114. if (idx && ifam->ifam_index != idx)
  115. abort(); /* this cannot happen */
  116. #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
  117. if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
  118. break;
  119. p = (char *)(void *)(ifam + 1);
  120. ++icnt;
  121. /* Scan to look for length of address */
  122. alen = 0;
  123. for (p0 = p, i = 0; i < RTAX_MAX; i++) {
  124. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  125. == 0)
  126. continue;
  127. sa = (struct sockaddr *)(void *)p;
  128. len = SA_RLEN(sa);
  129. if (i == RTAX_IFA) {
  130. alen = len;
  131. break;
  132. }
  133. p += len;
  134. }
  135. for (p = p0, i = 0; i < RTAX_MAX; i++) {
  136. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  137. == 0)
  138. continue;
  139. sa = (struct sockaddr *)(void *)p;
  140. len = SA_RLEN(sa);
  141. if (i == RTAX_NETMASK && sa->sa_len == 0)
  142. dcnt += alen;
  143. else
  144. dcnt += len;
  145. p += len;
  146. }
  147. break;
  148. }
  149. }
  150. if (icnt + dcnt + ncnt == 1) {
  151. *pif = NULL;
  152. free(buf);
  153. return (0);
  154. }
  155. data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
  156. if (data == NULL) {
  157. free(buf);
  158. return(-1);
  159. }
  160. ifa = (struct ifaddrs *)(void *)data;
  161. data += sizeof(struct ifaddrs) * icnt;
  162. names = data + dcnt;
  163. memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
  164. ift = ifa;
  165. idx = 0;
  166. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  167. rtm = (struct rt_msghdr *)(void *)next;
  168. if (rtm->rtm_version != RTM_VERSION)
  169. continue;
  170. switch (rtm->rtm_type) {
  171. case RTM_IFINFO:
  172. ifm = (struct if_msghdr *)(void *)rtm;
  173. if (ifm->ifm_addrs & RTA_IFP) {
  174. const struct sockaddr_dl *dl;
  175. idx = ifm->ifm_index;
  176. dl = (struct sockaddr_dl *)(void *)(ifm + 1);
  177. memset(&cif, 0, sizeof(cif));
  178. cif.ifa_name = names;
  179. cif.ifa_flags = (int)ifm->ifm_flags;
  180. memcpy(names, dl->sdl_data,
  181. (size_t)dl->sdl_nlen);
  182. names[dl->sdl_nlen] = 0;
  183. names += dl->sdl_nlen + 1;
  184. cif.ifa_addr = (struct sockaddr *)(void *)data;
  185. memcpy(data, dl, (size_t)dl->sdl_len);
  186. data += SA_RLEN((const struct sockaddr *)(const void *)dl);
  187. /* ifm_data needs to be aligned */
  188. cif.ifa_data = data = (void *)ALIGN(data);
  189. memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
  190. data += sizeof(ifm->ifm_data);
  191. } else
  192. idx = 0;
  193. break;
  194. case RTM_NEWADDR:
  195. ifam = (struct ifa_msghdr *)(void *)rtm;
  196. if (idx && ifam->ifam_index != idx)
  197. abort(); /* this cannot happen */
  198. if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
  199. break;
  200. ift->ifa_name = cif.ifa_name;
  201. ift->ifa_flags = cif.ifa_flags;
  202. ift->ifa_data = NULL;
  203. p = (char *)(void *)(ifam + 1);
  204. /* Scan to look for length of address */
  205. alen = 0;
  206. for (p0 = p, i = 0; i < RTAX_MAX; i++) {
  207. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  208. == 0)
  209. continue;
  210. sa = (struct sockaddr *)(void *)p;
  211. len = SA_RLEN(sa);
  212. if (i == RTAX_IFA) {
  213. alen = len;
  214. break;
  215. }
  216. p += len;
  217. }
  218. for (p = p0, i = 0; i < RTAX_MAX; i++) {
  219. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  220. == 0)
  221. continue;
  222. sa = (struct sockaddr *)(void *)p;
  223. len = SA_RLEN(sa);
  224. switch (i) {
  225. case RTAX_IFA:
  226. ift->ifa_addr =
  227. (struct sockaddr *)(void *)data;
  228. memcpy(data, p, len);
  229. data += len;
  230. if (ift->ifa_addr->sa_family == AF_LINK)
  231. ift->ifa_data = cif.ifa_data;
  232. break;
  233. case RTAX_NETMASK:
  234. ift->ifa_netmask =
  235. (struct sockaddr *)(void *)data;
  236. if (sa->sa_len == 0) {
  237. memset(data, 0, alen);
  238. data += alen;
  239. break;
  240. }
  241. memcpy(data, p, len);
  242. data += len;
  243. break;
  244. case RTAX_BRD:
  245. ift->ifa_broadaddr =
  246. (struct sockaddr *)(void *)data;
  247. memcpy(data, p, len);
  248. data += len;
  249. break;
  250. }
  251. p += len;
  252. }
  253. ift = (ift->ifa_next = ift + 1);
  254. break;
  255. }
  256. }
  257. free(buf);
  258. if (--ift >= ifa) {
  259. ift->ifa_next = NULL;
  260. *pif = ifa;
  261. } else {
  262. *pif = NULL;
  263. free(ifa);
  264. }
  265. return (0);
  266. }
  267. void
  268. freeifaddrs(struct ifaddrs *ifp)
  269. {
  270. _DIAGASSERT(ifp != NULL);
  271. free(ifp);
  272. }