2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS WinSock Helper DLL for TCP/IP
5 * PURPOSE: WSHIoctl - SIO_GET_INTERFACE_LIST
6 * PROGRAMMERS: Andreas Maier
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 */
15 #include <wine/list.h>
21 BOOL
AllocAndGetEntityArray(
24 OUT TDIEntityID
**ppEntities
,
29 ULONG outBufLen
, outBufLenNeeded
;
31 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq
;
33 TDIEntityID
*pEntities
;
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;
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
++)
52 /* maybe free old buffer ... */
55 HeapFree(hHeap
, 0, outBuf
);
59 outBufLen
= outBufLenNeeded
;
60 DPRINT("outBufLen %lx\n", outBufLen
);// 0x24;
61 outBuf
= HeapAlloc(hHeap
, 0, outBufLen
);
68 IOCTL_TCP_QUERY_INFORMATION_EX
,
75 Status
= GetLastError();
77 /* We need TDI_SUCCESS and the outBufLenNeeded must be equal or smaller
78 than our buffer (outBufLen). */
79 if (Status
!= NO_ERROR
)
81 HeapFree(hHeap
, 0, outBuf
);
84 /* status = Success; was the buffer large enough? */
85 if (outBufLenNeeded
<= outBufLen
)
95 *idCount
= (outBufLenNeeded
/ sizeof(TDIEntityID
));
96 *ppEntities
= (TDIEntityID
*)outBuf
;
98 DPRINT("TcpFile %lx\n", (DWORD
)TcpFile
);
100 DPRINT("idCount %lx\n", *idCount
);// 0x24;
102 pEntities
= *ppEntities
;
103 for (i1
= 0; i1
< *idCount
; i1
++)
105 DPRINT("outIfInfo->tei_entity %x\n", (UINT
)pEntities
->tei_entity
);
106 DPRINT("outIfInfo->tei_instance %x\n", (UINT
)pEntities
->tei_instance
);
116 IN TDIEntityID
* pEntityID
,
117 OUT IPSNMPInfo
* outIPSNMPInfo
)
119 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq
;
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(
129 IOCTL_TCP_QUERY_INFORMATION_EX
,
133 sizeof(*outIPSNMPInfo
),
137 DPRINT("DeviceIoControl (IPSNMPInfo) failed, Status %li!\n", GetLastError());
144 INT
GetTdiEntityType(
146 IN TDIEntityID
* pEntityID
,
149 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq
;
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(
159 IOCTL_TCP_QUERY_INFORMATION_EX
,
167 DPRINT("DeviceIoControl (TdiEntityType) failed, Status %li!\n", GetLastError());
176 IN TDIEntityID
* pEntityID
,
177 OUT IFEntry
* pIFEntry
,
180 TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq
;
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(
190 IOCTL_TCP_QUERY_INFORMATION_EX
,
198 DPRINT("DeviceIoControl (IFEntry) failed, Status %li!\n", GetLastError());
205 typedef struct _IntfIDItem
211 /* Ip-Address entries */
212 IPAddrEntry
*pIPAddrEntry0
;
216 WSHIoctl_GetInterfaceList(
217 IN LPVOID OutputBuffer
,
218 IN DWORD OutputBufferLength
,
219 OUT LPDWORD NumberOfBytesReturned
,
220 OUT LPBOOL NeedsCompletion
)
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
;
234 HANDLE hHeap
= GetProcessHeap();
238 /* Init Interface-ID-List */
239 IntfIDList
= HeapAlloc(hHeap
, 0, sizeof(*IntfIDList
));
240 list_init(&IntfIDList
->entry
);
242 /* open tcp-driver */
243 LastErr
= openTcpFile(&TcpFile
, FILE_READ_DATA
| FILE_WRITE_DATA
);
244 if (!NT_SUCCESS(LastErr
))
250 DPRINT("TcpFile %lx\n",(DWORD
)TcpFile
);
252 if (!AllocAndGetEntityArray(TcpFile
,hHeap
,&outEntityID
,&outIDCount
))
254 DPRINT("ERROR in AllocAndGetEntityArray: out of memory!\n");
255 res
= ERROR_OUTOFMEMORY
;
259 IFEntryLen
= sizeof(IFEntry
) + MAX_ADAPTER_DESCRIPTION_LENGTH
+ 1;
260 pIFEntry
= HeapAlloc(hHeap
, 0, IFEntryLen
);
264 res
= ERROR_OUTOFMEMORY
;
269 pEntityID
= outEntityID
;
270 for (i1
= 0; i1
< outIDCount
; i1
++)
272 /* we are only interessted in network layers */
273 if ( (pEntityID
->tei_entity
!= CL_NL_ENTITY
) &&
274 (pEntityID
->tei_entity
!= CO_NL_ENTITY
) )
280 res
= GetIPSNMPInfo(TcpFile
, pEntityID
, &outIPSNMPInfo
);
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
;
290 pIntfIDItem
->pIPAddrEntry0
= NULL
;
295 /* Calculate needed size */
296 outNumberOfBytes
= 0;
297 LIST_FOR_EACH_ENTRY(pIntfIDItem
, &IntfIDList
->entry
, struct _IntfIDItem
, entry
)
299 outNumberOfBytes
+= (pIntfIDItem
->numaddr
* sizeof(INTERFACE_INFO
));
301 DPRINT("Buffer size needed: %lu\n", outNumberOfBytes
);
302 if (outNumberOfBytes
> OutputBufferLength
)
304 /* Buffer to small */
305 if (NumberOfBytesReturned
)
306 *NumberOfBytesReturned
= 0;
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
)
318 inTcpReq1
.ID
.toi_entity
= pIntfIDItem
->id
;
320 BufLen
= sizeof(IPAddrEntry
) * pIntfIDItem
->numaddr
;
321 pIntfIDItem
->pIPAddrEntry0
= HeapAlloc(hHeap
, 0, BufLen
);
323 if (!DeviceIoControl(
325 IOCTL_TCP_QUERY_INFORMATION_EX
,
328 pIntfIDItem
->pIPAddrEntry0
,
333 LastErr
= GetLastError();
334 DPRINT("DeviceIoControl failed, Status %li!\n", LastErr
);
341 pIntfInfo
= (LPINTERFACE_INFO
)OutputBuffer
;
342 LIST_FOR_EACH_ENTRY(pIntfIDItem
, &IntfIDList
->entry
, struct _IntfIDItem
, entry
)
344 DPRINT("Number of addresses %d\n", pIntfIDItem
->numaddr
);
346 pIPAddrEntry
= pIntfIDItem
->pIPAddrEntry0
;
347 for (iAddr
= 0; iAddr
< pIntfIDItem
->numaddr
; iAddr
++)
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
);
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
;
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
;
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
;
368 pIntfInfo
->iiFlags
= IFF_BROADCAST
| IFF_MULTICAST
;
369 if (pIPAddrEntry
->iae_addr
== ntohl(INADDR_LOOPBACK
))
370 pIntfInfo
->iiFlags
|= IFF_LOOPBACK
;
378 /* Get Interface up/down-state and patch pIntfInfo->iiFlags */
379 pEntityID
= outEntityID
;
380 for (i1
= 0; i1
< outIDCount
; i1
++)
382 res
= GetTdiEntityType(TcpFile
, pEntityID
, &TdiType
);
386 if (TdiType
!= IF_MIB
)
392 res
= GetIFEntry(TcpFile
, pEntityID
, pIFEntry
, IFEntryLen
);
396 /* if network isn't up -> no patch needed */
397 if (pIFEntry
->if_operstatus
< IF_OPER_STATUS_CONNECTING
)
403 /* patching ... if interface-index matches */
404 pIntfInfo
= (LPINTERFACE_INFO
)OutputBuffer
;
405 LIST_FOR_EACH_ENTRY(pIntfIDItem
, &IntfIDList
->entry
, struct _IntfIDItem
, entry
)
407 pIPAddrEntry
= pIntfIDItem
->pIPAddrEntry0
;
408 for (iAddr
= 0; iAddr
< pIntfIDItem
->numaddr
; iAddr
++)
410 if (pIPAddrEntry
->iae_index
== pIFEntry
->if_index
)
411 pIntfInfo
->iiFlags
|= IFF_UP
;
421 if (NumberOfBytesReturned
)
422 *NumberOfBytesReturned
= outNumberOfBytes
;
423 if (NeedsCompletion
!= NULL
)
424 *NeedsCompletion
= FALSE
;
428 DPRINT("WSHIoctl_GetInterfaceList - CLEANUP\n");
431 if (pIFEntry
!= NULL
)
432 HeapFree(hHeap
, 0, pIFEntry
);
433 LIST_FOR_EACH_ENTRY_SAFE_REV(pIntfIDItem
, pIntfIDNext
,
434 &IntfIDList
->entry
, struct _IntfIDItem
, entry
)
436 if (pIntfIDItem
->pIPAddrEntry0
!= NULL
)
437 HeapFree(hHeap
, 0, pIntfIDItem
->pIPAddrEntry0
);
438 list_remove(&pIntfIDItem
->entry
);
439 HeapFree(hHeap
, 0, pIntfIDItem
);
441 HeapFree(hHeap
, 0, IntfIDList
);