-#ifdef NEED_LINUX_GETIFADDRS
-
-/* We could do this _much_ better. kame racoon in its current form
- * will esentially die at frequent changes of address configuration.
- */
-
-struct ifaddrs
-{
- struct ifaddrs *ifa_next;
- char ifa_name[16];
- int ifa_ifindex;
- struct sockaddr *ifa_addr;
- struct sockaddr_storage ifa_addrbuf;
-};
-
-static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
-{
- while (RTA_OK(rta, len)) {
- if (rta->rta_type <= max)
- tb[rta->rta_type] = rta;
- rta = RTA_NEXT(rta,len);
- }
- return 0;
-}
-
-static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
-{
- char buf[8192];
- struct sockaddr_nl nladdr;
- struct iovec iov = { buf, sizeof(buf) };
- struct ifaddrmsg *m;
- struct rtattr * rta_tb[IFA_MAX+1];
- struct ifaddrs *I;
-
- while (1) {
- int status;
- struct nlmsghdr *h;
-
- struct msghdr msg = {
- (void*)&nladdr, sizeof(nladdr),
- &iov, 1,
- NULL, 0,
- 0
- };
-
- status = recvmsg(fd, &msg, 0);
-
- if (status < 0)
- continue;
-
- if (status == 0)
- return;
-
- if (nladdr.nl_pid) /* Message not from kernel */
- continue;
-
- h = (struct nlmsghdr*)buf;
- while (NLMSG_OK(h, status)) {
- if (h->nlmsg_seq != seq)
- goto skip_it;
-
- if (h->nlmsg_type == NLMSG_DONE)
- return;
-
- if (h->nlmsg_type == NLMSG_ERROR)
- return;
-
- if (h->nlmsg_type != RTM_NEWADDR)
- goto skip_it;
-
- m = NLMSG_DATA(h);
-
- if (m->ifa_family != AF_INET &&
- m->ifa_family != AF_INET6)
- goto skip_it;
-
- if (m->ifa_flags&IFA_F_TENTATIVE)
- goto skip_it;
-
- memset(rta_tb, 0, sizeof(rta_tb));
- parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
-
- if (rta_tb[IFA_LOCAL] == NULL)
- rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
- if (rta_tb[IFA_LOCAL] == NULL)
- goto skip_it;
-
- I = malloc(sizeof(struct ifaddrs));
- if (!I)
- return;
- memset(I, 0, sizeof(*I));
-
- I->ifa_ifindex = m->ifa_index;
- I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
- I->ifa_addr->sa_family = m->ifa_family;
- if (m->ifa_family == AF_INET) {
- struct sockaddr_in *sin = (void*)I->ifa_addr;
- memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
- } else {
- struct sockaddr_in6 *sin = (void*)I->ifa_addr;
- memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
- if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
- sin->sin6_scope_id = I->ifa_ifindex;
- }
- I->ifa_next = *ifa;
- *ifa = I;
-
-skip_it:
- h = NLMSG_NEXT(h, status);
- }
- if (msg.msg_flags & MSG_TRUNC)
- continue;
- }
- return;
-}
-
-static int getifaddrs(struct ifaddrs **ifa0)
-{
- struct {
- struct nlmsghdr nlh;
- struct rtgenmsg g;
- } req;
- struct sockaddr_nl nladdr;
- static __u32 seq;
- struct ifaddrs *i;
- int fd;
-
- fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (fd < 0)
- return -1;
-
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
-
- req.nlh.nlmsg_len = sizeof(req);
- req.nlh.nlmsg_type = RTM_GETADDR;
- req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
- req.nlh.nlmsg_pid = 0;
- req.nlh.nlmsg_seq = ++seq;
- req.g.rtgen_family = AF_UNSPEC;
-
- if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
- close(fd);
- return -1;
- }
-
- *ifa0 = NULL;
-
- recvaddrs(fd, ifa0, seq);
-
- close(fd);
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- for (i=*ifa0; i; i = i->ifa_next) {
- struct ifreq ifr;
- ifr.ifr_ifindex = i->ifa_ifindex;
- ioctl(fd, SIOCGIFNAME, (void*)&ifr);
- memcpy(i->ifa_name, ifr.ifr_name, 16);
- }
- close(fd);
-
- return 0;
-}
-
-static void freeifaddrs(struct ifaddrs *ifa0)
-{
- struct ifaddrs *i;
-
- while (ifa0) {
- i = ifa0;
- ifa0 = i->ifa_next;
- free(i);
- }
-}
-
-#endif
-