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