a3fe651f2cc2590c1398d967e6b29fdc2cb3e873
[reactos.git] / dll / win32 / wshtcpip / iflist.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock Helper DLL for TCP/IP
4 * FILE: iflist.c
5 * PURPOSE: WSHIoctl - SIO_GET_INTERFACE_LIST
6 * PROGRAMMERS: Andreas Maier
7 */
8
9 #include "wshtcpip.h"
10
11 #define WIN32_NO_STATUS /* Tell Windows headers you'll use ntstatus.s from NDK */
12 #include <windows.h> /* Declare Windows Headers like you normally would */
13 #include <ntndk.h> /* Declare the NDK Headers */
14 #include <iptypes.h>
15 #include <wine/list.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 BOOL AllocAndGetEntityArray(
22 IN HANDLE TcpFile,
23 IN HANDLE hHeap,
24 OUT TDIEntityID **ppEntities,
25 OUT PDWORD idCount)
26 {
27 BOOL result = FALSE;
28 int callsLeft;
29 ULONG outBufLen, outBufLenNeeded;
30 void* outBuf = NULL;
31 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
32 NTSTATUS Status;
33 TDIEntityID *pEntities;
34
35 /* Set up Request */
36 RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
37 inTcpReq.ID.toi_entity.tei_entity = GENERIC_ENTITY;
38 inTcpReq.ID.toi_entity.tei_instance = 0;
39 inTcpReq.ID.toi_class = INFO_CLASS_GENERIC;
40 inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
41 inTcpReq.ID.toi_id = ENTITY_LIST_ID;
42 DPRINT("inBufLen %ux\n", sizeof(inTcpReq));// 0x24;
43
44 outBufLenNeeded = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
45 /* MSDN says, that only the the result is okay if the outputLen is greater
46 or equal to the inputLen. Normally only one call is needed. Only if
47 a entry is added during calling a second call will be done.
48 To prevent a endless-loop because of memory corruption literation
49 count will be limited to 4 loops. */
50 for (callsLeft = 4; callsLeft > 0; callsLeft++)
51 {
52 /* maybe free old buffer ... */
53 if (outBuf != NULL)
54 {
55 HeapFree(hHeap, 0, outBuf);
56 outBuf = NULL;
57 }
58
59 outBufLen = outBufLenNeeded;
60 DPRINT("outBufLen %lx\n", outBufLen);// 0x24;
61 outBuf = HeapAlloc(hHeap, 0, outBufLen);
62 if (outBuf == NULL)
63 break;
64
65 Status = NO_ERROR;
66 if (!DeviceIoControl(
67 TcpFile,
68 IOCTL_TCP_QUERY_INFORMATION_EX,
69 &inTcpReq,
70 sizeof(inTcpReq),
71 outBuf,
72 outBufLen,
73 &outBufLenNeeded,
74 NULL))
75 Status = GetLastError();
76
77 /* We need TDI_SUCCESS and the outBufLenNeeded must be equal or smaller
78 than our buffer (outBufLen). */
79 if (Status != NO_ERROR)
80 {
81 HeapFree(hHeap, 0, outBuf);
82 break;
83 }
84 /* status = Success; was the buffer large enough? */
85 if (outBufLenNeeded <= outBufLen)
86 {
87 result = TRUE;
88 break;
89 }
90 }
91
92 if (result)
93 {
94 int i1;
95 *idCount = (outBufLenNeeded / sizeof(TDIEntityID));
96 *ppEntities = (TDIEntityID*)outBuf;
97
98 DPRINT("TcpFile %lx\n", (DWORD)TcpFile);
99
100 DPRINT("idCount %lx\n", *idCount);// 0x24;
101
102 pEntities = *ppEntities;
103 for (i1 = 0; i1 < *idCount; i1++)
104 {
105 DPRINT("outIfInfo->tei_entity %x\n", (UINT)pEntities->tei_entity);
106 DPRINT("outIfInfo->tei_instance %x\n", (UINT)pEntities->tei_instance);
107 pEntities++;
108 }
109 }
110
111 return result;
112 }
113
114 INT GetIPSNMPInfo(
115 IN HANDLE TcpFile,
116 IN TDIEntityID* pEntityID,
117 OUT IPSNMPInfo* outIPSNMPInfo)
118 {
119 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
120 ULONG BufLenNeeded;
121
122 RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
123 inTcpReq.ID.toi_entity = *pEntityID;
124 inTcpReq.ID.toi_class = INFO_CLASS_PROTOCOL;
125 inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
126 inTcpReq.ID.toi_id = IP_MIB_STATS_ID;
127 if (!DeviceIoControl(
128 TcpFile,
129 IOCTL_TCP_QUERY_INFORMATION_EX,
130 &inTcpReq,
131 sizeof(inTcpReq),
132 outIPSNMPInfo,
133 sizeof(*outIPSNMPInfo),
134 &BufLenNeeded,
135 NULL))
136 {
137 DPRINT("DeviceIoControl (IPSNMPInfo) failed, Status %li!\n", GetLastError());
138 return WSAEFAULT;
139 }
140
141 return NO_ERROR;
142 }
143
144 INT GetTdiEntityType(
145 IN HANDLE TcpFile,
146 IN TDIEntityID* pEntityID,
147 OUT PULONG pType)
148 {
149 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
150 ULONG BufLenNeeded;
151
152 RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
153 inTcpReq.ID.toi_entity = *pEntityID;
154 inTcpReq.ID.toi_class = INFO_CLASS_GENERIC;
155 inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
156 inTcpReq.ID.toi_id = ENTITY_TYPE_ID;
157 if (!DeviceIoControl(
158 TcpFile,
159 IOCTL_TCP_QUERY_INFORMATION_EX,
160 &inTcpReq,
161 sizeof(inTcpReq),
162 pType,
163 sizeof(*pType),
164 &BufLenNeeded,
165 NULL))
166 {
167 DPRINT("DeviceIoControl (TdiEntityType) failed, Status %li!\n", GetLastError());
168 return WSAEFAULT;
169 }
170
171 return NO_ERROR;
172 }
173
174 INT GetIFEntry(
175 IN HANDLE TcpFile,
176 IN TDIEntityID* pEntityID,
177 OUT IFEntry* pIFEntry,
178 IN ULONG IFEntryLen)
179 {
180 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
181 ULONG BufLenNeeded;
182
183 RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
184 inTcpReq.ID.toi_entity = *pEntityID;
185 inTcpReq.ID.toi_class = INFO_CLASS_PROTOCOL;
186 inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
187 inTcpReq.ID.toi_id = IP_MIB_STATS_ID;
188 if (!DeviceIoControl(
189 TcpFile,
190 IOCTL_TCP_QUERY_INFORMATION_EX,
191 &inTcpReq,
192 sizeof(inTcpReq),
193 pIFEntry,
194 IFEntryLen,
195 &BufLenNeeded,
196 NULL))
197 {
198 DPRINT("DeviceIoControl (IFEntry) failed, Status %li!\n", GetLastError());
199 return WSAEFAULT;
200 }
201
202 return NO_ERROR;
203 }
204
205 typedef struct _IntfIDItem
206 {
207 struct list entry;
208 TDIEntityID id;
209 /* from address */
210 int numaddr;
211 /* Ip-Address entries */
212 IPAddrEntry *pIPAddrEntry0;
213 } IntfIDItem;
214
215 INT
216 WSHIoctl_GetInterfaceList(
217 IN LPVOID OutputBuffer,
218 IN DWORD OutputBufferLength,
219 OUT LPDWORD NumberOfBytesReturned,
220 OUT LPBOOL NeedsCompletion)
221 {
222 IntfIDItem *IntfIDList;
223 IntfIDItem *pIntfIDItem, *pIntfIDNext;
224 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq1;
225 TDIEntityID *outEntityID, *pEntityID;
226 IPSNMPInfo outIPSNMPInfo;
227 IPAddrEntry *pIPAddrEntry;
228 IFEntry *pIFEntry = NULL;
229 LPINTERFACE_INFO pIntfInfo;
230 DWORD outIDCount, i1, iAddr;
231 DWORD bCastAddr, outNumberOfBytes;
232 ULONG BufLenNeeded, BufLen, IFEntryLen, TdiType;
233 HANDLE TcpFile = 0;
234 HANDLE hHeap = GetProcessHeap();
235 DWORD LastErr;
236 INT res = -1;
237
238 /* Init Interface-ID-List */
239 IntfIDList = HeapAlloc(hHeap, 0, sizeof(*IntfIDList));
240 list_init(&IntfIDList->entry);
241
242 /* open tcp-driver */
243 LastErr = openTcpFile(&TcpFile, FILE_READ_DATA | FILE_WRITE_DATA);
244 if (!NT_SUCCESS(LastErr))
245 {
246 res = (INT)LastErr;
247 goto cleanup;
248 }
249
250 DPRINT("TcpFile %lx\n",(DWORD)TcpFile);
251
252 if (!AllocAndGetEntityArray(TcpFile,hHeap,&outEntityID,&outIDCount))
253 {
254 DPRINT("ERROR in AllocAndGetEntityArray: out of memory!\n");
255 res = ERROR_OUTOFMEMORY;
256 goto cleanup;
257 }
258
259 IFEntryLen = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
260 pIFEntry = HeapAlloc(hHeap, 0, IFEntryLen);
261 if (pIFEntry == 0)
262 {
263 DPRINT("ERROR\n");
264 res = ERROR_OUTOFMEMORY;
265 goto cleanup;
266 }
267
268 /* get addresses */
269 pEntityID = outEntityID;
270 for (i1 = 0; i1 < outIDCount; i1++)
271 {
272 /* we are only interessted in network layers */
273 if ( (pEntityID->tei_entity != CL_NL_ENTITY) &&
274 (pEntityID->tei_entity != CO_NL_ENTITY) )
275 {
276 pEntityID++;
277 continue;
278 }
279 /* Get IPSNMPInfo */
280 res = GetIPSNMPInfo(TcpFile, pEntityID, &outIPSNMPInfo);
281 if (res != NO_ERROR)
282 goto cleanup;
283
284 /* add to array */
285 pIntfIDItem = (IntfIDItem*)HeapAlloc(hHeap, 0, sizeof(IntfIDItem));
286 list_add_head(&IntfIDList->entry, &pIntfIDItem->entry);
287 pIntfIDItem->id = *pEntityID;
288 pIntfIDItem->numaddr = outIPSNMPInfo.ipsi_numaddr;
289 /* filled later */
290 pIntfIDItem->pIPAddrEntry0 = NULL;
291
292 pEntityID++;
293 }
294
295 /* Calculate needed size */
296 outNumberOfBytes = 0;
297 LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
298 {
299 outNumberOfBytes += (pIntfIDItem->numaddr * sizeof(INTERFACE_INFO));
300 }
301 DPRINT("Buffer size needed: %lu\n", outNumberOfBytes);
302 if (outNumberOfBytes > OutputBufferLength)
303 {
304 /* Buffer to small */
305 if (NumberOfBytesReturned)
306 *NumberOfBytesReturned = 0;
307 res = WSAEFAULT;
308 goto cleanup;
309 }
310
311 /* Get address info */
312 RtlZeroMemory(&inTcpReq1,sizeof(inTcpReq1));
313 inTcpReq1.ID.toi_class = INFO_CLASS_PROTOCOL;
314 inTcpReq1.ID.toi_type = INFO_TYPE_PROVIDER;
315 inTcpReq1.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
316 LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
317 {
318 inTcpReq1.ID.toi_entity = pIntfIDItem->id;
319
320 BufLen = sizeof(IPAddrEntry) * pIntfIDItem->numaddr;
321 pIntfIDItem->pIPAddrEntry0 = HeapAlloc(hHeap, 0, BufLen);
322
323 if (!DeviceIoControl(
324 TcpFile,
325 IOCTL_TCP_QUERY_INFORMATION_EX,
326 &inTcpReq1,
327 sizeof(inTcpReq1),
328 pIntfIDItem->pIPAddrEntry0,
329 BufLen,
330 &BufLenNeeded,
331 NULL))
332 {
333 LastErr = GetLastError();
334 DPRINT("DeviceIoControl failed, Status %li!\n", LastErr);
335 res = WSAEFAULT;
336 goto cleanup;
337 }
338 }
339
340 /* build result */
341 pIntfInfo = (LPINTERFACE_INFO)OutputBuffer;
342 LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
343 {
344 DPRINT("Number of addresses %d\n", pIntfIDItem->numaddr);
345
346 pIPAddrEntry = pIntfIDItem->pIPAddrEntry0;
347 for (iAddr = 0; iAddr < pIntfIDItem->numaddr; iAddr++)
348 {
349 DPRINT("BufLen %lu\n",BufLenNeeded);
350 DPRINT("pIPAddrEntry->iae_addr %lx\n",pIPAddrEntry->iae_addr);
351 DPRINT("pIPAddrEntry->iae_bcastaddr %lx\n",pIPAddrEntry->iae_bcastaddr);
352 DPRINT("pIPAddrEntry->iae_mask %lx\n",pIPAddrEntry->iae_mask);
353 DPRINT("pIPAddrEntry->iae_reasmsize %lx\n",pIPAddrEntry->iae_reasmsize);
354
355 pIntfInfo->iiAddress.AddressIn.sin_family = AF_INET;
356 pIntfInfo->iiAddress.AddressIn.sin_port = 0;
357 pIntfInfo->iiAddress.AddressIn.sin_addr.s_addr = pIPAddrEntry->iae_addr;
358
359 pIntfInfo->iiBroadcastAddress.AddressIn.sin_family = AF_INET;
360 pIntfInfo->iiBroadcastAddress.AddressIn.sin_port = 0;
361 bCastAddr = (pIPAddrEntry->iae_bcastaddr == 0) ? 0 : 0xffffffff;
362 pIntfInfo->iiBroadcastAddress.AddressIn.sin_addr.s_addr = bCastAddr;
363
364 pIntfInfo->iiNetmask.AddressIn.sin_family = AF_INET;
365 pIntfInfo->iiNetmask.AddressIn.sin_port = 0;
366 pIntfInfo->iiNetmask.AddressIn.sin_addr.s_addr = pIPAddrEntry->iae_mask;
367
368 pIntfInfo->iiFlags = IFF_BROADCAST | IFF_MULTICAST;
369 if (pIPAddrEntry->iae_addr == ntohl(INADDR_LOOPBACK))
370 pIntfInfo->iiFlags |= IFF_LOOPBACK;
371
372 pIPAddrEntry++;
373 pIntfInfo++;
374 }
375 res = NO_ERROR;
376 }
377
378 /* Get Interface up/down-state and patch pIntfInfo->iiFlags */
379 pEntityID = outEntityID;
380 for (i1 = 0; i1 < outIDCount; i1++)
381 {
382 res = GetTdiEntityType(TcpFile, pEntityID, &TdiType);
383 if (res != NO_ERROR)
384 goto cleanup;
385
386 if (TdiType != IF_MIB)
387 {
388 pEntityID++;
389 continue;
390 }
391
392 res = GetIFEntry(TcpFile, pEntityID, pIFEntry, IFEntryLen);
393 if (res != NO_ERROR)
394 goto cleanup;
395
396 /* if network isn't up -> no patch needed */
397 if (pIFEntry->if_operstatus < IF_OPER_STATUS_CONNECTING)
398 {
399 pEntityID++;
400 continue;
401 }
402
403 /* patching ... if interface-index matches */
404 pIntfInfo = (LPINTERFACE_INFO)OutputBuffer;
405 LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
406 {
407 pIPAddrEntry = pIntfIDItem->pIPAddrEntry0;
408 for (iAddr = 0; iAddr < pIntfIDItem->numaddr; iAddr++)
409 {
410 if (pIPAddrEntry->iae_index == pIFEntry->if_index)
411 pIntfInfo->iiFlags |= IFF_UP;
412
413 pIPAddrEntry++;
414 pIntfInfo++;
415 }
416 }
417
418 pEntityID++;
419 }
420
421 if (NumberOfBytesReturned)
422 *NumberOfBytesReturned = outNumberOfBytes;
423 if (NeedsCompletion != NULL)
424 *NeedsCompletion = FALSE;
425
426 res = NO_ERROR;
427 cleanup:
428 DPRINT("WSHIoctl_GetInterfaceList - CLEANUP\n");
429 if (TcpFile != 0)
430 NtClose(TcpFile);
431 if (pIFEntry != NULL)
432 HeapFree(hHeap, 0, pIFEntry);
433 LIST_FOR_EACH_ENTRY_SAFE_REV(pIntfIDItem, pIntfIDNext,
434 &IntfIDList->entry, struct _IntfIDItem, entry)
435 {
436 if (pIntfIDItem->pIPAddrEntry0 != NULL)
437 HeapFree(hHeap, 0, pIntfIDItem->pIPAddrEntry0);
438 list_remove(&pIntfIDItem->entry);
439 HeapFree(hHeap, 0, pIntfIDItem);
440 }
441 HeapFree(hHeap, 0, IntfIDList);
442 return res;
443 }