PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/newcnix/cnix-newlib/net/getifaddrs.c

http://newcnix.googlecode.com/
C | 401 lines | 321 code | 42 blank | 38 comment | 65 complexity | 28ae66528629067d57d91718121dc641 MD5 | raw file
  1. /* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun 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. /*
  27. * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
  28. * try-and-error for region size.
  29. */
  30. #include <sys/cdefs.h>
  31. #include <sys/types.h>
  32. #include <sys/types.h>
  33. #include <sys/sockio.h>
  34. #include <unistd.h>
  35. #include "namespace.h"
  36. #include <sys/types.h>
  37. #include <sys/ioctl.h>
  38. #include <sys/socket.h>
  39. #include <net/if.h>
  40. #ifdef NET_RT_IFLIST
  41. #include <sys/param.h>
  42. #include <net/route.h>
  43. #include <sys/sysctl.h>
  44. #include <net/if_dl.h>
  45. #endif
  46. #include <ifaddrs.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include "un-namespace.h"
  50. #if !defined(AF_LINK)
  51. #define SA_LEN(sa) sizeof(struct sockaddr)
  52. #endif
  53. #if !defined(SA_LEN)
  54. #define SA_LEN(sa) sizeof(struct sockaddr)
  55. #endif
  56. #define SALIGN (sizeof(long) - 1)
  57. #define SA_RLEN(sa) (sizeof(struct sockaddr) ? ((sizeof(struct sockaddr) + SALIGN) & ~SALIGN) : (SALIGN + 1))
  58. #ifndef ALIGNBYTES
  59. /*
  60. * On systems with a routing socket, ALIGNBYTES should match the value
  61. * that the kernel uses when building the messages.
  62. */
  63. #define ALIGNBYTES (sizeof(int) - 1) // XXX
  64. #endif
  65. #ifndef ALIGN
  66. #define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
  67. #endif
  68. #if _BSDI_VERSION >= 199701
  69. #define HAVE_IFM_DATA
  70. #endif
  71. #if _BSDI_VERSION >= 199802
  72. /* ifam_data is very specific to recent versions of bsdi */
  73. #define HAVE_IFAM_DATA
  74. #endif
  75. #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
  76. #define HAVE_IFM_DATA
  77. #endif
  78. int
  79. getifaddrs(struct ifaddrs **pif)
  80. {
  81. int icnt = 1;
  82. int dcnt = 0;
  83. int ncnt = 0;
  84. #ifdef NET_RT_IFLIST
  85. int mib[6];
  86. size_t needed;
  87. char *buf;
  88. char *next;
  89. struct ifaddrs *cif = 0;
  90. char *p, *p0;
  91. struct rt_msghdr *rtm;
  92. struct if_msghdr *ifm;
  93. struct ifa_msghdr *ifam;
  94. struct sockaddr_dl *dl;
  95. struct sockaddr *sa;
  96. struct ifaddrs *ifa, *ift;
  97. u_short idx = 0;
  98. #else /* NET_RT_IFLIST */
  99. struct ifaddrs *ifa, *ift;
  100. char buf[1024];
  101. int m, sock;
  102. struct ifconf ifc;
  103. struct ifreq *ifr;
  104. struct ifreq *lifr;
  105. #endif /* NET_RT_IFLIST */
  106. int i;
  107. size_t len, alen;
  108. char *data;
  109. char *names;
  110. #ifdef NET_RT_IFLIST
  111. mib[0] = CTL_NET;
  112. mib[1] = PF_ROUTE;
  113. mib[2] = 0; /* protocol */
  114. mib[3] = 0; /* wildcard address family */
  115. mib[4] = NET_RT_IFLIST;
  116. mib[5] = 0; /* no flags */
  117. if (__sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
  118. return (-1);
  119. if ((buf = malloc(needed)) == NULL)
  120. return (-1);
  121. if (__sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
  122. free(buf);
  123. return (-1);
  124. }
  125. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  126. rtm = (struct rt_msghdr *)(void *)next;
  127. if (rtm->rtm_version != RTM_VERSION)
  128. continue;
  129. switch (rtm->rtm_type) {
  130. case RTM_IFINFO:
  131. ifm = (struct if_msghdr *)(void *)rtm;
  132. if (ifm->ifm_addrs & RTA_IFP) {
  133. idx = ifm->ifm_index;
  134. ++icnt;
  135. dl = (struct sockaddr_dl *)(void *)(ifm + 1);
  136. dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
  137. ALIGNBYTES;
  138. #ifdef HAVE_IFM_DATA
  139. dcnt += sizeof(ifm->ifm_data);
  140. #endif /* HAVE_IFM_DATA */
  141. ncnt += dl->sdl_nlen + 1;
  142. } else
  143. idx = 0;
  144. break;
  145. case RTM_NEWADDR:
  146. ifam = (struct ifa_msghdr *)(void *)rtm;
  147. if (idx && ifam->ifam_index != idx)
  148. abort(); /* this cannot happen */
  149. #define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
  150. if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
  151. break;
  152. p = (char *)(void *)(ifam + 1);
  153. ++icnt;
  154. #ifdef HAVE_IFAM_DATA
  155. dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
  156. #endif /* HAVE_IFAM_DATA */
  157. /* Scan to look for length of address */
  158. alen = 0;
  159. for (p0 = p, i = 0; i < RTAX_MAX; i++) {
  160. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  161. == 0)
  162. continue;
  163. sa = (struct sockaddr *)(void *)p;
  164. len = SA_RLEN(sa);
  165. if (i == RTAX_IFA) {
  166. alen = len;
  167. break;
  168. }
  169. p += len;
  170. }
  171. for (p = p0, i = 0; i < RTAX_MAX; i++) {
  172. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  173. == 0)
  174. continue;
  175. sa = (struct sockaddr *)(void *)p;
  176. len = SA_RLEN(sa);
  177. if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
  178. dcnt += alen;
  179. else
  180. dcnt += len;
  181. p += len;
  182. }
  183. break;
  184. }
  185. }
  186. #else /* NET_RT_IFLIST */
  187. ifc.ifc_buf = buf;
  188. ifc.ifc_len = sizeof(buf);
  189. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  190. return (-1);
  191. i = ioctl(sock, SIOCGIFCONF, (char *)&ifc);
  192. close(sock);
  193. if (i < 0)
  194. return (-1);
  195. ifr = ifc.ifc_req;
  196. lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
  197. while (ifr < lifr) {
  198. struct sockaddr *sa;
  199. sa = &ifr->ifr_addr;
  200. ++icnt;
  201. dcnt += SA_RLEN(sa);
  202. ncnt += sizeof(ifr->ifr_name) + 1;
  203. if (SA_LEN(sa) < sizeof(*sa))
  204. ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
  205. else
  206. ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
  207. }
  208. #endif /* NET_RT_IFLIST */
  209. if (icnt + dcnt + ncnt == 1) {
  210. *pif = NULL;
  211. free(buf);
  212. return (0);
  213. }
  214. data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
  215. if (data == NULL) {
  216. free(buf);
  217. return(-1);
  218. }
  219. ifa = (struct ifaddrs *)(void *)data;
  220. data += sizeof(struct ifaddrs) * icnt;
  221. names = data + dcnt;
  222. memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
  223. ift = ifa;
  224. #ifdef NET_RT_IFLIST
  225. idx = 0;
  226. for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
  227. rtm = (struct rt_msghdr *)(void *)next;
  228. if (rtm->rtm_version != RTM_VERSION)
  229. continue;
  230. switch (rtm->rtm_type) {
  231. case RTM_IFINFO:
  232. ifm = (struct if_msghdr *)(void *)rtm;
  233. if (ifm->ifm_addrs & RTA_IFP) {
  234. idx = ifm->ifm_index;
  235. dl = (struct sockaddr_dl *)(void *)(ifm + 1);
  236. cif = ift;
  237. ift->ifa_name = names;
  238. ift->ifa_flags = (int)ifm->ifm_flags;
  239. memcpy(names, dl->sdl_data,
  240. (size_t)dl->sdl_nlen);
  241. names[dl->sdl_nlen] = 0;
  242. names += dl->sdl_nlen + 1;
  243. ift->ifa_addr = (struct sockaddr *)(void *)data;
  244. memcpy(data, dl,
  245. (size_t)SA_LEN((struct sockaddr *)
  246. (void *)dl));
  247. data += SA_RLEN((struct sockaddr *)(void *)dl);
  248. #ifdef HAVE_IFM_DATA
  249. /* ifm_data needs to be aligned */
  250. ift->ifa_data = data = (void *)ALIGN(data);
  251. memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
  252. data += sizeof(ifm->ifm_data);
  253. #else /* HAVE_IFM_DATA */
  254. ift->ifa_data = NULL;
  255. #endif /* HAVE_IFM_DATA */
  256. ift = (ift->ifa_next = ift + 1);
  257. } else
  258. idx = 0;
  259. break;
  260. case RTM_NEWADDR:
  261. ifam = (struct ifa_msghdr *)(void *)rtm;
  262. if (idx && ifam->ifam_index != idx)
  263. abort(); /* this cannot happen */
  264. if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
  265. break;
  266. ift->ifa_name = cif->ifa_name;
  267. ift->ifa_flags = cif->ifa_flags;
  268. ift->ifa_data = NULL;
  269. p = (char *)(void *)(ifam + 1);
  270. /* Scan to look for length of address */
  271. alen = 0;
  272. for (p0 = p, i = 0; i < RTAX_MAX; i++) {
  273. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  274. == 0)
  275. continue;
  276. sa = (struct sockaddr *)(void *)p;
  277. len = SA_RLEN(sa);
  278. if (i == RTAX_IFA) {
  279. alen = len;
  280. break;
  281. }
  282. p += len;
  283. }
  284. for (p = p0, i = 0; i < RTAX_MAX; i++) {
  285. if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
  286. == 0)
  287. continue;
  288. sa = (struct sockaddr *)(void *)p;
  289. len = SA_RLEN(sa);
  290. switch (i) {
  291. case RTAX_IFA:
  292. ift->ifa_addr =
  293. (struct sockaddr *)(void *)data;
  294. memcpy(data, p, len);
  295. data += len;
  296. break;
  297. case RTAX_NETMASK:
  298. ift->ifa_netmask =
  299. (struct sockaddr *)(void *)data;
  300. if (SA_LEN(sa) == 0) {
  301. memset(data, 0, alen);
  302. data += alen;
  303. break;
  304. }
  305. memcpy(data, p, len);
  306. data += len;
  307. break;
  308. case RTAX_BRD:
  309. ift->ifa_broadaddr =
  310. (struct sockaddr *)(void *)data;
  311. memcpy(data, p, len);
  312. data += len;
  313. break;
  314. }
  315. p += len;
  316. }
  317. #ifdef HAVE_IFAM_DATA
  318. /* ifam_data needs to be aligned */
  319. ift->ifa_data = data = (void *)ALIGN(data);
  320. memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
  321. data += sizeof(ifam->ifam_data);
  322. #endif /* HAVE_IFAM_DATA */
  323. ift = (ift->ifa_next = ift + 1);
  324. break;
  325. }
  326. }
  327. free(buf);
  328. #else /* NET_RT_IFLIST */
  329. ifr = ifc.ifc_req;
  330. lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
  331. while (ifr < lifr) {
  332. struct sockaddr *sa;
  333. ift->ifa_name = names;
  334. names[sizeof(ifr->ifr_name)] = 0;
  335. strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
  336. while (*names++)
  337. ;
  338. ift->ifa_addr = (struct sockaddr *)data;
  339. sa = &ifr->ifr_addr;
  340. memcpy(data, sa, SA_LEN(sa));
  341. data += SA_RLEN(sa);
  342. ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
  343. ift = (ift->ifa_next = ift + 1);
  344. }
  345. #endif /* NET_RT_IFLIST */
  346. if (--ift >= ifa) {
  347. ift->ifa_next = NULL;
  348. *pif = ifa;
  349. } else {
  350. *pif = NULL;
  351. free(ifa);
  352. }
  353. return (0);
  354. }
  355. void
  356. freeifaddrs(struct ifaddrs *ifp)
  357. {
  358. free(ifp);
  359. }