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 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 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 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 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 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