1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * PURPOSE:         Test for WSHIoctl:
5  *                  - SIO_GET_INTERFACE_LIST
6  * PROGRAMMERS:     Andreas Maier
7  */
8 
9 #include "ws2_32.h"
10 
11 #include <iphlpapi.h>
12 
13 void traceaddr(char* txt, sockaddr_gen a)
14 {
15     trace("  %s.AddressIn.sin_family %x\n", txt, a.AddressIn.sin_family);
16     trace("  %s.AddressIn.sin_port %x\n", txt, a.AddressIn.sin_port);
17     trace("  %s.AddressIn.sin_addr.s_addr %lx\n", txt, a.AddressIn.sin_addr.s_addr);
18 }
19 
20 BOOL Test_WSAIoctl_InitTest(
21     OUT PMIB_IPADDRTABLE* ppTable)
22 {
23     PMIB_IPADDRROW pRow;
24     DWORD ret, i1;
25     ULONG TableSize;
26     PMIB_IPADDRTABLE pTable;
27 
28     TableSize = 0;
29     *ppTable = NULL;
30     ret = GetIpAddrTable(NULL, &TableSize, FALSE);
31     if (ret != ERROR_INSUFFICIENT_BUFFER)
32     {
33         skip("GetIpAddrTable failed with %ld. Abort Testing.\n", ret);
34         return FALSE;
35     }
36 
37     /* get sorted ip-address table. Sort order is the ip-address. */
38     pTable = (PMIB_IPADDRTABLE)malloc(TableSize);
39     *ppTable = pTable;
40     ret = GetIpAddrTable(pTable, &TableSize, TRUE);
41     if (ret != NO_ERROR)
42     {
43         skip("GetIpAddrTable failed with %ld. Abort Testing.\n", ret);
44         return FALSE;
45     }
46 
47     if (winetest_debug >= 2)
48     {
49         trace("Result of GetIpAddrTable:\n");
50         trace("Count: %ld\n", pTable->dwNumEntries);
51         pRow = pTable->table;
52         for (i1 = 0; i1 < pTable->dwNumEntries; i1++)
53         {
54             trace("** Entry %ld **\n", i1);
55             trace("  dwAddr %lx\n", pRow->dwAddr);
56             trace("  dwIndex %lx\n", pRow->dwIndex);
57             trace("  dwMask %lx\n", pRow->dwMask);
58             trace("  dwBCastAddr %lx\n", pRow->dwBCastAddr);
59             trace("  dwReasmSize %lx\n", pRow->dwReasmSize);
60             trace("  wType %x\n", pRow->wType);
61             pRow++;
62         }
63         trace("END\n");
64     }
65 
66     return TRUE;
67 }
68 
69 void Test_WSAIoctl_GetInterfaceList()
70 {
71     WSADATA wdata;
72     INT iResult;
73     SOCKET sck;
74     ULONG buflen, BytesReturned, BCastAddr;
75     ULONG infoCount, i1, j1, iiFlagsExpected;
76     BYTE* buf = NULL;
77     LPINTERFACE_INFO ifInfo;
78     PMIB_IPADDRTABLE pTable = NULL;
79     PMIB_IPADDRROW pRow;
80 
81     /* Get PMIB_IPADDRTABE - these results we should get from wshtcpip.dll too. */
82     /* pTable is allocated by Test_WSAIoctl_InitTest! */
83     if (!Test_WSAIoctl_InitTest(&pTable))
84         goto cleanup;
85 
86     /* Start up Winsock */
87     iResult = WSAStartup(MAKEWORD(2, 2), &wdata);
88     ok(iResult == 0, "WSAStartup failed. iResult = %d\n", iResult);
89 
90     /* Create the socket */
91     sck = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0, 0, 0);
92     ok(sck != INVALID_SOCKET, "WSASocket failed. sck = %d\n", (INT)sck);
93     if (sck == INVALID_SOCKET)
94     {
95         skip("Failed to create socket!\n");
96         goto cleanup;
97     }
98 
99     /* Do the Ioctl (buffer to small) */
100     buflen = sizeof(INTERFACE_INFO)-1;
101     buf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, buflen);
102     if (buf == NULL)
103     {
104         skip("Failed to allocate memory!\n");
105         goto cleanup;
106     }
107     BytesReturned = 0;
108     iResult = WSAIoctl(sck, SIO_GET_INTERFACE_LIST, 0, 0,
109                        buf, buflen, &BytesReturned, 0, 0);
110     ok(iResult == -1, "WSAIoctl/SIO_GET_INTERFACE_LIST did not fail! iResult = %d.\n", iResult);
111     ok_hex(WSAGetLastError(), WSAEFAULT);
112     ok(BytesReturned == 0, "WSAIoctl/SIO_GET_INTERFACE_LIST: BytesReturned should be 0, not %ld.\n", BytesReturned);
113     HeapFree(GetProcessHeap(), 0, buf);
114     buf = NULL;
115 
116     /* Do the Ioctl
117        In most cases no loop is done.
118        Only if WSAIoctl fails with WSAEFAULT (buffer to small) we need to retry with a
119        larger buffer */
120     i1 = 0;
121     while (TRUE)
122     {
123         if (buf != NULL)
124         {
125             HeapFree(GetProcessHeap(), 0, buf);
126             buf = NULL;
127         }
128 
129         buflen = sizeof(INTERFACE_INFO) * (i1+1) * 32;
130         buf = (BYTE*)HeapAlloc(GetProcessHeap(), 0, buflen);
131         if (buf == NULL)
132         {
133             skip("Failed to allocate memory!\n");
134             goto cleanup;
135         }
136         BytesReturned = 0;
137         iResult = WSAIoctl(sck, SIO_GET_INTERFACE_LIST, 0, 0,
138                            buf, buflen, &BytesReturned, 0, 0);
139         /* we have what we want ... leave loop */
140         if (iResult == NO_ERROR)
141             break;
142         /* only retry if buffer was to small */
143         /* to avoid infinite loop we maximum retry count is 4 */
144         if ((i1 >= 4) || (WSAGetLastError() != WSAEFAULT))
145         {
146             ok_hex(iResult, NO_ERROR);
147             skip("WSAIoctl / SIO_GET_INTERFACE_LIST\n");
148             goto cleanup;
149         }
150         /* buffer to small -> retry */
151         i1++;
152     }
153 
154     ok_dec(BytesReturned % sizeof(INTERFACE_INFO), 0);
155 
156     /* Calculate how many INTERFACE_INFO we got */
157     infoCount = BytesReturned / sizeof(INTERFACE_INFO);
158     ok(infoCount == pTable->dwNumEntries,
159        "Wrong count of entries! Got %ld, expected %ld.\n", pTable->dwNumEntries, infoCount);
160 
161     if (winetest_debug >= 2)
162     {
163         trace("WSAIoctl\n");
164         trace("  BytesReturned %ld - InfoCount %ld\n ", BytesReturned, infoCount);
165         ifInfo = (LPINTERFACE_INFO)buf;
166         for (i1 = 0; i1 < infoCount; i1++)
167         {
168             trace("entry-index %ld\n", i1);
169             trace("  iiFlags %ld\n", ifInfo->iiFlags);
170             traceaddr("ifInfo^.iiAddress", ifInfo->iiAddress);
171             traceaddr("ifInfo^.iiBroadcastAddress", ifInfo->iiBroadcastAddress);
172             traceaddr("ifInfo^.iiNetmask", ifInfo->iiNetmask);
173             ifInfo++;
174         }
175     }
176 
177     /* compare entries */
178     ifInfo = (LPINTERFACE_INFO)buf;
179     for (i1 = 0; i1 < infoCount; i1++)
180     {
181         if (winetest_debug >= 2)
182             trace("Entry %ld\n", i1);
183         for (j1 = 0; j1 < pTable->dwNumEntries; j1++)
184         {
185             if (ifInfo[i1].iiAddress.AddressIn.sin_addr.s_addr == pTable->table[j1].dwAddr)
186             {
187                 pRow = &pTable->table[j1];
188                 break;
189             }
190         }
191         if (j1 == pTable->dwNumEntries)
192         {
193             skip("Skipping interface\n");
194             continue;
195         }
196 
197         /* iiFlags
198          * Don't know if this value is fix for SIO_GET_INTERFACE_LIST! */
199         iiFlagsExpected = IFF_BROADCAST | IFF_MULTICAST;
200         if ((pRow->wType & MIB_IPADDR_DISCONNECTED) == 0)
201             iiFlagsExpected |= IFF_UP;
202         if (pRow->dwAddr == ntohl(INADDR_LOOPBACK))
203         {
204             iiFlagsExpected |= IFF_LOOPBACK;
205             /* on Windows 7 loopback has broadcast flag cleared */
206             //iiFlagsExpected &= ~IFF_BROADCAST;
207         }
208 
209         ok_hex(ifInfo[i1].iiFlags, iiFlagsExpected);
210         ok_hex(ifInfo[i1].iiAddress.AddressIn.sin_addr.s_addr, pRow->dwAddr);
211         // dwBCastAddr is not the "real" Broadcast-Address.
212         BCastAddr = (pRow->dwBCastAddr == 1 && (iiFlagsExpected & IFF_BROADCAST) != 0) ? 0xFFFFFFFF : 0x0;
213         ok_hex(ifInfo[i1].iiBroadcastAddress.AddressIn.sin_addr.s_addr, BCastAddr);
214         ok_hex(ifInfo[i1].iiNetmask.AddressIn.sin_addr.s_addr, pRow->dwMask);
215     }
216 
217 cleanup:
218     if (sck != 0)
219         closesocket(sck);
220     if (pTable != NULL)
221        free(pTable);
222     if (buf != NULL)
223        HeapFree(GetProcessHeap(), 0, buf);
224     WSACleanup();
225 }
226 
227 START_TEST(WSAIoctl)
228 {
229     Test_WSAIoctl_GetInterfaceList();
230 }
231