Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3439 lines
86 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ipconfig.cxx
  5. Abstract:
  6. CIpConfig class implementation
  7. Contents:
  8. CIpAddress::GetAddress
  9. CIpAddressList::Find
  10. CIpAddressList::Add(CIpAddress *)
  11. CIpAddressList::Add(DWORD, DWORD, DWORD)
  12. CIpAddressList::GetAddress
  13. CIpAddressList::ThrowOutUnfoundEntries
  14. CAdapterInterface::CAdapterInterface
  15. CAdapterInterface::~CAdapterInterface
  16. CIpConfig::CIpConfig
  17. CIpConfig::~CIpConfig
  18. CIpConfig::GetRouterAddress
  19. CIpConfig::GetDnsAddress
  20. CIpConfig::IsKnownIpAddress
  21. CIpConfig::Refresh
  22. (CIpConfig::GetAdapterList)
  23. (CIpConfig::LoadEntryPoints)
  24. (CIpConfig::UnloadEntryPoints)
  25. (CIpConfig::FindOrCreateInterface)
  26. (CIpConfig::FindInterface)
  27. (CIpConfig::ThrowOutUnfoundEntries)
  28. WsControl
  29. (WinNtWsControl)
  30. (OpenTcpipDriverHandle)
  31. (CloseTcpipDriverHandle)
  32. (GetEntityList)
  33. [InternetMapEntity]
  34. [InternetMapInterface]
  35. Author:
  36. Richard L Firth (rfirth) 29-Oct-1996
  37. Environment:
  38. Win32 user-mode DLL
  39. Notes:
  40. In order to operate correctly, we require the Microsoft Winsock implementation
  41. (WSOCK32.DLL) and the Microsoft TCP/IP stack to be loaded
  42. Revision History:
  43. 29-Oct-1996 rfirth
  44. Created
  45. 15-Jul-1998 arthurbi
  46. Resurrected from the dead
  47. --*/
  48. #include <wininetp.h>
  49. #include "aproxp.h"
  50. //
  51. // manifests
  52. //
  53. #define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arbitrary
  54. //#define DEFAULT_MINIMUM_ENTITIES MAX_TDI_ENTITIES
  55. //
  56. // macros
  57. //
  58. //
  59. // IS_INTERESTING_ADAPTER - TRUE if the type of this adapter (IFEntry) is NOT
  60. // loopback. Loopback (corresponding to local host) is the only one we filter
  61. // out right now
  62. //
  63. #define IS_INTERESTING_ADAPTER(p) (!((p)->if_type == IF_TYPE_LOOPBACK))
  64. #define IS_INTERESTING_ADAPTER_NT5(p) (!((p)->Type == IF_TYPE_RFC877_X25))
  65. //
  66. // globals
  67. //
  68. const char SERVICES_KEY_NAME[] = "SYSTEM\\CurrentControlSet\\Services";
  69. HKEY TcpipLinkageKey = NULL;// = INVALID_HANDLE_VALUE;
  70. HKEY ServicesKey = NULL; // = INVALID_HANDLE_VALUE;
  71. //
  72. // private prototypes
  73. //
  74. PRIVATE
  75. DWORD
  76. WinNtWsControl(
  77. DWORD dwProtocol,
  78. DWORD dwRequest,
  79. LPVOID lpInputBuffer,
  80. LPDWORD lpdwInputBufferLength,
  81. LPVOID lpOutputBuffer,
  82. LPDWORD lpdwOutputBufferLength
  83. );
  84. PRIVATE
  85. DWORD
  86. OpenTcpipDriverHandle(
  87. VOID
  88. );
  89. PRIVATE
  90. VOID
  91. CloseTcpipDriverHandle(
  92. VOID
  93. );
  94. PRIVATE
  95. DWORD
  96. GetEntityList(
  97. OUT TDIEntityID * * lplpEntities
  98. );
  99. //
  100. // private debug prototypes
  101. //
  102. PRIVATE
  103. LPCSTR
  104. InternetMapEntity(
  105. IN INT EntityId
  106. );
  107. PRIVATE
  108. LPCSTR
  109. InternetMapInterface(
  110. IN DWORD InterfaceType
  111. );
  112. PRIVATE
  113. LPCSTR
  114. InternetMapInterfaceOnNT5(
  115. IN DWORD InterfaceType
  116. );
  117. //
  118. // private data
  119. //
  120. //
  121. // NTDLL info - if the platform is NT then we use the following entry points in
  122. // NTDLL.DLL to talk to the TCP/IP device driver
  123. //
  124. PRIVATE VOID (* _I_RtlInitUnicodeString)(PUNICODE_STRING, PCWSTR) = NULL;
  125. PRIVATE NTSTATUS (* _I_NtCreateFile)(PHANDLE,
  126. ACCESS_MASK,
  127. POBJECT_ATTRIBUTES,
  128. PIO_STATUS_BLOCK,
  129. PLARGE_INTEGER,
  130. ULONG,
  131. ULONG,
  132. ULONG,
  133. ULONG,
  134. PVOID,
  135. ULONG
  136. ) = NULL;
  137. PRIVATE ULONG (* _I_RtlNtStatusToDosError)(NTSTATUS) = NULL;
  138. PRIVATE DLL_ENTRY_POINT NtDllEntryPoints[] = {
  139. DLL_ENTRY_POINT_ELEMENT(RtlInitUnicodeString),
  140. DLL_ENTRY_POINT_ELEMENT(NtCreateFile),
  141. DLL_ENTRY_POINT_ELEMENT(RtlNtStatusToDosError)
  142. };
  143. PRIVATE DLL_INFO NtDllInfo = DLL_INFO_INIT("NTDLL.DLL", NtDllEntryPoints);
  144. //
  145. // WSOCK32 info - if the platform is Windows 95 then we use the WsControl entry
  146. // point in WSOCK32.DLL to access the TCP/IP device driver. If we are running
  147. // over non-MS Winsock or TCP/IP then we cannot get the IpConfig info (unless
  148. // the same features are supported)
  149. //
  150. PRIVATE DWORD (PASCAL FAR * _I_WsControl)(DWORD,
  151. DWORD,
  152. LPVOID,
  153. LPDWORD,
  154. LPVOID,
  155. LPDWORD
  156. ) = NULL;
  157. PRIVATE DLL_ENTRY_POINT WsControlEntryPoint[] = {
  158. DLL_ENTRY_POINT_ELEMENT(WsControl)
  159. };
  160. PRIVATE DLL_INFO WsControlInfo = DLL_INFO_INIT("WSOCK32.DLL", WsControlEntryPoint);
  161. PRIVATE HANDLE TcpipDriverHandle = INVALID_HANDLE_VALUE;
  162. //
  163. // Iphlpapi - Ip Helper APIs only found on NT 5 and Win 98, must dynaload,
  164. // Used to gather information on what adapters are avaible on the machine
  165. //
  166. PRIVATE DWORD (PASCAL FAR * _I_GetAdaptersInfo)(PIP_ADAPTER_INFO,
  167. PULONG
  168. ) = NULL;
  169. PRIVATE DLL_ENTRY_POINT IpHlpApiEntryPoints[] = {
  170. DLL_ENTRY_POINT_ELEMENT(GetAdaptersInfo)
  171. };
  172. PRIVATE DLL_INFO IpHlpApiDllInfo = DLL_INFO_INIT("IPHLPAPI.DLL", IpHlpApiEntryPoints);
  173. //
  174. // DhcpcSvc - DHCP dll, Only found on Win'98 and NT 5. This function does almost all the
  175. // work for us using the native DHCP services found on these cool new OSes.
  176. //
  177. PRIVATE DWORD (PASCAL FAR * _I_DhcpRequestOptions)(LPWSTR,
  178. BYTE *,
  179. DWORD,
  180. BYTE **,
  181. DWORD *,
  182. BYTE **,
  183. DWORD *
  184. ) = NULL;
  185. PRIVATE DLL_ENTRY_POINT DhcpcSvcEntryPoints[] = {
  186. DLL_ENTRY_POINT_ELEMENT(DhcpRequestOptions)
  187. };
  188. PRIVATE DLL_INFO DhcpcSvcDllInfo = DLL_INFO_INIT("DHCPCSVC.DLL", DhcpcSvcEntryPoints);
  189. //
  190. // global data
  191. //
  192. // none.
  193. //
  194. // methods
  195. //
  196. //
  197. // public CIpAddress methods
  198. //
  199. BOOL
  200. CIpAddress::GetAddress(
  201. OUT LPBYTE lpbAddress,
  202. IN OUT LPDWORD lpdwAddressLength
  203. )
  204. /*++
  205. Routine Description:
  206. Returns the IP address from this CIpAddress
  207. Arguments:
  208. lpbAddress - pointer to returned address
  209. lpdwAddressLength - size of IP address
  210. Return Value:
  211. BOOL
  212. TRUE - address copied
  213. FALSE - address not copied (buffer not large enough)
  214. --*/
  215. {
  216. if (*lpdwAddressLength >= sizeof(DWORD)) {
  217. *(LPDWORD)lpbAddress = m_dwIpAddress;
  218. *lpdwAddressLength = sizeof(DWORD);
  219. return TRUE;
  220. }
  221. return FALSE;
  222. }
  223. //
  224. // public CIpAddressList methods
  225. //
  226. BOOL
  227. CIpAddressList::IsContextInList(
  228. IN DWORD dwContext
  229. )
  230. {
  231. for (CIpAddress * pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
  232. if (pEntry->Context() == dwContext) {
  233. return TRUE;
  234. }
  235. }
  236. return FALSE;
  237. }
  238. CIpAddress *
  239. CIpAddressList::Find(
  240. IN DWORD dwIpAddress,
  241. IN DWORD dwIpMask
  242. )
  243. /*++
  244. Routine Description:
  245. Finds the CIpAddress object corresponding to (dwIpAddress, dwIpMask)
  246. Arguments:
  247. dwIpAddress - IP address to find
  248. dwIpMask - IP address mask, or INADDR_ANY (0) if we don't care
  249. Return Value:
  250. CIpAddress *
  251. Success - pointer to found object
  252. Failure - NULL
  253. --*/
  254. {
  255. for (CIpAddress * pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
  256. if ((pEntry->IpAddress() == dwIpAddress)
  257. && ((dwIpMask == INADDR_ANY) || (pEntry->IpMask() == dwIpMask))) {
  258. break;
  259. }
  260. }
  261. return pEntry;
  262. }
  263. VOID
  264. CIpAddressList::Add(
  265. IN CIpAddress * pAddress
  266. )
  267. /*++
  268. Routine Description:
  269. Adds an IP address entry to the list
  270. Arguments:
  271. pAddress - pointer to CIpAddress to add
  272. Return Value:
  273. None.
  274. --*/
  275. {
  276. INET_ASSERT(pAddress->m_Next == NULL);
  277. CIpAddress * pEntry = (CIpAddress *)&m_List;
  278. while (pEntry->m_Next != NULL) {
  279. pEntry = pEntry->m_Next;
  280. }
  281. pEntry->m_Next = pAddress;
  282. }
  283. BOOL
  284. CIpAddressList::Add(
  285. IN DWORD dwIpAddress,
  286. IN DWORD dwIpMask,
  287. IN DWORD dwContext
  288. )
  289. /*++
  290. Routine Description:
  291. Adds an IP address entry to the list
  292. Arguments:
  293. dwIpAddress - IP address to add
  294. dwIpMask - IP subnet mask
  295. dwContext - unique interface context value
  296. Return Value:
  297. BOOL
  298. TRUE - item added
  299. FALSE - out of memory
  300. --*/
  301. {
  302. CIpAddress * pIpAddress = new CIpAddress(dwIpAddress, dwIpMask, dwContext);
  303. if (pIpAddress != NULL) {
  304. Add(pIpAddress);
  305. return TRUE;
  306. }
  307. return FALSE;
  308. }
  309. BOOL
  310. CIpAddressList::GetAddress(
  311. IN OUT LPDWORD lpdwIndex,
  312. OUT LPBYTE lpbAddress,
  313. IN OUT LPDWORD lpdwAddressLength
  314. )
  315. /*++
  316. Routine Description:
  317. Returns the *lpdwIndex'th address from the list
  318. Arguments:
  319. lpdwIndex - which address to return. Updated on output
  320. lpbAddress - pointer to returned address
  321. lpdwAddressLength - pointer to returned address length
  322. Return Value:
  323. BOOL
  324. TRUE - address returned
  325. FALSE - address not returned
  326. --*/
  327. {
  328. DEBUG_ENTER((DBG_SOCKETS,
  329. Bool,
  330. "CIpAddressList::GetAddress",
  331. "%#x [%d], %#x, %#x [%d]",
  332. lpdwIndex,
  333. *lpdwIndex,
  334. lpbAddress,
  335. lpdwAddressLength,
  336. *lpdwAddressLength
  337. ));
  338. CIpAddress * p = m_List;
  339. for (DWORD i = 0; (i < *lpdwIndex) && (p != NULL); ++i) {
  340. p = p->m_Next;
  341. }
  342. BOOL found;
  343. if (p != NULL) {
  344. found = p->GetAddress(lpbAddress, lpdwAddressLength);
  345. if (found) {
  346. ++*lpdwIndex;
  347. }
  348. } else {
  349. found = FALSE;
  350. }
  351. DEBUG_LEAVE(found);
  352. return found;
  353. }
  354. PRIVATE
  355. BOOL
  356. CIpAddressList::ThrowOutUnfoundEntries(
  357. VOID
  358. )
  359. /*++
  360. Routine Description:
  361. Throws out (deletes) any addresses that are marked not-found
  362. Arguments:
  363. None.
  364. Return Value:
  365. BOOL
  366. TRUE - interfaces thrown out
  367. FALSE - " not " "
  368. --*/
  369. {
  370. DEBUG_ENTER((DBG_SOCKETS,
  371. Bool,
  372. "CIpAddressList::ThrowOutUnfoundEntries",
  373. NULL
  374. ));
  375. CIpAddress * pLast = (CIpAddress *)&m_List;
  376. CIpAddress * pEntry;
  377. BOOL bThrownOut = FALSE;
  378. for (pEntry = m_List; pEntry != NULL; pEntry = pEntry->m_Next) {
  379. if (!pEntry->IsFound()) {
  380. pLast->m_Next = pEntry->m_Next;
  381. delete pEntry;
  382. bThrownOut = TRUE;
  383. pEntry = pLast;
  384. } else {
  385. pLast = pEntry;
  386. }
  387. }
  388. DEBUG_LEAVE(bThrownOut);
  389. return bThrownOut;
  390. }
  391. //
  392. // public CAdapterInterface methods
  393. //
  394. CAdapterInterface::CAdapterInterface(
  395. IN DWORD dwIndex,
  396. IN DWORD dwType,
  397. IN DWORD dwSpeed,
  398. IN LPSTR lpszDescription,
  399. IN DWORD dwDescriptionLength,
  400. IN LPBYTE lpPhysicalAddress,
  401. IN DWORD dwPhysicalAddressLength
  402. )
  403. /*++
  404. Routine Description:
  405. CAdapterInterface constructor
  406. Arguments:
  407. dwIndex - unique adapter interface index
  408. dwType - type of interface
  409. dwSpeed - speed of interface
  410. lpszDescription - pointer to descriptive name of adapter
  411. dwDescriptionLength - length of lpszDescription
  412. lpPhysicalAddress -
  413. dwPhysicalAddressLength -
  414. Return Value:
  415. None.
  416. --*/
  417. {
  418. if ((lpszDescription != NULL) && (dwDescriptionLength != 0)) {
  419. m_lpszDescription = new char[dwDescriptionLength + 1];
  420. if (m_lpszDescription != NULL) {
  421. memcpy(m_lpszDescription, lpszDescription, dwDescriptionLength);
  422. } else {
  423. dwDescriptionLength = 0;
  424. }
  425. }
  426. if ((lpPhysicalAddress != NULL) && (dwPhysicalAddressLength != 0)) {
  427. m_lpPhysicalAddress = new BYTE[dwPhysicalAddressLength];
  428. if ( m_lpPhysicalAddress != NULL ) {
  429. memcpy(m_lpPhysicalAddress, lpPhysicalAddress, dwPhysicalAddressLength);
  430. }
  431. else {
  432. dwPhysicalAddressLength = 0;
  433. }
  434. }
  435. switch( dwType )
  436. {
  437. case IF_TYPE_ETHERNET:
  438. m_dwPhysicalAddressType = HARDWARE_TYPE_10MB_EITHERNET;
  439. break;
  440. case IF_TYPE_TOKENRING:
  441. case IF_TYPE_FDDI:
  442. m_dwPhysicalAddressType = HARDWARE_TYPE_IEEE_802;
  443. break;
  444. case IF_TYPE_OTHER:
  445. m_dwPhysicalAddressType = HARDWARE_ARCNET;
  446. break;
  447. case IF_TYPE_PPP:
  448. m_dwPhysicalAddressType = HARDWARE_PPP;
  449. break;
  450. default:
  451. //DhcpPrint(("Invalid HW Type, %ld.\n", IFE.if_type ));
  452. INET_ASSERT( FALSE );
  453. m_dwPhysicalAddressType = HARDWARE_ARCNET;
  454. break;
  455. }
  456. m_dwPhysicalAddressLength = dwPhysicalAddressLength;
  457. m_dwDescriptionLength = dwDescriptionLength;
  458. m_lpszAdapterName = NULL;
  459. m_dwIndex = dwIndex;
  460. m_dwType = dwType;
  461. m_dwSpeed = dwSpeed;
  462. m_Flags.Word = 0;
  463. SetFound(TRUE);
  464. }
  465. CAdapterInterface::~CAdapterInterface(
  466. VOID
  467. )
  468. /*++
  469. Routine Description:
  470. CAdapterInterface destructor
  471. Arguments:
  472. None.
  473. Return Value:
  474. None.
  475. --*/
  476. {
  477. if (m_lpszDescription != NULL) {
  478. delete m_lpszDescription;
  479. }
  480. if (m_lpPhysicalAddress != NULL) {
  481. delete m_lpPhysicalAddress;
  482. }
  483. if ( m_lpszAdapterName != NULL) {
  484. FREE_MEMORY(m_lpszAdapterName);
  485. }
  486. }
  487. BOOL
  488. CAdapterInterface::DhcpDoInformNT5(
  489. IN OUT LPSTR lpszAutoProxyUrl,
  490. IN DWORD dwAutoProxyUrlLength
  491. )
  492. /*++
  493. Routine Description:
  494. For a given Interface, this nifly little method uses the new wizbang NT 5/Win'98 specific API
  495. to do the DHCP Inform request and determine an auto-proxy Url that we can use.
  496. Kinda of nice when we're on NT 5, otherwise we need to pull in the kitchen sink equivlent of
  497. DHCP code that has been ripped off from the NT 4/Win'95 code base
  498. Arguments:
  499. lpszAutoProxyUrl - a piece of memory where we can stuff our new auto-proxy URL
  500. dwAutoProxyUrlLength - size of the space to store the string above
  501. Return Value:
  502. BOOL
  503. TRUE - successfully talked to server and got Url
  504. FALSE - failed to allocate memory or failure talking to TCP/IP or failure to get an Url needed to continue
  505. --*/
  506. {
  507. DWORD error;
  508. BYTE bRequestOptions[] = { OPTION_WPAD_URL, OPTION_SUBNET_MASK, OPTION_ROUTER_ADDRESS,
  509. OPTION_DOMAIN_NAME_SERVERS, OPTION_HOST_NAME, OPTION_DOMAIN_NAME };
  510. LPBYTE pbOptionList = NULL, pbReturnOptions = NULL;
  511. DWORD dwOptionListSize, dwReturnOptionSize;
  512. WCHAR wszAdapterName[(MAX_ADAPTER_NAME_LENGTH + 6)];
  513. int len;
  514. len = MultiByteToWideChar(
  515. CP_ACP,
  516. 0, // flags
  517. GetAdapterName(),
  518. -1, // assume null-terminated
  519. wszAdapterName,
  520. (MAX_ADAPTER_NAME_LENGTH + 6)
  521. );
  522. if ( len == 0 ) {
  523. return FALSE; // failed to convert string
  524. }
  525. if ( _I_DhcpRequestOptions == NULL )
  526. {
  527. error = LoadDllEntryPoints(&DhcpcSvcDllInfo, 0);
  528. if ( error != ERROR_SUCCESS ) {
  529. return FALSE;
  530. }
  531. }
  532. error = _I_DhcpRequestOptions(
  533. wszAdapterName, // adapter name
  534. bRequestOptions, // array of byte codes, each represnts an option
  535. sizeof(bRequestOptions),// size of array above
  536. &pbOptionList, // allocated array of option ids returned from server
  537. &dwOptionListSize, // size of above allocated array
  538. &pbReturnOptions, // allocated array of option values
  539. &dwReturnOptionSize
  540. );
  541. if ( error == ERROR_SUCCESS )
  542. {
  543. DWORD dwNextInc = 0;
  544. //
  545. // option ids are returned as byte codes in an array while
  546. // the option data contains a byte size descritor followed
  547. // by the option data itself which is a second array.
  548. //
  549. // pbReturnedOptions = <OPTION_ID_1><OPTION_ID_2> ... <OPTION_ID_N>
  550. // pbOptionValue = (<OPTION_LEN_1><OPTION_DATA_1>) ...
  551. // (<OPTION_LEN_N><OPTION_DATA_N>)
  552. //
  553. // pbOptionId is the byte code of the option itself
  554. // pbOptionValue points to the option length, or the data following it.
  555. //
  556. //
  557. for ( LPBYTE pbOptionId = pbReturnOptions, pbOptionValue = pbOptionList;
  558. (pbOptionId < (pbReturnOptions+dwReturnOptionSize) &&
  559. pbOptionValue < (pbOptionList+dwOptionListSize));
  560. pbOptionId++, pbOptionValue+=(dwNextInc+1) )
  561. {
  562. dwNextInc = *pbOptionValue;
  563. pbOptionValue++; // advance past the size/length byte
  564. if (*pbOptionId == OPTION_WPAD_URL &&
  565. dwAutoProxyUrlLength > dwNextInc &&
  566. lpszAutoProxyUrl)
  567. {
  568. strncpy(lpszAutoProxyUrl, (char *) pbOptionValue, dwNextInc);
  569. return TRUE;
  570. }
  571. }
  572. }
  573. //
  574. // BUGBUG [arthurbi] pbOptionList & pbReturnOptions - need to be freed
  575. // but the documentation says it needs to be freed by DhcpFreeMemory?!?
  576. //
  577. return FALSE;
  578. }
  579. BOOL
  580. CAdapterInterface::CopyAdapterInfoToDhcpContext(
  581. PDHCP_CONTEXT pDhcpContext
  582. )
  583. {
  584. memset ((void *) pDhcpContext, 0, sizeof(DHCP_CONTEXT));
  585. // hardware address, length, and type
  586. pDhcpContext->HardwareAddressType = m_dwPhysicalAddressType;
  587. pDhcpContext->HardwareAddress = m_lpPhysicalAddress;
  588. pDhcpContext->HardwareAddressLength = m_dwPhysicalAddressLength;
  589. if (m_IpList.m_List) {
  590. // Selected IpAddress, NetworkOrder. htonl
  591. // note: assumed to be in network order
  592. pDhcpContext->IpAddress = ((m_IpList.m_List)->IpAddress());
  593. pDhcpContext->IpInterfaceContext = ((m_IpList.m_List)->Context());
  594. }
  595. if (m_DhcpList.m_List) {
  596. // Selected DHCP server address. Network Order. htonl
  597. // note: assumed to be in network order
  598. pDhcpContext->DhcpServerAddress = ((m_DhcpList.m_List)->IpAddress());
  599. }
  600. pDhcpContext->ClientIdentifier.fSpecified = FALSE;
  601. pDhcpContext->T2Time = 0;
  602. // when was the last time an inform was sent?
  603. pDhcpContext->LastInformSent = 0;
  604. // seconds passed since boot.
  605. pDhcpContext->SecondsSinceBoot = 0;
  606. // the list of options to send and the list of options received
  607. InitializeListHead(&pDhcpContext->RecdOptionsList);
  608. InitializeListHead(&pDhcpContext->SendOptionsList);
  609. // the class this adapter belongs to
  610. if ( m_lpszAdapterName )
  611. {
  612. pDhcpContext->ClassId = (unsigned char *) m_lpszAdapterName;
  613. pDhcpContext->ClassIdLength = lstrlen(m_lpszAdapterName);
  614. }
  615. else
  616. {
  617. pDhcpContext->ClassId = NULL;
  618. pDhcpContext->ClassIdLength = 0;
  619. }
  620. // Message buffer to send and receive DHCP message.
  621. pDhcpContext->MessageBuffer = (PDHCP_MESSAGE) pDhcpContext->szMessageBuffer;
  622. memset(pDhcpContext->szMessageBuffer, 0, sizeof(pDhcpContext->szMessageBuffer));
  623. //LocalInfo = (PLOCAL_CONTEXT_INFO)((*pDhcpContext)->LocalInformation);
  624. //LocalInfo->IpInterfaceContext = IpInterfaceContext;
  625. //LocalInfo->IpInterfaceInstance = IpInterfaceInstance;
  626. // IpInterfaceInstance is filled in make context
  627. pDhcpContext->Socket = INVALID_SOCKET;
  628. pDhcpContext->State.Plumbed = TRUE;
  629. pDhcpContext->State.ServerReached = FALSE;
  630. pDhcpContext->State.AutonetEnabled= FALSE;
  631. pDhcpContext->State.HasBeenLooked = FALSE;
  632. pDhcpContext->State.DhcpEnabled = FALSE;
  633. pDhcpContext->State.AutoMode = FALSE;
  634. pDhcpContext->State.MediaState = FALSE;
  635. pDhcpContext->State.MDhcp = FALSE;
  636. pDhcpContext->State.PowerResumed = FALSE;
  637. pDhcpContext->State.Broadcast = FALSE;
  638. return TRUE;
  639. }
  640. //
  641. // public CIpConfig methods
  642. //
  643. CIpConfig::CIpConfig(
  644. VOID
  645. )
  646. /*++
  647. Routine Description:
  648. CIpConfig constructor - initializes the object & loads the requird DLLs if
  649. not already loaded
  650. Arguments:
  651. None.
  652. Return Value:
  653. None.
  654. --*/
  655. {
  656. DEBUG_ENTER((DBG_OBJECTS,
  657. None,
  658. "CIpConfig::CIpConfig",
  659. NULL
  660. ));
  661. InitializeListHead(&m_List);
  662. m_dwNumberOfInterfaces = 0;
  663. m_Loaded = TRI_STATE_UNKNOWN;
  664. DWORD error = LoadEntryPoints();
  665. if (error == ERROR_SUCCESS) {
  666. #ifndef unix
  667. GetAdapterList();
  668. #endif /* unix */
  669. }
  670. DEBUG_LEAVE(0);
  671. }
  672. CIpConfig::~CIpConfig()
  673. /*++
  674. Routine Description:
  675. CIpConfig destructor - destroys this object and unloads (or reduces the
  676. reference count on) the DLLs
  677. Arguments:
  678. None.
  679. Return Value:
  680. None.
  681. --*/
  682. {
  683. DEBUG_ENTER((DBG_OBJECTS,
  684. None,
  685. "CIpConfig::~CIpConfig",
  686. NULL
  687. ));
  688. while (!IsListEmpty(&m_List)) {
  689. PLIST_ENTRY pEntry = RemoveHeadList(&m_List);
  690. //
  691. // BUGBUG - need CONTAINING_RECORD() if m_List is not @ start of
  692. // CAdapterInterface
  693. //
  694. CAdapterInterface * pInterface = (CAdapterInterface *)pEntry;
  695. delete pInterface;
  696. }
  697. UnloadEntryPoints();
  698. CloseTcpipDriverHandle();
  699. DEBUG_LEAVE(0);
  700. }
  701. BOOL
  702. CIpConfig::GetRouterAddress(
  703. IN LPBYTE lpbInterfaceAddress OPTIONAL,
  704. IN DWORD dwInterfaceAddressLength,
  705. IN OUT LPDWORD lpdwIndex,
  706. OUT LPBYTE lpbAddress,
  707. IN OUT LPDWORD lpdwAddressLength
  708. )
  709. /*++
  710. Routine Description:
  711. Returns the *lpdwIndex'th router address belonging to the interface
  712. corresponding to the address in lpbInterfaceAddress
  713. Arguments:
  714. lpbInterfaceAddress - pointer to interface address
  715. dwInterfaceAddressLength - length of interface address
  716. lpdwIndex - index of router address to return
  717. lpbAddress - returned router address
  718. lpdwAddressLength - length of router address
  719. Return Value:
  720. BOOL
  721. TRUE - *lpdwIndex'th router address returned for requested interface
  722. FALSE - requested address not returned
  723. --*/
  724. {
  725. DEBUG_ENTER((DBG_SOCKETS,
  726. Bool,
  727. "CIpConfig::GetRouterAddress",
  728. "%#x, %d, %#x [%d], %#x, %#x [%d]",
  729. lpbInterfaceAddress,
  730. dwInterfaceAddressLength,
  731. lpdwIndex,
  732. *lpdwIndex,
  733. lpbAddress,
  734. lpdwAddressLength,
  735. *lpdwAddressLength
  736. ));
  737. //
  738. // for now, we default to 1st interface
  739. //
  740. INET_ASSERT(lpbInterfaceAddress == NULL);
  741. INET_ASSERT(dwInterfaceAddressLength == sizeof(DWORD));
  742. BOOL found;
  743. //
  744. // no one uses this any more
  745. //
  746. INET_ASSERT(FALSE);
  747. //if (!IsListEmpty(&m_List)) {
  748. // found = ((CAdapterInterface *)m_List.Flink)->m_RouterList.GetAddress(
  749. // lpdwIndex,
  750. // lpbAddress,
  751. // lpdwAddressLength
  752. // );
  753. //} else {
  754. found = FALSE;
  755. //}
  756. DEBUG_LEAVE(found);
  757. return found;
  758. }
  759. BOOL
  760. CIpConfig::GetDnsAddress(
  761. IN LPBYTE lpbInterfaceAddress OPTIONAL,
  762. IN DWORD dwInterfaceAddressLength,
  763. IN OUT LPDWORD lpdwIndex,
  764. OUT LPBYTE lpbAddress,
  765. IN OUT LPDWORD lpdwAddressLength
  766. )
  767. /*++
  768. Routine Description:
  769. Returns the *lpdwIndex'th DNS address belonging to the interface
  770. corresponding to the address in lpbInterfaceAddress
  771. Arguments:
  772. lpbInterfaceAddress - pointer to interface address
  773. dwInterfaceAddressLength - length of interface address
  774. lpdwIndex - index of DNS address to return
  775. lpbAddress - returned DNS address
  776. lpdwAddressLength - length of DNS address
  777. Return Value:
  778. BOOL
  779. TRUE - *lpdwIndex'th DNS address returned for requested interface
  780. FALSE - requested address not returned
  781. --*/
  782. {
  783. DEBUG_ENTER((DBG_SOCKETS,
  784. Bool,
  785. "CIpConfig::GetDnsAddress",
  786. "%#x, %d, %#x [%d], %#x, %#x [%d]",
  787. lpbInterfaceAddress,
  788. dwInterfaceAddressLength,
  789. lpdwIndex,
  790. *lpdwIndex,
  791. lpbAddress,
  792. lpdwAddressLength,
  793. *lpdwAddressLength
  794. ));
  795. //
  796. // for now, we only return the global DNS info
  797. //
  798. INET_ASSERT(lpbInterfaceAddress == NULL);
  799. INET_ASSERT(dwInterfaceAddressLength == sizeof(DWORD));
  800. BOOL found;
  801. if (!m_DnsList.IsEmpty()) {
  802. found = m_DnsList.GetAddress(lpdwIndex,
  803. lpbAddress,
  804. lpdwAddressLength
  805. );
  806. } else {
  807. found = FALSE;
  808. }
  809. DEBUG_LEAVE(found);
  810. return found;
  811. }
  812. BOOL
  813. CIpConfig::IsKnownIpAddress(
  814. IN LPBYTE lpbInterfaceAddress OPTIONAL,
  815. IN DWORD dwInterfaceAddressLength,
  816. IN LPBYTE lpbAddress,
  817. IN DWORD dwAddressLength
  818. )
  819. /*++
  820. Routine Description:
  821. Return TRUE if lpbAddress is a known interface address
  822. Arguments:
  823. lpbInterfaceAddress - pointer to interface address
  824. dwInterfaceAddressLength - length of interface address
  825. lpbAddress - pointer to address to check
  826. dwAddressLength - length of address
  827. Return Value:
  828. BOOL
  829. --*/
  830. {
  831. DEBUG_ENTER((DBG_SOCKETS,
  832. Bool,
  833. "CIpConfig::IsKnownIpAddress",
  834. "%#x, %d, %#x, %d",
  835. lpbInterfaceAddress,
  836. dwInterfaceAddressLength,
  837. lpbAddress,
  838. dwAddressLength
  839. ));
  840. BOOL found = FALSE;
  841. for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
  842. pEntry != (CAdapterInterface *)&m_List.Flink;
  843. pEntry = (CAdapterInterface *)pEntry->m_List.Flink) {
  844. if (pEntry->FindIpAddress(*(LPDWORD)lpbAddress)) {
  845. found = TRUE;
  846. break;
  847. }
  848. }
  849. DEBUG_LEAVE(found);
  850. return found;
  851. }
  852. BOOL
  853. CIpConfig::Refresh(
  854. VOID
  855. )
  856. /*++
  857. Routine Description:
  858. Refreshes the interface information - re-reads the interfaces and IP
  859. addresses
  860. Arguments:
  861. None.
  862. Return Value:
  863. BOOL
  864. TRUE - interfaces or IP address changed
  865. FALSE - nothing changed
  866. --*/
  867. {
  868. DEBUG_ENTER((DBG_SOCKETS,
  869. Bool,
  870. "CIpConfig::Refresh",
  871. NULL
  872. ));
  873. BOOL bChanged;
  874. GetAdapterList(&bChanged);
  875. if (bChanged) {
  876. //dprintf("flushing hostent cache\n");
  877. // FlushHostentCache();
  878. }
  879. DEBUG_LEAVE(bChanged);
  880. return bChanged;
  881. }
  882. //
  883. // private CIpConfig methods
  884. //
  885. PRIVATE
  886. BOOL
  887. CIpConfig::GetAdapterList(
  888. OUT LPBOOL lpbChanged
  889. )
  890. /*++
  891. Routine Description:
  892. Builds a list of interfaces corresponding to physical and logical adapters,
  893. Uses Win'95 and NT 4 private VxD driver/registry entry points to get this data.
  894. Arguments:
  895. lpbChanged - if present, returns interface changed state
  896. Return Value:
  897. BOOL
  898. TRUE - successfully built list
  899. FALSE - failed to allocate memory or failure talking to TCP/IP
  900. --*/
  901. {
  902. DEBUG_ENTER((DBG_SOCKETS,
  903. Bool,
  904. "CIpConfig::GetAdapterList",
  905. "%#x",
  906. lpbChanged
  907. ));
  908. TCP_REQUEST_QUERY_INFORMATION_EX req;
  909. TDIObjectID id;
  910. UINT numberOfEntities;
  911. TDIEntityID* pEntity;
  912. TDIEntityID* entityList = NULL;
  913. IPRouteEntry* routeTable = NULL;
  914. LPVOID buffer = NULL;
  915. DWORD status;
  916. DWORD inputLen;
  917. DWORD outputLen;
  918. BOOL ok = FALSE;
  919. UINT i; // major loop index
  920. UINT j; // minor loop index
  921. BOOL bChanged = FALSE;
  922. //
  923. // default is interfaces unchanged
  924. //
  925. if (lpbChanged) {
  926. *lpbChanged = FALSE;
  927. }
  928. //
  929. // On NT 5 we override and use a different method for
  930. // getting network settings.
  931. //
  932. if ( GlobalPlatformVersion5 ) {
  933. return GetAdapterListOnNT5();
  934. }
  935. //
  936. // get the list of entities supported by TCP/IP then make 2 passes on the
  937. // list. Pass 1 scans for IF_ENTITY's (interface entities perhaps?) which
  938. // describe adapter instances (physical and virtual). Once we have our list
  939. // of adapters, on pass 2 we look for CL_NL_ENTITY's (connection-less
  940. // network layer entities peut-etre?) which will give us the list of IP
  941. // addresses for the adapters we found in pass 1
  942. //
  943. numberOfEntities = GetEntityList(&entityList);
  944. if (numberOfEntities == 0) {
  945. INET_ASSERT(entityList == NULL);
  946. DEBUG_PRINT(UTIL,
  947. ERROR,
  948. ("GetAdapterList: failed to get entity list\n"
  949. ));
  950. goto quit;
  951. }
  952. //
  953. // first off, mark all the current interfaces (if any), including current
  954. // IP addresses, as not found
  955. //
  956. SetNotFound();
  957. //
  958. // pass 1
  959. //
  960. for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
  961. DEBUG_PRINT(UTIL,
  962. INFO,
  963. ("Pass 1: Entity %#x (%s) Instance #%d\n",
  964. pEntity->tei_entity,
  965. InternetMapEntity(pEntity->tei_entity),
  966. pEntity->tei_instance
  967. ));
  968. if (pEntity->tei_entity != IF_ENTITY) {
  969. DEBUG_PRINT(UTIL,
  970. INFO,
  971. ("Entity %#x (%s) Instance #%d not IF_ENTITY - skipping\n",
  972. pEntity->tei_entity,
  973. InternetMapEntity(pEntity->tei_entity),
  974. pEntity->tei_instance
  975. ));
  976. continue;
  977. }
  978. //
  979. // IF_ENTITY: this entity/instance describes an adapter
  980. //
  981. DWORD isMib;
  982. BYTE info[sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1];
  983. IFEntry* pIfEntry = (IFEntry*)info;
  984. int len;
  985. //
  986. // find out if this entity supports MIB requests
  987. //
  988. memset(&req, 0, sizeof(req));
  989. id.toi_entity = *pEntity;
  990. id.toi_class = INFO_CLASS_GENERIC;
  991. id.toi_type = INFO_TYPE_PROVIDER;
  992. id.toi_id = ENTITY_TYPE_ID;
  993. req.ID = id;
  994. inputLen = sizeof(req);
  995. outputLen = sizeof(isMib);
  996. status = WsControl(IPPROTO_TCP,
  997. WSCNTL_TCPIP_QUERY_INFO,
  998. (LPVOID)&req,
  999. &inputLen,
  1000. (LPVOID)&isMib,
  1001. &outputLen
  1002. );
  1003. //
  1004. // BUGBUG - this returns 0 as outputLen
  1005. //
  1006. // if ((status != TDI_SUCCESS) || (outputLen != sizeof(isMib))) {
  1007. if (status != TDI_SUCCESS) {
  1008. //
  1009. // unexpected results - bail out
  1010. //
  1011. DEBUG_PRINT(UTIL,
  1012. ERROR,
  1013. ("WsControl(ENTITY_TYPE_ID): status = %d, outputLen = %d\n",
  1014. status,
  1015. outputLen
  1016. ));
  1017. goto error_exit;
  1018. }
  1019. if (isMib != IF_MIB) {
  1020. //
  1021. // entity doesn't support MIB requests - try another
  1022. //
  1023. DEBUG_PRINT(UTIL,
  1024. WARNING,
  1025. ("Entity %#x, Instance #%d doesn't support MIB (%#x)\n",
  1026. id.toi_entity.tei_entity,
  1027. id.toi_entity.tei_instance,
  1028. isMib
  1029. ));
  1030. continue;
  1031. }
  1032. //
  1033. // MIB requests supported - query the adapter info
  1034. //
  1035. id.toi_class = INFO_CLASS_PROTOCOL;
  1036. id.toi_id = IF_MIB_STATS_ID;
  1037. memset(&req, 0, sizeof(req));
  1038. req.ID = id;
  1039. inputLen = sizeof(req);
  1040. outputLen = sizeof(info);
  1041. status = WsControl(IPPROTO_TCP,
  1042. WSCNTL_TCPIP_QUERY_INFO,
  1043. (LPVOID)&req,
  1044. &inputLen,
  1045. (LPVOID)&info,
  1046. &outputLen
  1047. );
  1048. if (status != TDI_SUCCESS) {
  1049. //
  1050. // unexpected results - bail out
  1051. //
  1052. DEBUG_PRINT(UTIL,
  1053. ERROR,
  1054. ("WsControl(IF_MIB_STATS_ID) returns %d\n",
  1055. status
  1056. ));
  1057. goto error_exit;
  1058. }
  1059. //
  1060. // we only want physical adapters
  1061. //
  1062. if (!IS_INTERESTING_ADAPTER(pIfEntry)) {
  1063. DEBUG_PRINT(UTIL,
  1064. INFO,
  1065. ("ignoring adapter #%d [%s]\n",
  1066. pIfEntry->if_index,
  1067. InternetMapInterface(pIfEntry->if_type)
  1068. ));
  1069. continue;
  1070. }
  1071. //
  1072. // got this adapter info ok. Find or create an interface object and fill
  1073. // in what we can
  1074. //
  1075. CAdapterInterface * pInterface;
  1076. len = min(MAX_ADAPTER_ADDRESS_LENGTH, (size_t)pIfEntry->if_physaddrlen);
  1077. pInterface = FindOrCreateInterface(pIfEntry->if_index,
  1078. pIfEntry->if_type,
  1079. pIfEntry->if_speed,
  1080. (LPSTR)pIfEntry->if_descr,
  1081. pIfEntry->if_descrlen,
  1082. (LPBYTE)pIfEntry->if_physaddr,
  1083. (DWORD) len
  1084. );
  1085. if (pInterface == NULL) {
  1086. DEBUG_PRINT(UTIL,
  1087. ERROR,
  1088. ("failed to allocate memory for CAdapterInterface\n"
  1089. ));
  1090. goto error_exit;
  1091. }
  1092. }
  1093. //
  1094. // pass 2
  1095. //
  1096. for (i = 0, pEntity = entityList; i < numberOfEntities; ++i, ++pEntity) {
  1097. DEBUG_PRINT(UTIL,
  1098. INFO,
  1099. ("Pass 2: Entity %#x (%s) Instance %d\n",
  1100. pEntity->tei_entity,
  1101. InternetMapEntity(pEntity->tei_entity),
  1102. pEntity->tei_instance
  1103. ));
  1104. if (pEntity->tei_entity != CL_NL_ENTITY) {
  1105. DEBUG_PRINT(UTIL,
  1106. INFO,
  1107. ("Entity %#x (%s) Instance %d - not CL_NL_ENTITY - skipping\n",
  1108. pEntity->tei_entity,
  1109. InternetMapEntity(pEntity->tei_entity),
  1110. pEntity->tei_instance
  1111. ));
  1112. continue;
  1113. }
  1114. IPSNMPInfo info;
  1115. DWORD type;
  1116. //
  1117. // first off, see if this network layer entity supports IP
  1118. //
  1119. memset(&req, 0, sizeof(req));
  1120. id.toi_entity = *pEntity;
  1121. id.toi_class = INFO_CLASS_GENERIC;
  1122. id.toi_type = INFO_TYPE_PROVIDER;
  1123. id.toi_id = ENTITY_TYPE_ID;
  1124. req.ID = id;
  1125. inputLen = sizeof(req);
  1126. outputLen = sizeof(type);
  1127. status = WsControl(IPPROTO_TCP,
  1128. WSCNTL_TCPIP_QUERY_INFO,
  1129. (LPVOID)&req,
  1130. &inputLen,
  1131. (LPVOID)&type,
  1132. &outputLen
  1133. );
  1134. //
  1135. // BUGBUG - this returns 0 as outputLen
  1136. //
  1137. // if ((status != TDI_SUCCESS) || (outputLen != sizeof(type))) {
  1138. if (status != TDI_SUCCESS) {
  1139. //
  1140. // unexpected results - bail out
  1141. //
  1142. DEBUG_PRINT(UTIL,
  1143. ERROR,
  1144. ("WsControl(ENTITY_TYPE_ID): status = %d, outputLen = %d\n",
  1145. status,
  1146. outputLen
  1147. ));
  1148. goto error_exit;
  1149. }
  1150. if (type != CL_NL_IP) {
  1151. //
  1152. // nope, not IP - try next one
  1153. //
  1154. DEBUG_PRINT(UTIL,
  1155. INFO,
  1156. ("CL_NL_ENTITY #%d not CL_NL_IP - skipping\n",
  1157. pEntity->tei_instance
  1158. ));
  1159. continue;
  1160. }
  1161. //
  1162. // okay, this NL provider supports IP. Let's get them addresses: First
  1163. // we find out how many by getting the SNMP stats and looking at the
  1164. // number of addresses supported by this interface
  1165. //
  1166. memset(&req, 0, sizeof(req));
  1167. id.toi_class = INFO_CLASS_PROTOCOL;
  1168. id.toi_id = IP_MIB_STATS_ID;
  1169. req.ID = id;
  1170. inputLen = sizeof(req);
  1171. outputLen = sizeof(info);
  1172. status = WsControl(IPPROTO_TCP,
  1173. WSCNTL_TCPIP_QUERY_INFO,
  1174. (LPVOID)&req,
  1175. &inputLen,
  1176. (LPVOID)&info,
  1177. &outputLen
  1178. );
  1179. if ((status != TDI_SUCCESS) || (outputLen != sizeof(info))) {
  1180. //
  1181. // unexpected results - bail out
  1182. //
  1183. DEBUG_PRINT(UTIL,
  1184. ERROR,
  1185. ("WsControl(IP_MIB_STATS_ID): status = %d, outputLen = %d\n",
  1186. status,
  1187. outputLen
  1188. ));
  1189. goto error_exit;
  1190. }
  1191. //
  1192. // get the IP addresses & subnet masks
  1193. //
  1194. if (info.ipsi_numaddr != 0) {
  1195. //
  1196. // this interface has some addresses. What are they?
  1197. //
  1198. UINT numberOfAddresses;
  1199. IPAddrEntry* pAddr;
  1200. outputLen = info.ipsi_numaddr * sizeof(IPAddrEntry);
  1201. buffer = (LPVOID)ALLOCATE_MEMORY(LMEM_FIXED, outputLen);
  1202. if (buffer == NULL) {
  1203. //
  1204. // unexpected results - bail out
  1205. //
  1206. DEBUG_PRINT(UTIL,
  1207. ERROR,
  1208. ("failed to allocate %d bytes\n",
  1209. outputLen
  1210. ));
  1211. goto error_exit;
  1212. }
  1213. memset(&req, 0, sizeof(req));
  1214. id.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1215. req.ID = id;
  1216. inputLen = sizeof(req);
  1217. status = WsControl(IPPROTO_TCP,
  1218. WSCNTL_TCPIP_QUERY_INFO,
  1219. (LPVOID)&req,
  1220. &inputLen,
  1221. (LPVOID)buffer,
  1222. &outputLen
  1223. );
  1224. if (status != TDI_SUCCESS) {
  1225. //
  1226. // unexpected results - bail out
  1227. //
  1228. DEBUG_PRINT(UTIL,
  1229. ERROR,
  1230. ("WsControl(IP_MIB_ADDRTABLE_ENTRY_ID): status = %d, outputLen = %d\n",
  1231. status,
  1232. outputLen
  1233. ));
  1234. goto error_exit;
  1235. }
  1236. //
  1237. // now loop through this list of IP addresses, applying them
  1238. // to the correct adapter
  1239. //
  1240. numberOfAddresses = min((UINT)(outputLen / sizeof(IPAddrEntry)),
  1241. (UINT)info.ipsi_numaddr
  1242. );
  1243. DEBUG_PRINT(UTIL,
  1244. INFO,
  1245. ("%d IP addresses\n",
  1246. numberOfAddresses
  1247. ));
  1248. pAddr = (IPAddrEntry *)buffer;
  1249. for (j = 0; j < numberOfAddresses; ++j, ++pAddr) {
  1250. DEBUG_PRINT(UTIL,
  1251. INFO,
  1252. ("IP address %d.%d.%d.%d, index %d, context %d\n",
  1253. ((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
  1254. ((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
  1255. ((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
  1256. ((LPBYTE)&pAddr->iae_addr)[3] & 0xff,
  1257. pAddr->iae_index,
  1258. pAddr->iae_context
  1259. ));
  1260. CAdapterInterface * pInterface = FindInterface(pAddr->iae_index);
  1261. if (pInterface != NULL) {
  1262. CIpAddress * pIpAddress;
  1263. pIpAddress = pInterface->m_IpList.Find(pAddr->iae_addr,
  1264. pAddr->iae_mask
  1265. );
  1266. if (pIpAddress == NULL) {
  1267. pInterface->m_IpList.Add(pAddr->iae_addr,
  1268. pAddr->iae_mask,
  1269. pAddr->iae_context
  1270. );
  1271. //
  1272. // added an address - interface is changed
  1273. //
  1274. //dprintf("adding IP address %d.%d.%d.%d - changed\n",
  1275. // ((LPBYTE)&pAddr->iae_addr)[0] & 0xff,
  1276. // ((LPBYTE)&pAddr->iae_addr)[1] & 0xff,
  1277. // ((LPBYTE)&pAddr->iae_addr)[2] & 0xff,
  1278. // ((LPBYTE)&pAddr->iae_addr)[3] & 0xff
  1279. // );
  1280. bChanged = TRUE;
  1281. } else {
  1282. INET_ASSERT(pAddr->iae_context == pIpAddress->Context());
  1283. pIpAddress->SetFound(TRUE);
  1284. }
  1285. }
  1286. }
  1287. INET_ASSERT(buffer);
  1288. FREE_MEMORY(buffer);
  1289. buffer = NULL;
  1290. }
  1291. //
  1292. // get the gateway server IP address(es)
  1293. //
  1294. //
  1295. // We don't need this information any more
  1296. //
  1297. #if 0
  1298. if (info.ipsi_numroutes != 0) {
  1299. IPRouteEntry* pRoute;
  1300. memset(&req, 0, sizeof(req));
  1301. id.toi_id = IP_MIB_RTTABLE_ENTRY_ID;
  1302. req.ID = id;
  1303. inputLen = sizeof(req);
  1304. //
  1305. // Warning: platform specifics; Win95 structure size is different
  1306. // than NT 4.0
  1307. //
  1308. //
  1309. // BUGBUG - this will probably have to be checked for version # on
  1310. // Memphis
  1311. //
  1312. int structLength = (GlobalPlatformType == PLATFORM_TYPE_WINNT)
  1313. ? sizeof(IPRouteEntry) : sizeof(IPRouteEntry95);
  1314. outputLen = structLength * info.ipsi_numroutes;
  1315. //
  1316. // the route table may have grown since we got the SNMP stats
  1317. //
  1318. for (j = 0; j < 4; ++j) {
  1319. DWORD previousOutputLen = outputLen;
  1320. routeTable = (IPRouteEntry*)ResizeBuffer(routeTable,
  1321. outputLen,
  1322. FALSE
  1323. );
  1324. if (routeTable == NULL) {
  1325. goto error_exit;
  1326. }
  1327. status = WsControl(IPPROTO_TCP,
  1328. WSCNTL_TCPIP_QUERY_INFO,
  1329. (LPVOID)&req,
  1330. &inputLen,
  1331. (LPVOID)routeTable,
  1332. &outputLen
  1333. );
  1334. if (status != TDI_SUCCESS) {
  1335. //
  1336. // unexpected results - bail out
  1337. //
  1338. DEBUG_PRINT(UTIL,
  1339. ERROR,
  1340. ("WsControl(IP_MIB_RTTABLE_ENTRY_ID): status = %d, outputLen = %d\n",
  1341. status,
  1342. outputLen
  1343. ));
  1344. goto error_exit;
  1345. }
  1346. if (outputLen <= previousOutputLen) {
  1347. break;
  1348. }
  1349. }
  1350. UINT numberOfRoutes = (UINT)(outputLen / sizeof(IPRouteEntry));
  1351. for (j = 0, pRoute = routeTable; j < numberOfRoutes; ++j) {
  1352. //
  1353. // the gateway address has a destination of 0.0.0.0
  1354. //
  1355. if (pRoute->ire_dest == INADDR_ANY) {
  1356. CAdapterInterface * pInterface;
  1357. pInterface = FindInterface(pRoute->ire_index);
  1358. if (pInterface != NULL) {
  1359. DEBUG_PRINT(UTIL,
  1360. INFO,
  1361. ("router address %d.%d.%d.%d, index %d\n",
  1362. ((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
  1363. ((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
  1364. ((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
  1365. ((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff,
  1366. pRoute->ire_index
  1367. ));
  1368. CIpAddress * pIpAddress;
  1369. pIpAddress = pInterface->m_RouterList.Find(pRoute->ire_nexthop);
  1370. if (pIpAddress == NULL) {
  1371. pInterface->m_RouterList.Add(pRoute->ire_nexthop);
  1372. //
  1373. // added a router address - interface is changed
  1374. //
  1375. //dprintf("adding router address %d.%d.%d.%d - changed\n",
  1376. // ((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
  1377. // ((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
  1378. // ((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
  1379. // ((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff
  1380. // );
  1381. bChanged = TRUE;
  1382. } else {
  1383. pIpAddress->SetFound(TRUE);
  1384. }
  1385. }
  1386. } else {
  1387. DEBUG_PRINT(UTIL,
  1388. INFO,
  1389. ("rejecting router address %d.%d.%d.%d, index %d\n",
  1390. ((LPBYTE)&pRoute->ire_nexthop)[0] & 0xff,
  1391. ((LPBYTE)&pRoute->ire_nexthop)[1] & 0xff,
  1392. ((LPBYTE)&pRoute->ire_nexthop)[2] & 0xff,
  1393. ((LPBYTE)&pRoute->ire_nexthop)[3] & 0xff,
  1394. pRoute->ire_index
  1395. ));
  1396. }
  1397. pRoute = (IPRouteEntry *)((LPBYTE)pRoute + structLength);
  1398. }
  1399. INET_ASSERT(routeTable);
  1400. FREE_MEMORY(routeTable);
  1401. routeTable = NULL;
  1402. }
  1403. #endif // if 0, disable gathering of router addresses
  1404. }
  1405. //
  1406. // add the DNS servers, read from registry or DHCP depending on platform.
  1407. // Even if we don't get any DNS servers, we deem that this function has
  1408. // succeeded
  1409. //
  1410. char dnsBuffer[1024]; // arbitrary (how many DNS entries?)
  1411. UINT error;
  1412. error = SockGetSingleValue(CONFIG_NAME_SERVER,
  1413. (LPBYTE)dnsBuffer,
  1414. sizeof(dnsBuffer)
  1415. );
  1416. if (error == ERROR_SUCCESS) {
  1417. //m_DnsList.Clear();
  1418. char ipString[4 * 4];
  1419. LPSTR p = dnsBuffer;
  1420. DWORD buflen = (DWORD)lstrlen(dnsBuffer);
  1421. do {
  1422. if (SkipWhitespace(&p, &buflen)) {
  1423. int i = 0;
  1424. while ((*p != '\0')
  1425. && (*p != ',')
  1426. && (buflen != 0)
  1427. && (i < sizeof(ipString))
  1428. && !isspace(*p)) {
  1429. ipString[i++] = *p++;
  1430. --buflen;
  1431. }
  1432. ipString[i] = '\0';
  1433. DWORD ipAddress = _I_inet_addr(ipString);
  1434. if (IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress)) {
  1435. CIpAddress * pIpAddress;
  1436. pIpAddress = m_DnsList.Find(ipAddress);
  1437. if (pIpAddress == NULL) {
  1438. m_DnsList.Add(ipAddress);
  1439. //
  1440. // added a DNS address - interface is changed
  1441. //
  1442. //dprintf("adding DNS address %d.%d.%d.%d - changed\n",
  1443. // ((LPBYTE)&ipAddress)[0] & 0xff,
  1444. // ((LPBYTE)&ipAddress)[1] & 0xff,
  1445. // ((LPBYTE)&ipAddress)[2] & 0xff,
  1446. // ((LPBYTE)&ipAddress)[3] & 0xff
  1447. // );
  1448. bChanged = TRUE;
  1449. } else {
  1450. pIpAddress->SetFound(TRUE);
  1451. }
  1452. }
  1453. while ((*p == ',') && (buflen != 0)) {
  1454. ++p;
  1455. --buflen;
  1456. }
  1457. } else {
  1458. break;
  1459. }
  1460. } while (TRUE);
  1461. }
  1462. //
  1463. // Refresh registry settings of DHCP server stuff
  1464. // and figure out what DHCP server we have
  1465. //
  1466. GetAdapterInfo();
  1467. //
  1468. // throw out any adapter interfaces which were not found this time. This may
  1469. // happen if we support PnP devices that are unplugged
  1470. //
  1471. BOOL bThrownOut;
  1472. bThrownOut = ThrowOutUnfoundEntries();
  1473. if (!bChanged) {
  1474. bChanged = bThrownOut;
  1475. }
  1476. INET_ASSERT(entityList != NULL);
  1477. FREE_MEMORY(entityList);
  1478. ok = TRUE;
  1479. //
  1480. // return the change state of the interfaces, if required
  1481. //
  1482. if (lpbChanged) {
  1483. *lpbChanged = bChanged;
  1484. }
  1485. quit:
  1486. if (routeTable != NULL) {
  1487. FREE_MEMORY(routeTable);
  1488. }
  1489. if (buffer != NULL) {
  1490. FREE_MEMORY(buffer);
  1491. }
  1492. DEBUG_LEAVE(ok);
  1493. return ok;
  1494. error_exit:
  1495. //
  1496. // here because of an error. Throw out all interfaces
  1497. //
  1498. SetNotFound();
  1499. ThrowOutUnfoundEntries();
  1500. INET_ASSERT(!ok);
  1501. goto quit;
  1502. }
  1503. PRIVATE
  1504. BOOL
  1505. CIpConfig::GetAdapterListOnNT5(
  1506. OUT LPBOOL lpbChanged
  1507. )
  1508. /*++
  1509. Routine Description:
  1510. Builds a list of interfaces corresponding to physical and logical adapters
  1511. using the new NT 5 and Win98 APIs.
  1512. BUGBUG [arthurbi] - turned off for Win '98 because we were getting erronous
  1513. data values from the APIs (we currently fall back to old Win'95 code on '98).
  1514. Arguments:
  1515. lpbChanged - if present, returns interface changed state
  1516. Return Value:
  1517. BOOL
  1518. TRUE - successfully built list
  1519. FALSE - failed to allocate memory or failure talking to TCP/IP
  1520. --*/
  1521. {
  1522. DEBUG_ENTER((DBG_SOCKETS,
  1523. Bool,
  1524. "CIpConfig::GetAdapterListOnNT5",
  1525. "%#x",
  1526. lpbChanged
  1527. ));
  1528. DWORD status;
  1529. DWORD inputLen;
  1530. DWORD outputLen;
  1531. BOOL ok = FALSE;
  1532. UINT i; // major loop index
  1533. UINT j; // minor loop index
  1534. BOOL bChanged = FALSE;
  1535. int len;
  1536. IP_ADAPTER_INFO AdapterInfo[15];
  1537. PIP_ADAPTER_INFO pAdapterInfo;
  1538. DWORD dwError;
  1539. ULONG uSize;
  1540. //
  1541. // Load the IPHLPAPI DLL, cause we need this function find adapter info on NT 5/Win98
  1542. //
  1543. if ( _I_GetAdaptersInfo == NULL )
  1544. {
  1545. DEBUG_PRINT(UTIL,
  1546. ERROR,
  1547. ("GetAdapterListOnNT5: IPHLPAPI dll could not be found with correct entry point\n"
  1548. ));
  1549. goto quit;
  1550. }
  1551. //
  1552. // get the list of adapters supported by TCP/IP
  1553. //
  1554. uSize = sizeof(IP_ADAPTER_INFO)*15;
  1555. pAdapterInfo = AdapterInfo;
  1556. dwError = _I_GetAdaptersInfo(pAdapterInfo, &uSize);
  1557. if ( dwError != ERROR_SUCCESS )
  1558. {
  1559. //
  1560. // BUGBUG [arthurbi] handle the case where we have more than 15 adapters,
  1561. // need to be brave and start allocating memory for a change.
  1562. //
  1563. DEBUG_PRINT(UTIL,
  1564. ERROR,
  1565. ("GetAdapterListOnNT5: failed to get adapters list\n"
  1566. ));
  1567. goto quit;
  1568. }
  1569. //
  1570. // first off, mark all the current interfaces (if any), including current
  1571. // IP addresses, as not found
  1572. //
  1573. SetNotFound();
  1574. //
  1575. // pass 1
  1576. //
  1577. for (pAdapterInfo = AdapterInfo; pAdapterInfo; pAdapterInfo = pAdapterInfo->Next)
  1578. {
  1579. DEBUG_PRINT(UTIL,
  1580. INFO,
  1581. ("Adapter Pass: [#%u] Adapter name=%s, description=%s\n",
  1582. pAdapterInfo->Index,
  1583. pAdapterInfo->AdapterName,
  1584. pAdapterInfo->Description
  1585. ));
  1586. //
  1587. // we only want physical adapters
  1588. //
  1589. if (!IS_INTERESTING_ADAPTER_NT5(pAdapterInfo)) {
  1590. DEBUG_PRINT(UTIL,
  1591. INFO,
  1592. ("ignoring adapter #%u [%s]\n",
  1593. pAdapterInfo->Index,
  1594. InternetMapInterfaceOnNT5(pAdapterInfo->Type)
  1595. ));
  1596. continue;
  1597. }
  1598. //
  1599. // got this adapter info ok. Find or create an interface object and fill
  1600. // in what we can
  1601. //
  1602. CAdapterInterface * pInterface;
  1603. len = min(MAX_ADAPTER_ADDRESS_LENGTH, (size_t)pAdapterInfo->AddressLength);
  1604. pInterface = FindOrCreateInterface(pAdapterInfo->Index,
  1605. pAdapterInfo->Type,
  1606. 0, // speed
  1607. pAdapterInfo->Description,
  1608. lstrlen(pAdapterInfo->Description),
  1609. pAdapterInfo->Address,
  1610. (DWORD) len
  1611. );
  1612. if (pInterface == NULL) {
  1613. DEBUG_PRINT(UTIL,
  1614. ERROR,
  1615. ("failed to allocate memory for CAdapterInterface\n"
  1616. ));
  1617. goto error_exit;
  1618. }
  1619. //
  1620. // Update the Adapter Name, this is the critical glue to make the new NT 5 DHCP Apis work,
  1621. // as they need this Adapter name as an ID to work.
  1622. //
  1623. if ( pInterface->GetAdapterName() == NULL ) {
  1624. pInterface->SetAdapterName(pAdapterInfo->AdapterName);
  1625. } else {
  1626. INET_ASSERT(lstrcmpi(pInterface->GetAdapterName(), pAdapterInfo->AdapterName) == 0 );
  1627. }
  1628. //
  1629. // Update the IP address found in the structure, as we're not getting anything back with this filled in.
  1630. //
  1631. if ( pAdapterInfo->CurrentIpAddress == NULL )
  1632. {
  1633. pAdapterInfo->CurrentIpAddress = &pAdapterInfo->IpAddressList;
  1634. }
  1635. else
  1636. {
  1637. INET_ASSERT(FALSE); // want to know about this case.
  1638. }
  1639. //
  1640. // Gather the IP addresses from the structure, doing all the necessary,
  1641. // IP string to network-ordered DWORD thingie usable for winsock.
  1642. //
  1643. // BUGBUG [arthurbi] do we really need to do this anymore? As the
  1644. // the new NT 5 APIs can handle themselves without IP addresses...
  1645. //
  1646. if ( pAdapterInfo->CurrentIpAddress->IpAddress.String &&
  1647. pAdapterInfo->CurrentIpAddress->IpMask.String )
  1648. {
  1649. DWORD dwAddress = _I_inet_addr(pAdapterInfo->CurrentIpAddress->IpAddress.String);
  1650. DWORD dwMask = _I_inet_addr(pAdapterInfo->CurrentIpAddress->IpMask.String);
  1651. DWORD dwContext = pAdapterInfo->CurrentIpAddress->Context;
  1652. if ( dwAddress != INADDR_NONE &&
  1653. dwMask != INADDR_NONE )
  1654. {
  1655. DEBUG_PRINT(UTIL,
  1656. INFO,
  1657. ("IP address %d.%d.%d.%d, index %d, context %d\n",
  1658. ((LPBYTE)&dwAddress)[0] & 0xff,
  1659. ((LPBYTE)&dwAddress)[1] & 0xff,
  1660. ((LPBYTE)&dwAddress)[2] & 0xff,
  1661. ((LPBYTE)&dwAddress)[3] & 0xff,
  1662. pAdapterInfo->Index,
  1663. dwContext
  1664. ));
  1665. INET_ASSERT(pInterface != NULL);
  1666. CIpAddress * pIpAddress;
  1667. pIpAddress = pInterface->m_IpList.Find(dwAddress,
  1668. dwMask
  1669. );
  1670. if (pIpAddress == NULL) {
  1671. pInterface->m_IpList.Add(dwAddress,
  1672. dwMask,
  1673. dwContext
  1674. );
  1675. //
  1676. // added an address - interface is changed
  1677. //
  1678. bChanged = TRUE;
  1679. } else {
  1680. INET_ASSERT(dwContext == pIpAddress->Context());
  1681. pIpAddress->SetFound(TRUE);
  1682. }
  1683. }
  1684. }
  1685. //
  1686. // Gather DHCP server addresses to use, once again do we need this info on NT 5?
  1687. //
  1688. if ( pAdapterInfo->DhcpEnabled )
  1689. {
  1690. PIP_ADDR_STRING pDhcpServer;
  1691. INET_ASSERT(pInterface != NULL);
  1692. for ( pDhcpServer = &pAdapterInfo->DhcpServer; pDhcpServer; pDhcpServer = pDhcpServer->Next )
  1693. {
  1694. CIpAddress * pDhcpAddress;
  1695. DWORD dwAddress = _I_inet_addr(pDhcpServer->IpAddress.String);
  1696. DWORD dwMask = _I_inet_addr(pDhcpServer->IpMask.String);
  1697. DWORD dwContext = pDhcpServer->Context;
  1698. if ( dwAddress != INADDR_NONE )
  1699. {
  1700. CIpAddress * pIpAddress;
  1701. pInterface->SetDhcp();
  1702. pIpAddress = pInterface->m_DhcpList.Find(dwAddress,
  1703. dwMask
  1704. );
  1705. if (pIpAddress == NULL)
  1706. {
  1707. pInterface->m_DhcpList.Add(dwAddress,
  1708. dwMask,
  1709. dwContext
  1710. );
  1711. //
  1712. // added an address - interface is changed
  1713. //
  1714. bChanged = TRUE;
  1715. } else {
  1716. INET_ASSERT(dwContext == pIpAddress->Context());
  1717. pIpAddress->SetFound(TRUE);
  1718. }
  1719. }
  1720. }
  1721. }
  1722. }
  1723. //
  1724. // add the DNS servers, read from registry or DHCP depending on platform.
  1725. // Even if we don't get any DNS servers, we deem that this function has
  1726. // succeeded
  1727. //
  1728. char dnsBuffer[1024]; // arbitrary (how many DNS entries?)
  1729. UINT error;
  1730. error = SockGetSingleValue(CONFIG_NAME_SERVER,
  1731. (LPBYTE)dnsBuffer,
  1732. sizeof(dnsBuffer)
  1733. );
  1734. if (error == ERROR_SUCCESS) {
  1735. //m_DnsList.Clear();
  1736. char ipString[4 * 4];
  1737. LPSTR p = dnsBuffer;
  1738. DWORD buflen = (DWORD)lstrlen(dnsBuffer);
  1739. do {
  1740. if (SkipWhitespace(&p, &buflen)) {
  1741. int i = 0;
  1742. while ((*p != '\0')
  1743. && (*p != ',')
  1744. && (buflen != 0)
  1745. && (i < sizeof(ipString))
  1746. && !isspace(*p)) {
  1747. ipString[i++] = *p++;
  1748. --buflen;
  1749. }
  1750. ipString[i] = '\0';
  1751. DWORD ipAddress = _I_inet_addr(ipString);
  1752. if (IS_VALID_NON_LOOPBACK_IP_ADDRESS(ipAddress)) {
  1753. CIpAddress * pIpAddress;
  1754. pIpAddress = m_DnsList.Find(ipAddress);
  1755. if (pIpAddress == NULL) {
  1756. m_DnsList.Add(ipAddress);
  1757. //
  1758. // added a DNS address - interface is changed
  1759. //
  1760. bChanged = TRUE;
  1761. } else {
  1762. pIpAddress->SetFound(TRUE);
  1763. }
  1764. }
  1765. while ((*p == ',') && (buflen != 0)) {
  1766. ++p;
  1767. --buflen;
  1768. }
  1769. } else {
  1770. break;
  1771. }
  1772. } while (TRUE);
  1773. }
  1774. //
  1775. // throw out any adapter interfaces which were not found this time. This may
  1776. // happen if we support PnP devices that are unplugged
  1777. //
  1778. // Do we need to still do this ???
  1779. //
  1780. BOOL bThrownOut;
  1781. bThrownOut = ThrowOutUnfoundEntries();
  1782. if (!bChanged) {
  1783. bChanged = bThrownOut;
  1784. }
  1785. ok = TRUE;
  1786. //
  1787. // return the change state of the interfaces, if required
  1788. //
  1789. if (lpbChanged) {
  1790. *lpbChanged = bChanged;
  1791. }
  1792. quit:
  1793. DEBUG_LEAVE(ok);
  1794. return ok;
  1795. error_exit:
  1796. //
  1797. // here because of an error. Throw out all interfaces
  1798. //
  1799. SetNotFound();
  1800. ThrowOutUnfoundEntries();
  1801. INET_ASSERT(!ok);
  1802. goto quit;
  1803. }
  1804. BOOL
  1805. CIpConfig::DoInformsOnEachInterface(
  1806. IN OUT LPSTR lpszAutoProxyUrl,
  1807. IN DWORD dwAutoProxyUrlLength
  1808. )
  1809. {
  1810. for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
  1811. pEntry != (CAdapterInterface *)&m_List.Flink;
  1812. pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
  1813. {
  1814. if ( pEntry->IsDhcp() )
  1815. {
  1816. BOOL fSuccess;
  1817. if ( GlobalPlatformVersion5 )
  1818. {
  1819. fSuccess = pEntry->DhcpDoInformNT5(
  1820. lpszAutoProxyUrl,
  1821. dwAutoProxyUrlLength
  1822. );
  1823. }
  1824. else
  1825. {
  1826. fSuccess = DhcpDoInform( // send an inform packet if necessary
  1827. pEntry,
  1828. FALSE,
  1829. lpszAutoProxyUrl,
  1830. dwAutoProxyUrlLength
  1831. );
  1832. }
  1833. if ( fSuccess ) {
  1834. return TRUE;
  1835. }
  1836. }
  1837. }
  1838. return FALSE;
  1839. }
  1840. /*******************************************************************************
  1841. *
  1842. * GetAdapterInfo
  1843. *
  1844. * Gets a list of all adapters to which TCP/IP is bound and reads the per-
  1845. * adapter information that we want to display. Most of the information now
  1846. * comes from the TCP/IP stack itself. In order to keep the 'short' names that
  1847. * exist in the registry to refer to the individual adapters, we read the names
  1848. * from the registry then match them to the adapters returned by TCP/IP by
  1849. * matching the IPInterfaceContext value with the adapter which owns the IP
  1850. * address with that context value
  1851. *
  1852. * ENTRY nothing
  1853. *
  1854. * EXIT nothing
  1855. *
  1856. * RETURNS pointer to linked list of ADAPTER_INFO structures
  1857. *
  1858. * ASSUMES
  1859. *
  1860. ******************************************************************************/
  1861. VOID
  1862. CIpConfig::GetAdapterInfo()
  1863. {
  1864. LPSTR* boundAdapterNames = NULL;
  1865. DWORD err = ERROR_SUCCESS;
  1866. if (GlobalPlatformType == PLATFORM_TYPE_WINNT)
  1867. {
  1868. if ( ServicesKey == NULL )
  1869. {
  1870. err = REGOPENKEY(HKEY_LOCAL_MACHINE,
  1871. SERVICES_KEY_NAME,
  1872. &ServicesKey
  1873. );
  1874. }
  1875. if ( err == ERROR_SUCCESS && TcpipLinkageKey == NULL )
  1876. {
  1877. err = REGOPENKEY(ServicesKey,
  1878. "Tcpip\\Linkage",
  1879. //"Tcpip\\Parameters\\Interfaces",
  1880. &TcpipLinkageKey
  1881. );
  1882. }
  1883. if (err == ERROR_SUCCESS && (boundAdapterNames = GetBoundAdapterList(TcpipLinkageKey)))
  1884. {
  1885. int i;
  1886. //
  1887. // apply the short name to the right adapter info by comparing
  1888. // the IPInterfaceContext value in the adapter\Parameters\Tcpip
  1889. // section with the context values read from the stack for the
  1890. // IP addresses
  1891. //
  1892. for (i = 0; boundAdapterNames[i]; ++i) {
  1893. LPSTR name;
  1894. DWORD context;
  1895. HKEY key;
  1896. BOOL found;
  1897. name = boundAdapterNames[i];
  1898. if (!OpenAdapterKey(KEY_TCP, name, &key)) {
  1899. DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo cannot open %s\n",
  1900. name ));
  1901. goto quit;
  1902. }
  1903. if (!ReadRegistryDword(key,
  1904. "IPInterfaceContext",
  1905. &context
  1906. )) {
  1907. DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo: IPInterfaceContext failed\n"));
  1908. goto quit;
  1909. }
  1910. REGCLOSEKEY(key);
  1911. //
  1912. // now search through the list of adapters, looking for the one
  1913. // that has the IP address with the same context value as that
  1914. // just read. When found, apply the short name to that adapter
  1915. //
  1916. for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
  1917. pEntry != (CAdapterInterface *)&m_List.Flink;
  1918. pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
  1919. {
  1920. if ( pEntry->IsContextInIPAddrList(context) )
  1921. {
  1922. pEntry->SetAdapterName(name);
  1923. GetDhcpServerFromDhcp(pEntry);
  1924. break;
  1925. }
  1926. }
  1927. }
  1928. } else {
  1929. DEBUG_PRINT(UTIL, ERROR, ("GetAdapterInfo failed\n"));
  1930. }
  1931. }
  1932. else
  1933. {
  1934. //
  1935. // Win95: search through the list of adapters, gather DHCP server names
  1936. // for each.
  1937. //
  1938. for (CAdapterInterface * pEntry = (CAdapterInterface *)m_List.Flink;
  1939. pEntry != (CAdapterInterface *)&m_List.Flink;
  1940. pEntry = (CAdapterInterface *)pEntry->m_List.Flink)
  1941. {
  1942. GetDhcpServerFromDhcp(pEntry);
  1943. }
  1944. }
  1945. quit:
  1946. if (boundAdapterNames != NULL )
  1947. {
  1948. FREE_MEMORY(boundAdapterNames);
  1949. }
  1950. return;
  1951. }
  1952. PRIVATE
  1953. DWORD
  1954. CIpConfig::LoadEntryPoints(
  1955. VOID
  1956. )
  1957. /*++
  1958. Routine Description:
  1959. Loads NTDLL.DLL entry points if Windows NT else (if Windows 95) loads
  1960. WsControl from WSOCK32.DLL
  1961. Arguments:
  1962. None.
  1963. Return Value:
  1964. DWORD
  1965. Success - ERROR_SUCCESS
  1966. Failure -
  1967. --*/
  1968. {
  1969. DEBUG_ENTER((DBG_SOCKETS,
  1970. Dword,
  1971. "CIpConfig::LoadEntryPoints",
  1972. NULL
  1973. ));
  1974. DWORD error = ERROR_SUCCESS;
  1975. if (m_Loaded == TRI_STATE_UNKNOWN) {
  1976. error = LoadDllEntryPoints((GlobalPlatformType == PLATFORM_TYPE_WINNT)
  1977. ? &NtDllInfo : &WsControlInfo, 0);
  1978. m_Loaded = (error == ERROR_SUCCESS) ? TRI_STATE_TRUE : TRI_STATE_FALSE;
  1979. }
  1980. if (GlobalPlatformVersion5 && (_I_GetAdaptersInfo == NULL))
  1981. {
  1982. error = LoadDllEntryPoints(&IpHlpApiDllInfo, 0);
  1983. }
  1984. DEBUG_LEAVE(error);
  1985. return error;
  1986. }
  1987. PRIVATE
  1988. DWORD
  1989. CIpConfig::UnloadEntryPoints(
  1990. VOID
  1991. )
  1992. /*++
  1993. Routine Description:
  1994. Unloads NTDLL.DLL if platform is Windows NT
  1995. Arguments:
  1996. None.
  1997. Return Value:
  1998. DWORD
  1999. --*/
  2000. {
  2001. DEBUG_ENTER((DBG_SOCKETS,
  2002. Dword,
  2003. "CIpConfig::UnloadEntryPoints",
  2004. NULL
  2005. ));
  2006. DWORD error = ERROR_SUCCESS;
  2007. if (m_Loaded == TRI_STATE_TRUE) {
  2008. error = UnloadDllEntryPoints((GlobalPlatformType == PLATFORM_TYPE_WINNT)
  2009. ? &NtDllInfo : &WsControlInfo, FALSE);
  2010. if (error == ERROR_SUCCESS) {
  2011. m_Loaded = TRI_STATE_UNKNOWN;
  2012. }
  2013. }
  2014. if (GlobalPlatformVersion5)
  2015. {
  2016. if (_I_GetAdaptersInfo != NULL) {
  2017. error = UnloadDllEntryPoints(&IpHlpApiDllInfo, FALSE);
  2018. }
  2019. if ( _I_DhcpRequestOptions != NULL ) {
  2020. error = UnloadDllEntryPoints(&DhcpcSvcDllInfo, FALSE);
  2021. }
  2022. }
  2023. DEBUG_LEAVE(error);
  2024. return error;
  2025. }
  2026. PRIVATE
  2027. CAdapterInterface *
  2028. CIpConfig::FindOrCreateInterface(
  2029. IN DWORD dwIndex,
  2030. IN DWORD dwType,
  2031. IN DWORD dwSpeed,
  2032. IN LPSTR lpszDescription,
  2033. IN DWORD dwDescriptionLength,
  2034. IN LPBYTE lpPhysicalAddress,
  2035. IN DWORD dwPhysicalAddressLength
  2036. )
  2037. /*++
  2038. Routine Description:
  2039. Returns a pointer to the CAdapterInterface object corresponding to dwIndex.
  2040. If none found in the list, a new entry is created
  2041. Arguments:
  2042. dwIndex - unique interface identifier to find or create
  2043. dwType - type of adapter
  2044. dwSpeed - adapter media speed
  2045. lpszDescription - name of this interface
  2046. dwDescriptionLength - length of the name
  2047. Return Value:
  2048. CAdapterInterface *
  2049. Success - pointer to found or created object
  2050. Failure - NULL
  2051. --*/
  2052. {
  2053. DEBUG_ENTER((DBG_SOCKETS,
  2054. Pointer,
  2055. "CIpConfig::FindOrCreateInterface",
  2056. "%d, %s (%d), %d, %.*q, %d, %x, (%u)",
  2057. dwIndex,
  2058. InternetMapInterface(dwType),
  2059. dwType,
  2060. dwSpeed,
  2061. dwDescriptionLength,
  2062. lpszDescription,
  2063. dwDescriptionLength,
  2064. lpPhysicalAddress,
  2065. dwPhysicalAddressLength
  2066. ));
  2067. CAdapterInterface * pInterface = FindInterface(dwIndex);
  2068. if (pInterface == NULL) {
  2069. pInterface = new CAdapterInterface(dwIndex,
  2070. dwType,
  2071. dwSpeed,
  2072. lpszDescription,
  2073. dwDescriptionLength,
  2074. lpPhysicalAddress,
  2075. dwPhysicalAddressLength
  2076. );
  2077. if (pInterface != NULL) {
  2078. InsertHeadList(&m_List, &pInterface->m_List);
  2079. ++m_dwNumberOfInterfaces;
  2080. }
  2081. }
  2082. DEBUG_LEAVE(pInterface);
  2083. return pInterface;
  2084. }
  2085. PRIVATE
  2086. CAdapterInterface *
  2087. CIpConfig::FindInterface(
  2088. IN DWORD dwIndex
  2089. )
  2090. /*++
  2091. Routine Description:
  2092. Returns a pointer to the CAdapterInterface object corresponding to dwIndex
  2093. Arguments:
  2094. dwIndex - unique interface identifier to find
  2095. Return Value:
  2096. CAdapterInterface *
  2097. Success - pointer to found object
  2098. Failure - NULL
  2099. --*/
  2100. {
  2101. DEBUG_ENTER((DBG_SOCKETS,
  2102. Pointer,
  2103. "CIpConfig::FindInterface",
  2104. "%d",
  2105. dwIndex
  2106. ));
  2107. CAdapterInterface * pInterface = NULL;
  2108. for (PLIST_ENTRY pEntry = m_List.Flink;
  2109. pEntry != (PLIST_ENTRY)&m_List;
  2110. pEntry = pEntry->Flink) {
  2111. if (((CAdapterInterface *)pEntry)->m_dwIndex == dwIndex) {
  2112. ((CAdapterInterface *)pEntry)->SetFound(TRUE);
  2113. //
  2114. // ASSUMES: pEntry == &CAdapterInterface
  2115. //
  2116. pInterface = (CAdapterInterface *)pEntry;
  2117. break;
  2118. }
  2119. }
  2120. DEBUG_LEAVE(pInterface);
  2121. return pInterface;
  2122. }
  2123. PRIVATE
  2124. BOOL
  2125. CIpConfig::ThrowOutUnfoundEntries(
  2126. VOID
  2127. )
  2128. /*++
  2129. Routine Description:
  2130. Throws out (deletes) any entries that are marked not-found
  2131. Arguments:
  2132. None.
  2133. Return Value:
  2134. BOOL
  2135. TRUE - interfaces thrown out
  2136. FALSE - " not " "
  2137. --*/
  2138. {
  2139. DEBUG_ENTER((DBG_SOCKETS,
  2140. Bool,
  2141. "CIpConfig::ThrowOutUnfoundEntries",
  2142. NULL
  2143. ));
  2144. //
  2145. // ASSUMES: CAdapterInterface.m_List.Flink is first element in structure
  2146. //
  2147. PLIST_ENTRY pPrevious = (PLIST_ENTRY)&m_List.Flink;
  2148. PLIST_ENTRY pEntry = m_List.Flink;
  2149. BOOL bThrownOut = FALSE;
  2150. while (pEntry != (PLIST_ENTRY)&m_List) {
  2151. CAdapterInterface * pInterface = (CAdapterInterface *)pEntry;
  2152. if (!pInterface->IsFound()) {
  2153. DEBUG_PRINT(UTIL,
  2154. WARNING,
  2155. ("adapter index %d (%q) not located in list\n",
  2156. pInterface->m_dwIndex,
  2157. pInterface->m_lpszDescription
  2158. ));
  2159. RemoveEntryList(&pInterface->m_List);
  2160. --m_dwNumberOfInterfaces;
  2161. INET_ASSERT((int)m_dwNumberOfInterfaces >= 0);
  2162. delete pInterface;
  2163. bThrownOut = TRUE;
  2164. } else {
  2165. //
  2166. // throw out any IP addresses
  2167. //
  2168. bThrownOut |= pInterface->m_IpList.ThrowOutUnfoundEntries();
  2169. //bThrownOut |= pInterface->m_RouterList.ThrowOutUnfoundEntries();
  2170. //bThrownOut |= pInterface->m_DnsList.ThrowOutUnfoundEntries();
  2171. pPrevious = pEntry;
  2172. }
  2173. pEntry = pPrevious->Flink;
  2174. }
  2175. DEBUG_LEAVE(bThrownOut);
  2176. return bThrownOut;
  2177. }
  2178. //
  2179. // public functions
  2180. //
  2181. DWORD
  2182. WsControl(
  2183. IN DWORD dwProtocol,
  2184. IN DWORD dwRequest,
  2185. IN LPVOID lpInputBuffer,
  2186. IN OUT LPDWORD lpdwInputBufferLength,
  2187. OUT LPVOID lpOutputBuffer,
  2188. IN OUT LPDWORD lpdwOutputBufferLength
  2189. )
  2190. /*++
  2191. Routine Description:
  2192. Makes device-dependent driver call based on O/S
  2193. Arguments:
  2194. dwProtocol - ignored
  2195. dwRequest - ignored
  2196. lpInputBuffer - pointer to request buffer
  2197. lpdwInputBufferLength - pointer to DWORD: IN = request buffer length
  2198. lpOutputBuffer - pointer to output buffer
  2199. lpdwOutputBufferLength - pointer to DWORD: IN = length of output buffer;
  2200. OUT = length of returned data
  2201. Return Value:
  2202. DWORD
  2203. Success - ERROR_SUCCESS
  2204. Failure -
  2205. --*/
  2206. {
  2207. DEBUG_ENTER((DBG_SOCKETS,
  2208. Dword,
  2209. "WsControl",
  2210. "%d, %d, %#x, %#x [%d], %#x, %#x [%d]",
  2211. dwProtocol,
  2212. dwRequest,
  2213. lpInputBuffer,
  2214. lpdwInputBufferLength,
  2215. *lpdwInputBufferLength,
  2216. lpOutputBuffer,
  2217. lpdwOutputBufferLength,
  2218. *lpdwOutputBufferLength
  2219. ));
  2220. DWORD error;
  2221. if (GlobalPlatformType == PLATFORM_TYPE_WINNT) {
  2222. error = WinNtWsControl(dwProtocol,
  2223. dwRequest,
  2224. lpInputBuffer,
  2225. lpdwInputBufferLength,
  2226. lpOutputBuffer,
  2227. lpdwOutputBufferLength
  2228. );
  2229. } else {
  2230. error = _I_WsControl(dwProtocol,
  2231. dwRequest,
  2232. lpInputBuffer,
  2233. lpdwInputBufferLength,
  2234. lpOutputBuffer,
  2235. lpdwOutputBufferLength
  2236. );
  2237. }
  2238. DEBUG_LEAVE(error);
  2239. return error;
  2240. }
  2241. //
  2242. // private functions
  2243. //
  2244. PRIVATE
  2245. DWORD
  2246. WinNtWsControl(
  2247. DWORD dwProtocol,
  2248. DWORD dwRequest,
  2249. LPVOID lpInputBuffer,
  2250. LPDWORD lpdwInputBufferLength,
  2251. LPVOID lpOutputBuffer,
  2252. LPDWORD lpdwOutputBufferLength
  2253. )
  2254. /*++
  2255. Routine Description:
  2256. Handles WsControl() functionality on NT platform. Assumes NTDLL.DLL has
  2257. already been loaded
  2258. Arguments:
  2259. dwProtocol - unused
  2260. dwRequest - unused
  2261. lpInputBuffer - contains driver request structure
  2262. lpdwInputBufferLength - pointer to length of InputBuffer
  2263. lpOutputBuffer - pointer to buffer where results written
  2264. lpdwOutputBufferLength - pointer to length of OutputBuffer. Updated with
  2265. returned data length on successful return
  2266. Return Value:
  2267. DWORD
  2268. Success - ERROR_SUCCESS
  2269. Failure -
  2270. --*/
  2271. {
  2272. DEBUG_ENTER((DBG_SOCKETS,
  2273. Dword,
  2274. "WinNtWsControl",
  2275. "%d, %d, %#x, %#x [%d], %#x, %#x [%d]",
  2276. dwProtocol,
  2277. dwRequest,
  2278. lpInputBuffer,
  2279. lpdwInputBufferLength,
  2280. *lpdwInputBufferLength,
  2281. lpOutputBuffer,
  2282. lpdwOutputBufferLength,
  2283. *lpdwOutputBufferLength
  2284. ));
  2285. UNREFERENCED_PARAMETER(dwProtocol);
  2286. UNREFERENCED_PARAMETER(dwRequest);
  2287. DWORD error;
  2288. if (TcpipDriverHandle == INVALID_HANDLE_VALUE) {
  2289. error = OpenTcpipDriverHandle();
  2290. if (error != ERROR_SUCCESS) {
  2291. goto quit;
  2292. }
  2293. }
  2294. DWORD bytesReturned;
  2295. BOOL ok;
  2296. ok = DeviceIoControl(TcpipDriverHandle,
  2297. IOCTL_TCP_QUERY_INFORMATION_EX,
  2298. lpInputBuffer,
  2299. *lpdwInputBufferLength,
  2300. lpOutputBuffer,
  2301. *lpdwOutputBufferLength,
  2302. &bytesReturned,
  2303. NULL
  2304. );
  2305. if (!ok) {
  2306. error = GetLastError();
  2307. } else {
  2308. *lpdwOutputBufferLength = bytesReturned;
  2309. error = ERROR_SUCCESS;
  2310. }
  2311. quit:
  2312. DEBUG_LEAVE(error);
  2313. return error;
  2314. }
  2315. PRIVATE
  2316. DWORD
  2317. OpenTcpipDriverHandle(
  2318. VOID
  2319. )
  2320. /*++
  2321. Routine Description:
  2322. Opens handle to TCP/IP device driver
  2323. Arguments:
  2324. None.
  2325. Return Value:
  2326. DWORD
  2327. Success - ERROR_SUCCESS
  2328. Failure -
  2329. --*/
  2330. {
  2331. DWORD error = ERROR_SUCCESS;
  2332. if (TcpipDriverHandle == INVALID_HANDLE_VALUE) {
  2333. OBJECT_ATTRIBUTES objectAttributes;
  2334. IO_STATUS_BLOCK iosb;
  2335. UNICODE_STRING string;
  2336. NTSTATUS status;
  2337. _I_RtlInitUnicodeString(&string, DD_TCP_DEVICE_NAME);
  2338. InitializeObjectAttributes(&objectAttributes,
  2339. &string,
  2340. OBJ_CASE_INSENSITIVE,
  2341. NULL,
  2342. NULL
  2343. );
  2344. status = _I_NtCreateFile(&TcpipDriverHandle,
  2345. SYNCHRONIZE | GENERIC_EXECUTE,
  2346. &objectAttributes,
  2347. &iosb,
  2348. NULL,
  2349. FILE_ATTRIBUTE_NORMAL,
  2350. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2351. FILE_OPEN_IF,
  2352. FILE_SYNCHRONOUS_IO_NONALERT,
  2353. NULL,
  2354. 0
  2355. );
  2356. if (!NT_SUCCESS(status)) {
  2357. error = _I_RtlNtStatusToDosError(status);
  2358. }
  2359. }
  2360. return error;
  2361. }
  2362. PRIVATE
  2363. VOID
  2364. CloseTcpipDriverHandle(
  2365. VOID
  2366. )
  2367. /*++
  2368. Routine Description:
  2369. Closes TCP/IP device driver handle
  2370. Arguments:
  2371. None.
  2372. Return Value:
  2373. None.
  2374. --*/
  2375. {
  2376. if (TcpipDriverHandle != INVALID_HANDLE_VALUE) {
  2377. CloseHandle(TcpipDriverHandle);
  2378. TcpipDriverHandle = INVALID_HANDLE_VALUE;
  2379. }
  2380. }
  2381. PRIVATE
  2382. DWORD
  2383. GetEntityList(
  2384. OUT TDIEntityID * * lplpEntities
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. Allocates a buffer for, and retrieves, the list of entities supported by the
  2389. TCP/IP device driver
  2390. Arguments:
  2391. lplpEntities - pointer to allocated returned list of entities. Caller
  2392. must free
  2393. Return Value:
  2394. UINT - number of entities returned
  2395. --*/
  2396. {
  2397. DEBUG_ENTER((DBG_SOCKETS,
  2398. Int,
  2399. "GetEntityList",
  2400. "%#x",
  2401. lplpEntities
  2402. ));
  2403. TCP_REQUEST_QUERY_INFORMATION_EX req;
  2404. memset(&req, 0, sizeof(req));
  2405. req.ID.toi_entity.tei_entity = GENERIC_ENTITY;
  2406. req.ID.toi_entity.tei_instance = 0;
  2407. req.ID.toi_class = INFO_CLASS_GENERIC;
  2408. req.ID.toi_type = INFO_TYPE_PROVIDER;
  2409. req.ID.toi_id = ENTITY_LIST_ID;
  2410. DWORD inputLen = sizeof(req);
  2411. DWORD outputLen = sizeof(TDIEntityID) * DEFAULT_MINIMUM_ENTITIES;
  2412. TDIEntityID * pEntity = NULL;
  2413. DWORD status = TDI_SUCCESS;
  2414. //
  2415. // this is over-engineered - its very unlikely that we'll ever get >32
  2416. // entities returned, never mind >64K's worth
  2417. //
  2418. // Go round this loop a maximum of 4 times - length of list shouldn't
  2419. // change between calls. Stops us getting stuck in infinite loop if
  2420. // something bad happens with outputLen
  2421. //
  2422. for (int i = 0; i < 4; ++i) {
  2423. DWORD previousOutputLen = outputLen;
  2424. pEntity = (TDIEntityID *)ResizeBuffer(pEntity, outputLen, FALSE);
  2425. if (pEntity == NULL) {
  2426. outputLen = 0;
  2427. break;
  2428. }
  2429. status = WsControl(IPPROTO_TCP,
  2430. WSCNTL_TCPIP_QUERY_INFO,
  2431. (LPVOID)&req,
  2432. &inputLen,
  2433. (LPVOID)pEntity,
  2434. &outputLen
  2435. );
  2436. //
  2437. // TDI_SUCCESS is returned if all data is not returned: driver
  2438. // communicates all/partial data via outputLen
  2439. //
  2440. if (status == TDI_SUCCESS) {
  2441. DEBUG_PRINT(UTIL,
  2442. INFO,
  2443. ("GENERIC_ENTITY required length = %d\n",
  2444. outputLen
  2445. ));
  2446. if (outputLen && (outputLen <= previousOutputLen)) {
  2447. break;
  2448. }
  2449. } else {
  2450. outputLen = 0;
  2451. }
  2452. }
  2453. if ((status != TDI_SUCCESS) && (pEntity != NULL)) {
  2454. ResizeBuffer(pEntity, 0, FALSE);
  2455. }
  2456. DEBUG_PRINT(UTIL,
  2457. INFO,
  2458. ("%d entities returned in %#x\n",
  2459. (outputLen / sizeof(TDIEntityID)),
  2460. pEntity
  2461. ));
  2462. *lplpEntities = pEntity;
  2463. DEBUG_LEAVE((UINT)(outputLen / sizeof(TDIEntityID)));
  2464. return (UINT)(outputLen / sizeof(TDIEntityID));
  2465. }
  2466. //
  2467. // private debug functions
  2468. //
  2469. #if INET_DEBUG
  2470. PRIVATE
  2471. LPCSTR
  2472. InternetMapEntity(
  2473. IN INT EntityId
  2474. ) {
  2475. switch (EntityId) {
  2476. case CO_TL_ENTITY:
  2477. return "CO_TL_ENTITY";
  2478. case CL_TL_ENTITY:
  2479. return "CL_TL_ENTITY";
  2480. case ER_ENTITY:
  2481. return "ER_ENTITY";
  2482. case CO_NL_ENTITY:
  2483. return "CO_NL_ENTITY";
  2484. case CL_NL_ENTITY:
  2485. return "CL_NL_ENTITY";
  2486. case AT_ENTITY:
  2487. return "AT_ENTITY";
  2488. case IF_ENTITY:
  2489. return "IF_ENTITY";
  2490. }
  2491. return "*** UNKNOWN ENTITY ***";
  2492. }
  2493. PRIVATE
  2494. LPCSTR
  2495. InternetMapInterface(
  2496. IN DWORD InterfaceType
  2497. ) {
  2498. switch (InterfaceType) {
  2499. case IF_TYPE_OTHER:
  2500. return "other";
  2501. case IF_TYPE_ETHERNET:
  2502. return "ethernet";
  2503. case IF_TYPE_TOKENRING:
  2504. return "token ring";
  2505. case IF_TYPE_FDDI:
  2506. return "FDDI";
  2507. case IF_TYPE_PPP:
  2508. return "PPP";
  2509. case IF_TYPE_LOOPBACK:
  2510. return "loopback";
  2511. }
  2512. return "???";
  2513. }
  2514. PRIVATE
  2515. LPCSTR
  2516. InternetMapInterfaceOnNT5(
  2517. IN DWORD InterfaceType
  2518. ) {
  2519. switch (InterfaceType) {
  2520. case IF_TYPE_OTHER:
  2521. return "other";
  2522. case IF_TYPE_ETHERNET_CSMACD:
  2523. return "ethernet";
  2524. case IF_TYPE_ISO88025_TOKENRING:
  2525. return "token ring";
  2526. case IF_TYPE_FDDI:
  2527. return "FDDI";
  2528. case IF_TYPE_PPP:
  2529. return "PPP";
  2530. case IF_TYPE_SOFTWARE_LOOPBACK:
  2531. return "loopback";
  2532. case IF_TYPE_SLIP:
  2533. return "SLIP";
  2534. default:
  2535. return "???";
  2536. }
  2537. return "???";
  2538. }
  2539. #endif