1/***********************************************************************
2 * Copyright (c) 2009, Secure Endpoints Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in
14 *   the documentation and/or other materials provided with the
15 *   distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 **********************************************************************/
31
32#include<config.h>
33
34#include <roken.h>
35
36#include <ifaddrs.h>
37
38#ifndef _WIN32
39#error This is a Windows specific implementation.
40#endif
41
42static struct sockaddr *
43dupaddr(const sockaddr_gen * src)
44{
45    sockaddr_gen * d = malloc(sizeof(*d));
46
47    if (d) {
48	memcpy(d, src, sizeof(*d));
49    }
50
51    return (struct sockaddr *) d;
52}
53
54int ROKEN_LIB_FUNCTION
55rk_getifaddrs(struct ifaddrs **ifpp)
56{
57    SOCKET s = INVALID_SOCKET;
58    size_t il_len = 8192;
59    int ret = -1;
60    INTERFACE_INFO *il = NULL;
61
62    *ifpp = NULL;
63
64    s = socket(AF_INET, SOCK_DGRAM, 0);
65    if (s == INVALID_SOCKET)
66	return -1;
67
68    for (;;) {
69	DWORD cbret = 0;
70
71	il = malloc(il_len);
72	if (!il)
73	    break;
74
75	ZeroMemory(il, il_len);
76
77	if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, NULL, 0,
78		     (LPVOID) il, (DWORD) il_len, &cbret,
79		     NULL, NULL) == 0) {
80	    il_len = cbret;
81	    break;
82	}
83
84	free (il);
85	il = NULL;
86
87	if (WSAGetLastError() == WSAEFAULT && cbret > il_len) {
88	    il_len = cbret;
89	} else {
90	    break;
91	}
92    }
93
94    if (!il)
95	goto _exit;
96
97    /* il is an array of INTERFACE_INFO structures.  il_len has the
98       actual size of the buffer.  The number of elements is
99       il_len/sizeof(INTERFACE_INFO) */
100
101    {
102	size_t n = il_len / sizeof(INTERFACE_INFO);
103	size_t i;
104
105	for (i = 0; i < n; i++ ) {
106	    struct ifaddrs *ifp;
107
108	    ifp = malloc(sizeof(*ifp));
109	    if (ifp == NULL)
110		break;
111
112	    ZeroMemory(ifp, sizeof(*ifp));
113
114	    ifp->ifa_next = NULL;
115	    ifp->ifa_name = NULL;
116	    ifp->ifa_flags = il[i].iiFlags;
117	    ifp->ifa_addr = dupaddr(&il[i].iiAddress);
118	    ifp->ifa_netmask = dupaddr(&il[i].iiNetmask);
119	    ifp->ifa_broadaddr = dupaddr(&il[i].iiBroadcastAddress);
120	    ifp->ifa_data = NULL;
121
122	    *ifpp = ifp;
123	    ifpp = &ifp->ifa_next;
124	}
125
126	if (i == n)
127	    ret = 0;
128    }
129
130 _exit:
131
132    if (s != INVALID_SOCKET)
133	closesocket(s);
134
135    if (il)
136	free (il);
137
138    return ret;
139}
140
141void ROKEN_LIB_FUNCTION
142rk_freeifaddrs(struct ifaddrs *ifp)
143{
144    struct ifaddrs *p, *q;
145
146    for(p = ifp; p; ) {
147	if (p->ifa_name)
148	    free(p->ifa_name);
149	if(p->ifa_addr)
150	    free(p->ifa_addr);
151	if(p->ifa_dstaddr)
152	    free(p->ifa_dstaddr);
153	if(p->ifa_netmask)
154	    free(p->ifa_netmask);
155	if(p->ifa_data)
156	    free(p->ifa_data);
157	q = p;
158	p = p->ifa_next;
159	free(q);
160    }
161}
162