xref: /reactos/dll/win32/iphlpapi/iphlpapi_main.c (revision a5360f54)
1 /*
2  * iphlpapi dll implementation
3  *
4  * Copyright (C) 2003 Juan Lang
5  *               2018 Pierre Schweitzer
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #define DEBUG
23 
24 #include <config.h>
25 #include "iphlpapi_private.h"
26 #include <strsafe.h>
27 #include <psapi.h>
28 
29 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
30 
31 typedef struct _NAME_SERVER_LIST_CONTEXT {
32     ULONG uSizeAvailable;
33     ULONG uSizeRequired;
34     PIP_PER_ADAPTER_INFO pData;
35     UINT NumServers;
36     IP_ADDR_STRING *pLastAddr;
37 } NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
38 
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)39 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
40 {
41   switch (fdwReason) {
42     case DLL_PROCESS_ATTACH:
43       DisableThreadLibraryCalls( hinstDLL );
44       interfaceMapInit();
45       break;
46 
47     case DLL_PROCESS_DETACH:
48       interfaceMapFree();
49       break;
50   }
51   return TRUE;
52 }
53 
54 /******************************************************************
55  *    AddIPAddress (IPHLPAPI.@)
56  *
57  * PARAMS
58  *  Address [In]
59  *  IpMask [In]
60  *  IfIndex [In]
61  *  NTEContext [In/Out]
62  *  NTEInstance [In/Out]
63  *
64  * RETURNS
65  *  DWORD
66  */
AddIPAddress(IPAddr Address,IPMask Netmask,DWORD IfIndex,PULONG NteContext,PULONG NteInstance)67 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG NteContext, PULONG NteInstance)
68 {
69     return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
70 }
71 
getInterfaceGatewayByIndex(DWORD index)72 DWORD getInterfaceGatewayByIndex(DWORD index)
73 {
74     DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
75     RouteTable *table = getRouteTable();
76     if (!table) return 0;
77 
78     for (ndx = 0; ndx < numRoutes; ndx++)
79     {
80         if ((table->routes[ndx].ifIndex == (index)) && (table->routes[ndx].dest == 0))
81             retVal = table->routes[ndx].gateway;
82     }
83     HeapFree(GetProcessHeap(), 0, table);
84     return retVal;
85 }
86 
87 /******************************************************************
88  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
89  *
90  * PARAMS
91  *  ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
92  *   allocated and returned.
93  *  bOrder [In] -- passed to GetIfTable to order the table
94  *  heap [In] -- heap from which the table is allocated
95  *  flags [In] -- flags to HeapAlloc
96  *
97  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
98  *  GetIfTable returns otherwise
99  */
AllocateAndGetIfTableFromStack(PMIB_IFTABLE * ppIfTable,BOOL bOrder,HANDLE heap,DWORD flags)100 DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
101  BOOL bOrder, HANDLE heap, DWORD flags)
102 {
103   DWORD ret;
104 
105   TRACE("ppIfTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n", ppIfTable,
106    (DWORD)bOrder, heap, flags);
107   if (!ppIfTable)
108     ret = ERROR_INVALID_PARAMETER;
109   else {
110     DWORD dwSize = 0;
111 
112     *ppIfTable = NULL;
113     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
114     if (ret == ERROR_INSUFFICIENT_BUFFER) {
115       *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
116       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
117       if (ret != NO_ERROR) {
118         HeapFree(heap, flags, *ppIfTable);
119         *ppIfTable = NULL;
120       }
121     }
122   }
123   TRACE("returning %ld\n", ret);
124   return ret;
125 }
126 
127 
128 /******************************************************************
129  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
130  *
131  * PARAMS
132  *  ppIpAddrTable [Out]
133  *  bOrder [In] -- passed to GetIpAddrTable to order the table
134  *  heap [In] -- heap from which the table is allocated
135  *  flags [In] -- flags to HeapAlloc
136  *
137  * RETURNS
138  *  DWORD
139  */
AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE * ppIpAddrTable,BOOL bOrder,HANDLE heap,DWORD flags)140 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
141  BOOL bOrder, HANDLE heap, DWORD flags)
142 {
143   DWORD ret;
144 
145   TRACE("ppIpAddrTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
146    ppIpAddrTable, (DWORD)bOrder, heap, flags);
147   if (!ppIpAddrTable)
148     ret = ERROR_INVALID_PARAMETER;
149   else {
150     DWORD dwSize = 0;
151 
152     *ppIpAddrTable = NULL;
153     ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
154     if (ret == ERROR_INSUFFICIENT_BUFFER) {
155       *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
156       ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
157       if (ret != NO_ERROR) {
158         HeapFree(heap, flags, *ppIpAddrTable);
159         *ppIpAddrTable = NULL;
160       }
161     }
162   }
163   TRACE("returning %ld\n", ret);
164   return ret;
165 }
166 
167 
168 /******************************************************************
169  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
170  *
171  *  ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
172  *   allocated and returned.
173  *  bOrder [In] -- passed to GetIfTable to order the table
174  *  heap [In] -- heap from which the table is allocated
175  *  flags [In] -- flags to HeapAlloc
176  *
177  * RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
178  *  GetIpForwardTable returns otherwise
179  */
AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE * ppIpForwardTable,BOOL bOrder,HANDLE heap,DWORD flags)180 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
181  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
182 {
183   DWORD ret;
184 
185   TRACE("ppIpForwardTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
186    ppIpForwardTable, (DWORD)bOrder, heap, flags);
187   if (!ppIpForwardTable)
188     ret = ERROR_INVALID_PARAMETER;
189   else {
190     DWORD dwSize = 0;
191 
192     *ppIpForwardTable = NULL;
193     ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
194     if (ret == ERROR_INSUFFICIENT_BUFFER) {
195       *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
196       ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
197       if (ret != NO_ERROR) {
198         HeapFree(heap, flags, *ppIpForwardTable);
199         *ppIpForwardTable = NULL;
200       }
201     }
202   }
203   TRACE("returning %ld\n", ret);
204   return ret;
205 }
206 
207 
208 /******************************************************************
209  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
210  *
211  * PARAMS
212  *  ppIpNetTable [Out]
213  *  bOrder [In] -- passed to GetIpNetTable to order the table
214  *  heap [In] -- heap from which the table is allocated
215  *  flags [In] -- flags to HeapAlloc
216  *
217  * RETURNS
218  *  DWORD
219  */
AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE * ppIpNetTable,BOOL bOrder,HANDLE heap,DWORD flags)220 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
221  BOOL bOrder, HANDLE heap, DWORD flags)
222 {
223   DWORD ret;
224 
225   TRACE("ppIpNetTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
226    ppIpNetTable, (DWORD)bOrder, heap, flags);
227   if (!ppIpNetTable)
228     ret = ERROR_INVALID_PARAMETER;
229   else {
230     DWORD dwSize = 0;
231 
232     *ppIpNetTable = NULL;
233     ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
234     if (ret == ERROR_INSUFFICIENT_BUFFER) {
235       *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
236       ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
237       if (ret != NO_ERROR) {
238         HeapFree(heap, flags, *ppIpNetTable);
239         *ppIpNetTable = NULL;
240       }
241     }
242   }
243   TRACE("returning %ld\n", ret);
244   return ret;
245 }
246 
247 
248 /******************************************************************
249  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
250  *
251  * PARAMS
252  *  ppTcpTable [Out]
253  *  bOrder [In] -- passed to GetTcpTable to order the table
254  *  heap [In] -- heap from which the table is allocated
255  *  flags [In] -- flags to HeapAlloc
256  *
257  * RETURNS
258  *  DWORD
259  */
AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE * ppTcpTable,BOOL bOrder,HANDLE heap,DWORD flags)260 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
261  BOOL bOrder, HANDLE heap, DWORD flags)
262 {
263   DWORD ret;
264 
265   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
266    ppTcpTable, (DWORD)bOrder, heap, flags);
267   if (!ppTcpTable)
268     ret = ERROR_INVALID_PARAMETER;
269   else {
270     DWORD dwSize = 0;
271 
272     *ppTcpTable = NULL;
273     ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
274     if (ret == ERROR_INSUFFICIENT_BUFFER) {
275       *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
276       ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
277       if (ret != NO_ERROR) {
278         HeapFree(heap, flags, *ppTcpTable);
279         *ppTcpTable = NULL;
280       }
281     }
282   }
283   TRACE("returning %ld\n", ret);
284   return ret;
285 }
286 
287 
288 /******************************************************************
289  *    AllocateAndGetTcpExTableFromStack (IPHLPAPI.@)
290  *
291  * PARAMS
292  *  ppTcpTable [Out]
293  *  bOrder [In] -- passed to GetExtendedTcpTable to order the table
294  *  heap [In] -- heap from which the table is allocated
295  *  flags [In] -- flags to HeapAlloc
296  *  family [In] -- passed to GetExtendedTcpTable to select INET family
297  *
298  * RETURNS
299  *  DWORD
300  */
AllocateAndGetTcpExTableFromStack(PVOID * ppTcpTable,BOOL bOrder,HANDLE heap,DWORD flags,DWORD family)301 DWORD WINAPI AllocateAndGetTcpExTableFromStack(PVOID *ppTcpTable,
302  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family)
303 {
304   DWORD ret;
305 
306   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family 0x%08lx\n",
307    ppTcpTable, (DWORD)bOrder, heap, flags, family);
308   if (!ppTcpTable)
309     ret = ERROR_INVALID_PARAMETER;
310   else {
311     DWORD dwSize = 0;
312 
313     *ppTcpTable = NULL;
314     ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, TCP_TABLE_OWNER_PID_ALL, 0);
315     if (ret == ERROR_INSUFFICIENT_BUFFER) {
316       *ppTcpTable = (PMIB_TCPTABLE_OWNER_PID)HeapAlloc(heap, flags, dwSize);
317       ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, TCP_TABLE_OWNER_PID_ALL, 0);
318       if (ret != NO_ERROR) {
319         HeapFree(heap, flags, *ppTcpTable);
320         *ppTcpTable = NULL;
321       }
322     }
323   }
324   TRACE("returning %ld\n", ret);
325   return ret;
326 }
327 
328 
329 /******************************************************************
330  *    AllocateAndGetTcpExTable2FromStack (IPHLPAPI.@)
331  *
332  * PARAMS
333  *  ppTcpTable [Out]
334  *  bOrder [In] -- passed to GetExtendedTcpTable to order the table
335  *  heap [In] -- heap from which the table is allocated
336  *  flags [In] -- flags to HeapAlloc
337  *  family [In] -- passed to GetExtendedTcpTable to select INET family
338  *  class [In] -- passed to GetExtendedTcpTable to select information
339  *
340  * RETURNS
341  *  DWORD
342  */
AllocateAndGetTcpExTable2FromStack(PVOID * ppTcpTable,BOOL bOrder,HANDLE heap,DWORD flags,DWORD family,TCP_TABLE_CLASS class)343 DWORD WINAPI AllocateAndGetTcpExTable2FromStack(PVOID *ppTcpTable,
344  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family, TCP_TABLE_CLASS class)
345 {
346   DWORD ret;
347 
348   TRACE("ppTcpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family %ld, class %ld\n",
349    ppTcpTable, (DWORD)bOrder, heap, flags, family, class);
350   if (!ppTcpTable)
351     ret = ERROR_INVALID_PARAMETER;
352   else {
353     DWORD dwSize = 0;
354 
355     *ppTcpTable = NULL;
356     ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, class, 0);
357     if (ret == ERROR_INSUFFICIENT_BUFFER) {
358       *ppTcpTable = HeapAlloc(heap, flags, dwSize);
359       ret = GetExtendedTcpTable(*ppTcpTable, &dwSize, bOrder, family, class, 0);
360       if (ret != NO_ERROR) {
361         HeapFree(heap, flags, *ppTcpTable);
362         *ppTcpTable = NULL;
363       }
364     }
365   }
366   TRACE("returning %ld\n", ret);
367   return ret;
368 }
369 
370 
371 /******************************************************************
372  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
373  *
374  * PARAMS
375  *  ppUdpTable [Out]
376  *  bOrder [In] -- passed to GetUdpTable to order the table
377  *  heap [In] -- heap from which the table is allocated
378  *  flags [In] -- flags to HeapAlloc
379  *
380  * RETURNS
381  *  DWORD
382  */
AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE * ppUdpTable,BOOL bOrder,HANDLE heap,DWORD flags)383 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
384  BOOL bOrder, HANDLE heap, DWORD flags)
385 {
386   DWORD ret;
387 
388   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx\n",
389    ppUdpTable, (DWORD)bOrder, heap, flags);
390   if (!ppUdpTable)
391     ret = ERROR_INVALID_PARAMETER;
392   else {
393     DWORD dwSize = 0;
394 
395     *ppUdpTable = NULL;
396     ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
397     if (ret == ERROR_INSUFFICIENT_BUFFER) {
398       *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
399       ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
400       if (ret != NO_ERROR) {
401         HeapFree(heap, flags, *ppUdpTable);
402         *ppUdpTable = NULL;
403       }
404     }
405   }
406   TRACE("returning %ld\n", ret);
407   return ret;
408 }
409 
410 
411 /******************************************************************
412  *    AllocateAndGetUdpExTableFromStack (IPHLPAPI.@)
413  *
414  * PARAMS
415  *  ppUdpTable [Out]
416  *  bOrder [In] -- passed to GetExtendedUdpTable to order the table
417  *  heap [In] -- heap from which the table is allocated
418  *  flags [In] -- flags to HeapAlloc
419  *  family [In] -- passed to GetExtendedUdpTable to select INET family
420  *
421  * RETURNS
422  *  DWORD
423  */
AllocateAndGetUdpExTableFromStack(PVOID * ppUdpTable,BOOL bOrder,HANDLE heap,DWORD flags,DWORD family)424 DWORD WINAPI AllocateAndGetUdpExTableFromStack(PVOID *ppUdpTable,
425  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family)
426 {
427   DWORD ret;
428 
429   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family 0x%08lx\n",
430    ppUdpTable, (DWORD)bOrder, heap, flags, family);
431   if (!ppUdpTable)
432     ret = ERROR_INVALID_PARAMETER;
433   else {
434     DWORD dwSize = 0;
435 
436     *ppUdpTable = NULL;
437     ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, UDP_TABLE_OWNER_PID, 0);
438     if (ret == ERROR_INSUFFICIENT_BUFFER) {
439       *ppUdpTable = (PMIB_UDPTABLE_OWNER_PID)HeapAlloc(heap, flags, dwSize);
440       ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, UDP_TABLE_OWNER_PID, 0);
441       if (ret != NO_ERROR) {
442         HeapFree(heap, flags, *ppUdpTable);
443         *ppUdpTable = NULL;
444       }
445     }
446   }
447   TRACE("returning %ld\n", ret);
448   return ret;
449 }
450 
451 
452 /******************************************************************
453  *    AllocateAndGetUdpExTable2FromStack (IPHLPAPI.@)
454  *
455  * PARAMS
456  *  ppUdpTable [Out]
457  *  bOrder [In] -- passed to GetExtendedUdpTable to order the table
458  *  heap [In] -- heap from which the table is allocated
459  *  flags [In] -- flags to HeapAlloc
460  *  family [In] -- passed to GetExtendedUdpTable to select INET family
461  *  class [In] -- passed to GetExtendedUdpTable to select information
462  *
463  * RETURNS
464  *  DWORD
465  */
AllocateAndGetUdpExTable2FromStack(PVOID * ppUdpTable,BOOL bOrder,HANDLE heap,DWORD flags,DWORD family,UDP_TABLE_CLASS class)466 DWORD WINAPI AllocateAndGetUdpExTable2FromStack(PVOID *ppUdpTable,
467  BOOL bOrder, HANDLE heap, DWORD flags, DWORD family, UDP_TABLE_CLASS class)
468 {
469   DWORD ret;
470 
471   TRACE("ppUdpTable %p, bOrder %ld, heap 0x%p, flags 0x%08lx, family %ld, class %ld\n",
472    ppUdpTable, (DWORD)bOrder, heap, flags, family, class);
473   if (!ppUdpTable)
474     ret = ERROR_INVALID_PARAMETER;
475   else {
476     DWORD dwSize = 0;
477 
478     *ppUdpTable = NULL;
479     ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, class, 0);
480     if (ret == ERROR_INSUFFICIENT_BUFFER) {
481       *ppUdpTable = HeapAlloc(heap, flags, dwSize);
482       ret = GetExtendedUdpTable(*ppUdpTable, &dwSize, bOrder, family, class, 0);
483       if (ret != NO_ERROR) {
484         HeapFree(heap, flags, *ppUdpTable);
485         *ppUdpTable = NULL;
486       }
487     }
488   }
489   TRACE("returning %ld\n", ret);
490   return ret;
491 }
492 
493 
494 /******************************************************************
495  *    CreateIpForwardEntry (IPHLPAPI.@)
496  *
497  * PARAMS
498  *  pRoute [In/Out]
499  *
500  * RETURNS
501  *  DWORD
502  */
CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)503 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
504 {
505     return createIpForwardEntry( pRoute );
506 }
507 
508 
509 /******************************************************************
510  *    CreateIpNetEntry (IPHLPAPI.@)
511  *
512  * PARAMS
513  *  pArpEntry [In/Out]
514  *
515  * RETURNS
516  *  DWORD
517  */
CreateIpNetEntry(PMIB_IPNETROW pArpEntry)518 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
519 {
520   TRACE("pArpEntry %p\n", pArpEntry);
521   /* could use SIOCSARP on systems that support it, not sure I want to */
522   FIXME(":stub\n");
523   return (DWORD) 0;
524 }
525 
526 
527 /******************************************************************
528  *    CreateProxyArpEntry (IPHLPAPI.@)
529  *
530  * PARAMS
531  *  dwAddress [In]
532  *  dwMask [In]
533  *  dwIfIndex [In]
534  *
535  * RETURNS
536  *  DWORD
537  */
CreateProxyArpEntry(DWORD dwAddress,DWORD dwMask,DWORD dwIfIndex)538 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
539 {
540   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
541    dwMask, dwIfIndex);
542   FIXME(":stub\n");
543   /* marking Win2K+ functions not supported */
544   return ERROR_NOT_SUPPORTED;
545 }
546 
547 
548 /******************************************************************
549  *    DeleteIPAddress (IPHLPAPI.@)
550  *
551  * PARAMS
552  *  NTEContext [In]
553  *
554  * RETURNS
555  *  DWORD
556  */
DeleteIPAddress(ULONG NTEContext)557 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
558 {
559   TRACE("NTEContext %ld\n", NTEContext);
560   return RtlNtStatusToDosError(deleteIpAddress(NTEContext));
561 }
562 
563 
564 /******************************************************************
565  *    DeleteIpForwardEntry (IPHLPAPI.@)
566  *
567  * PARAMS
568  *  pRoute [In/Out]
569  *
570  * RETURNS
571  *  DWORD
572  */
DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)573 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
574 {
575     return deleteIpForwardEntry( pRoute );
576 }
577 
578 
579 /******************************************************************
580  *    DeleteIpNetEntry (IPHLPAPI.@)
581  *
582  * PARAMS
583  *  pArpEntry [In/Out]
584  *
585  * RETURNS
586  *  DWORD
587  */
DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)588 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
589 {
590   TRACE("pArpEntry %p\n", pArpEntry);
591   /* could use SIOCDARP on systems that support it, not sure I want to */
592   FIXME(":stub\n");
593   return (DWORD) 0;
594 }
595 
596 
597 /******************************************************************
598  *    DeleteProxyArpEntry (IPHLPAPI.@)
599  *
600  * PARAMS
601  *  dwAddress [In]
602  *  dwMask [In]
603  *  dwIfIndex [In]
604  *
605  * RETURNS
606  *  DWORD
607  */
DeleteProxyArpEntry(DWORD dwAddress,DWORD dwMask,DWORD dwIfIndex)608 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
609 {
610   TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress,
611    dwMask, dwIfIndex);
612   FIXME(":stub\n");
613   /* marking Win2K+ functions not supported */
614   return ERROR_NOT_SUPPORTED;
615 }
616 
617 /******************************************************************
618  *    EnableRouter (IPHLPAPI.@)
619  *
620  * PARAMS
621  *  pHandle [In/Out]
622  *  pOverlapped [In/Out]
623  *
624  * RETURNS
625  *  DWORD
626  */
EnableRouter(HANDLE * pHandle,OVERLAPPED * pOverlapped)627 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
628 {
629   TRACE("pHandle %p, pOverlapped %p\n", pHandle, pOverlapped);
630   FIXME(":stub\n");
631   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
632      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
633      marking Win2K+ functions not supported */
634   return ERROR_NOT_SUPPORTED;
635 }
636 
637 
638 /******************************************************************
639  *    FlushIpNetTable (IPHLPAPI.@)
640  *
641  * PARAMS
642  *  dwIfIndex [In]
643  *
644  * RETURNS
645  *  DWORD
646  */
FlushIpNetTable(DWORD dwIfIndex)647 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
648 {
649   TRACE("dwIfIndex 0x%08lx\n", dwIfIndex);
650   FIXME(":stub\n");
651   /* this flushes the arp cache of the given index
652      marking Win2K+ functions not supported */
653   return ERROR_NOT_SUPPORTED;
654 }
655 
656 
657 /******************************************************************
658  *    GetAdapterIndex (IPHLPAPI.@)
659  *
660  * PARAMS
661  *  AdapterName [In/Out]
662  *  IfIndex [In/Out]
663  *
664  * RETURNS
665  *  DWORD
666  */
GetAdapterIndex(LPWSTR AdapterName,PULONG IfIndex)667 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
668 {
669   TRACE("AdapterName %p, IfIndex %p\n", AdapterName, IfIndex);
670   FIXME(":stub\n");
671   /* marking Win2K+ functions not supported */
672   return ERROR_NOT_SUPPORTED;
673 }
674 
675 
676 /******************************************************************
677  *    GetAdaptersInfo (IPHLPAPI.@)
678  *
679  * PARAMS
680  *  pAdapterInfo [In/Out]
681  *  pOutBufLen [In/Out]
682  *
683  * RETURNS
684  *  DWORD
685  */
GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo,PULONG pOutBufLen)686 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
687 {
688   DWORD ret;
689   BOOL dhcpEnabled;
690   DWORD dhcpServer;
691 
692   TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
693   if (!pOutBufLen)
694     ret = ERROR_INVALID_PARAMETER;
695   else {
696     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
697 
698     if (numNonLoopbackInterfaces > 0) {
699       /* this calculation assumes only one address in the IP_ADDR_STRING lists.
700          that's okay, because:
701          - we don't get multiple addresses per adapter anyway
702          - we don't know about per-adapter gateways
703          - DHCP and WINS servers can have max one entry per list */
704       ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
705 
706       if (!pAdapterInfo || *pOutBufLen < size) {
707         *pOutBufLen = size;
708         ret = ERROR_BUFFER_OVERFLOW;
709       }
710       else {
711         InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
712 
713         if (table) {
714           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
715           if (*pOutBufLen < size) {
716             *pOutBufLen = size;
717             ret = ERROR_INSUFFICIENT_BUFFER;
718           }
719           else {
720             DWORD ndx;
721             HKEY hKey;
722             BOOL winsEnabled = FALSE;
723             IP_ADDRESS_STRING primaryWINS, secondaryWINS;
724 
725             memset(pAdapterInfo, 0, size);
726             /* @@ Wine registry key: HKCU\Software\Wine\Network */
727             if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network", &hKey) == ERROR_SUCCESS) {
728               DWORD size = sizeof(primaryWINS.String);
729               unsigned long addr;
730 
731               RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
732                (PBYTE)primaryWINS.String, &size);
733               addr = inet_addr(primaryWINS.String);
734               if (addr != INADDR_NONE && addr != INADDR_ANY)
735                 winsEnabled = TRUE;
736               size = sizeof(secondaryWINS.String);
737               RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
738                (PBYTE)secondaryWINS.String, &size);
739               addr = inet_addr(secondaryWINS.String);
740               if (addr != INADDR_NONE && addr != INADDR_ANY)
741                 winsEnabled = TRUE;
742               RegCloseKey(hKey);
743             }
744             TRACE("num of index is %lu\n", table->numIndexes);
745             for (ndx = 0; ndx < table->numIndexes; ndx++) {
746               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
747               DWORD addrLen = sizeof(ptr->Address), type;
748               const char *ifname =
749                   getInterfaceNameByIndex(table->indexes[ndx]);
750               if (!ifname) {
751                   ret = ERROR_OUTOFMEMORY;
752                   break;
753               }
754 
755               /* on Win98 this is left empty, but whatever */
756               strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
757               consumeInterfaceName(ifname);
758               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
759               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
760                ptr->Address, &type);
761               /* MS defines address length and type as UINT in some places and
762                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
763                  PDWORD are equiv (64-bit?) */
764               ptr->AddressLength = addrLen;
765               ptr->Type = type;
766               ptr->Index = table->indexes[ndx];
767               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
768                ptr->IpAddressList.IpAddress.String);
769               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
770                ptr->IpAddressList.IpMask.String);
771               ptr->IpAddressList.Context = ptr->Index;
772               toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
773                ptr->GatewayList.IpAddress.String);
774               getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
775                                     &dhcpServer, &ptr->LeaseObtained,
776                                     &ptr->LeaseExpires);
777               ptr->DhcpEnabled = (DWORD) dhcpEnabled;
778               toIPAddressString(dhcpServer,
779                                 ptr->DhcpServer.IpAddress.String);
780               if (winsEnabled) {
781                 ptr->HaveWins = TRUE;
782                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
783                  primaryWINS.String, sizeof(primaryWINS.String));
784                 memcpy(ptr->SecondaryWinsServer.IpAddress.String,
785                  secondaryWINS.String, sizeof(secondaryWINS.String));
786               }
787               if (ndx < table->numIndexes - 1)
788                 ptr->Next = &pAdapterInfo[ndx + 1];
789               else
790                 ptr->Next = NULL;
791             }
792             ret = NO_ERROR;
793           }
794           free(table);
795         }
796         else
797           ret = ERROR_OUTOFMEMORY;
798       }
799     }
800     else
801       ret = ERROR_NO_DATA;
802   }
803   TRACE("returning %ld\n", ret);
804   return ret;
805 }
806 
807 
808 /******************************************************************
809  *    GetBestInterface (IPHLPAPI.@)
810  *
811  * PARAMS
812  *  dwDestAddr [In]
813  *  pdwBestIfIndex [In/Out]
814  *
815  * RETURNS
816  *  DWORD
817  */
GetBestInterface(IPAddr dwDestAddr,PDWORD pdwBestIfIndex)818 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
819 {
820   DWORD ret;
821 
822   TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
823   if (!pdwBestIfIndex)
824     ret = ERROR_INVALID_PARAMETER;
825   else {
826     MIB_IPFORWARDROW ipRow;
827 
828     ret = GetBestRoute(dwDestAddr, 0, &ipRow);
829     if (ret == ERROR_SUCCESS)
830       *pdwBestIfIndex = ipRow.dwForwardIfIndex;
831   }
832   TRACE("returning %ld\n", ret);
833   return ret;
834 }
835 
836 
837 /******************************************************************
838  *    GetBestRoute (IPHLPAPI.@)
839  *
840  * PARAMS
841  *  dwDestAddr [In]
842  *  dwSourceAddr [In]
843  *  OUT [In]
844  *
845  * RETURNS
846  *  DWORD
847  */
GetBestRoute(DWORD dwDestAddr,DWORD dwSourceAddr,PMIB_IPFORWARDROW pBestRoute)848 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
849 {
850   PMIB_IPFORWARDTABLE table;
851   DWORD ret;
852 
853   TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
854    dwSourceAddr, pBestRoute);
855   if (!pBestRoute)
856     return ERROR_INVALID_PARAMETER;
857 
858   AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
859   if (table) {
860     DWORD ndx, minMaskSize, matchedNdx = 0;
861 
862     for (ndx = 0, minMaskSize = 255; ndx < table->dwNumEntries; ndx++) {
863       if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
864        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
865         DWORD hostMaskSize;
866 
867         if (!_BitScanForward(&hostMaskSize, ntohl(table->table[ndx].dwForwardMask)))
868         {
869             hostMaskSize = 32;
870         }
871         if (hostMaskSize < minMaskSize) {
872           minMaskSize = hostMaskSize;
873           matchedNdx = ndx;
874         }
875       }
876     }
877     memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
878     HeapFree(GetProcessHeap(), 0, table);
879     ret = ERROR_SUCCESS;
880   }
881   else
882     ret = ERROR_OUTOFMEMORY;
883   TRACE("returning %ld\n", ret);
884   return ret;
885 }
886 
TcpTableSorter(const void * a,const void * b)887 static int TcpTableSorter(const void *a, const void *b)
888 {
889   int ret;
890 
891   if (a && b) {
892     PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
893 
894     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
895     if (ret == 0) {
896       ret = rowA->dwLocalPort - rowB->dwLocalPort;
897       if (ret == 0) {
898         ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
899         if (ret == 0)
900           ret = rowA->dwRemotePort - rowB->dwRemotePort;
901       }
902     }
903   }
904   else
905     ret = 0;
906   return ret;
907 }
908 
909 /******************************************************************
910  *    GetExtendedTcpTable (IPHLPAPI.@)
911  *
912  * Get the table of TCP endpoints available to the application.
913  *
914  * PARAMS
915  *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
916  *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
917  *  bOrder    [In]     whether to order the table
918  *  ulAf	[in]	version of IP used by the TCP endpoints
919  *  TableClass [in]	type of the TCP table structure from TCP_TABLE_CLASS
920  *  Reserved [in]	reserved - this value must be zero
921  *
922  * RETURNS
923  *  Success: NO_ERROR
924  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
925  */
GetExtendedTcpTable(PVOID pTcpTable,PDWORD pdwSize,BOOL bOrder,ULONG ulAf,TCP_TABLE_CLASS TableClass,ULONG Reserved)926 DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
927 {
928     DWORD i, count, size;
929 	DWORD ret = NO_ERROR;
930 
931     if (!pdwSize)
932     {
933         return ERROR_INVALID_PARAMETER;
934     }
935 
936     if (ulAf != AF_INET)
937     {
938         UNIMPLEMENTED;
939         return ERROR_INVALID_PARAMETER;
940     }
941 
942     switch (TableClass)
943     {
944         case TCP_TABLE_BASIC_ALL:
945         {
946             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
947             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
948 
949             if (pOurTcpTable)
950             {
951                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW);
952                 if (size > *pdwSize || !pTheirTcpTable)
953                 {
954                     *pdwSize = size;
955                     ret = ERROR_INSUFFICIENT_BUFFER;
956                 }
957                 else
958                 {
959                     memcpy(pTheirTcpTable, pOurTcpTable, size);
960 
961                     if (bOrder)
962                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
963                               sizeof(MIB_TCPROW), TcpTableSorter);
964                 }
965 
966                 HeapFree(GetProcessHeap(),0, pOurTcpTable);
967             }
968         }
969         break;
970 
971         case TCP_TABLE_BASIC_CONNECTIONS:
972         {
973             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
974             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
975 
976             if (pOurTcpTable)
977             {
978                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
979                 {
980                     if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
981                     {
982                         ++count;
983                     }
984                 }
985 
986                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
987                 if (size > *pdwSize || !pTheirTcpTable)
988                 {
989                     *pdwSize = size;
990                     ret = ERROR_INSUFFICIENT_BUFFER;
991                 }
992                 else
993                 {
994                     pTheirTcpTable->dwNumEntries = count;
995 
996                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
997                     {
998                         if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
999                         {
1000                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1001                             ++count;
1002                         }
1003                     }
1004                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1005 
1006                     if (bOrder)
1007                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1008                               sizeof(MIB_TCPROW), TcpTableSorter);
1009                 }
1010 
1011                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1012             }
1013         }
1014         break;
1015 
1016         case TCP_TABLE_BASIC_LISTENER:
1017         {
1018             PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
1019             PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
1020 
1021             if (pOurTcpTable)
1022             {
1023                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1024                 {
1025                     if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1026                     {
1027                         ++count;
1028                     }
1029                 }
1030 
1031                 size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
1032                 if (size > *pdwSize || !pTheirTcpTable)
1033                 {
1034                     *pdwSize = size;
1035                     ret = ERROR_INSUFFICIENT_BUFFER;
1036                 }
1037                 else
1038                 {
1039                     pTheirTcpTable->dwNumEntries = count;
1040 
1041                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1042                     {
1043                         if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
1044                         {
1045                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
1046                             ++count;
1047                         }
1048                     }
1049                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1050 
1051                     if (bOrder)
1052                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1053                               sizeof(MIB_TCPROW), TcpTableSorter);
1054                 }
1055 
1056                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1057             }
1058         }
1059         break;
1060 
1061         case TCP_TABLE_OWNER_PID_ALL:
1062         {
1063             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1064             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1065 
1066             if (pOurTcpTable)
1067             {
1068                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID);
1069                 if (size > *pdwSize || !pTheirTcpTable)
1070                 {
1071                     *pdwSize = size;
1072                     ret = ERROR_INSUFFICIENT_BUFFER;
1073                 }
1074                 else
1075                 {
1076                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1077 
1078                     /* Don't sort on PID, so use basic helper */
1079                     if (bOrder)
1080                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1081                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1082                 }
1083 
1084                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1085             }
1086         }
1087         break;
1088 
1089         case TCP_TABLE_OWNER_PID_CONNECTIONS:
1090         {
1091             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1092             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1093 
1094             if (pOurTcpTable)
1095             {
1096                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1097                 {
1098                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1099                     {
1100                         ++count;
1101                     }
1102                 }
1103 
1104                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1105                 if (size > *pdwSize || !pTheirTcpTable)
1106                 {
1107                     *pdwSize = size;
1108                     ret = ERROR_INSUFFICIENT_BUFFER;
1109                 }
1110                 else
1111                 {
1112                     pTheirTcpTable->dwNumEntries = count;
1113 
1114                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1115                     {
1116                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1117                         {
1118                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1119                             ++count;
1120                         }
1121                     }
1122                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1123 
1124                     /* Don't sort on PID, so use basic helper */
1125                     if (bOrder)
1126                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1127                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1128                 }
1129 
1130                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1131             }
1132         }
1133         break;
1134 
1135         case TCP_TABLE_OWNER_PID_LISTENER:
1136         {
1137             PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
1138             PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
1139 
1140             if (pOurTcpTable)
1141             {
1142                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1143                 {
1144                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1145                     {
1146                         ++count;
1147                     }
1148                 }
1149 
1150                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
1151                 if (size > *pdwSize || !pTheirTcpTable)
1152                 {
1153                     *pdwSize = size;
1154                     ret = ERROR_INSUFFICIENT_BUFFER;
1155                 }
1156                 else
1157                 {
1158                     pTheirTcpTable->dwNumEntries = count;
1159 
1160                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1161                     {
1162                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1163                         {
1164                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
1165                             ++count;
1166                         }
1167                     }
1168                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1169 
1170                     /* Don't sort on PID, so use basic helper */
1171                     if (bOrder)
1172                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1173                               sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
1174                 }
1175 
1176                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1177             }
1178         }
1179         break;
1180 
1181         case TCP_TABLE_OWNER_MODULE_ALL:
1182         {
1183             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1184             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1185 
1186             if (pOurTcpTable)
1187             {
1188                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_MODULE);
1189                 if (size > *pdwSize || !pTheirTcpTable)
1190                 {
1191                     *pdwSize = size;
1192                     ret = ERROR_INSUFFICIENT_BUFFER;
1193                 }
1194                 else
1195                 {
1196                     memcpy(pTheirTcpTable, pOurTcpTable, size);
1197 
1198                     /* Don't sort on PID, so use basic helper */
1199                     if (bOrder)
1200                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1201                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1202                 }
1203 
1204                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1205             }
1206         }
1207         break;
1208 
1209         case TCP_TABLE_OWNER_MODULE_CONNECTIONS:
1210         {
1211             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1212             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1213 
1214             if (pOurTcpTable)
1215             {
1216                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1217                 {
1218                     if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1219                     {
1220                         ++count;
1221                     }
1222                 }
1223 
1224                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1225                 if (size > *pdwSize || !pTheirTcpTable)
1226                 {
1227                     *pdwSize = size;
1228                     ret = ERROR_INSUFFICIENT_BUFFER;
1229                 }
1230                 else
1231                 {
1232                     pTheirTcpTable->dwNumEntries = count;
1233 
1234                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1235                     {
1236                         if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
1237                         {
1238                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1239                             ++count;
1240                         }
1241                     }
1242                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1243 
1244                     /* Don't sort on PID, so use basic helper */
1245                     if (bOrder)
1246                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1247                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1248                 }
1249 
1250                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1251             }
1252         }
1253         break;
1254 
1255         case TCP_TABLE_OWNER_MODULE_LISTENER:
1256         {
1257             PMIB_TCPTABLE_OWNER_MODULE pOurTcpTable = getTcpTable(ClassModule);
1258             PMIB_TCPTABLE_OWNER_MODULE pTheirTcpTable = pTcpTable;
1259 
1260             if (pOurTcpTable)
1261             {
1262                 for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1263                 {
1264                     if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1265                     {
1266                         ++count;
1267                     }
1268                 }
1269 
1270                 size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_MODULE, table) + count * sizeof(MIB_TCPROW_OWNER_MODULE);
1271                 if (size > *pdwSize || !pTheirTcpTable)
1272                 {
1273                     *pdwSize = size;
1274                     ret = ERROR_INSUFFICIENT_BUFFER;
1275                 }
1276                 else
1277                 {
1278                     pTheirTcpTable->dwNumEntries = count;
1279 
1280                     for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
1281                     {
1282                         if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
1283                         {
1284                             memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_MODULE));
1285                             ++count;
1286                         }
1287                     }
1288                     ASSERT(count == pTheirTcpTable->dwNumEntries);
1289 
1290                     /* Don't sort on PID, so use basic helper */
1291                     if (bOrder)
1292                         qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
1293                               sizeof(MIB_TCPROW_OWNER_MODULE), TcpTableSorter);
1294                 }
1295 
1296                 HeapFree(GetProcessHeap(), 0, pOurTcpTable);
1297             }
1298         }
1299         break;
1300 
1301         default:
1302             ret = ERROR_INVALID_PARAMETER;
1303             break;
1304     }
1305 
1306     return ret;
1307 }
1308 
UdpTableSorter(const void * a,const void * b)1309 static int UdpTableSorter(const void *a, const void *b)
1310 {
1311   int ret;
1312 
1313   if (a && b) {
1314     PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
1315 
1316     ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
1317     if (ret == 0)
1318       ret = rowA->dwLocalPort - rowB->dwLocalPort;
1319   }
1320   else
1321     ret = 0;
1322   return ret;
1323 }
1324 
1325 /******************************************************************
1326  *    GetExtendedUdpTable (IPHLPAPI.@)
1327  *
1328  * Get the table of UDP endpoints available to the application.
1329  *
1330  * PARAMS
1331  *  pUdpTable [Out]    table struct with the filtered UDP endpoints available to application
1332  *  pdwSize   [In/Out] estimated size of the structure returned in pUdpTable, in bytes
1333  *  bOrder    [In]     whether to order the table
1334  *  ulAf	[in]	version of IP used by the UDP endpoints
1335  *  TableClass [in]	type of the UDP table structure from UDP_TABLE_CLASS
1336  *  Reserved [in]	reserved - this value must be zero
1337  *
1338  * RETURNS
1339  *  Success: NO_ERROR
1340  *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
1341  */
GetExtendedUdpTable(PVOID pUdpTable,PDWORD pdwSize,BOOL bOrder,ULONG ulAf,UDP_TABLE_CLASS TableClass,ULONG Reserved)1342 DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
1343 {
1344     DWORD size;
1345     DWORD ret = NO_ERROR;
1346 
1347     if (!pdwSize)
1348     {
1349         return ERROR_INVALID_PARAMETER;
1350     }
1351 
1352     if (ulAf != AF_INET)
1353     {
1354         UNIMPLEMENTED;
1355         return ERROR_INVALID_PARAMETER;
1356     }
1357 
1358     switch (TableClass)
1359     {
1360         case UDP_TABLE_BASIC:
1361         {
1362             PMIB_UDPTABLE pOurUdpTable = getUdpTable(ClassBasic);
1363             PMIB_UDPTABLE pTheirUdpTable = pUdpTable;
1364 
1365             if (pOurUdpTable)
1366             {
1367                 size = FIELD_OFFSET(MIB_UDPTABLE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW);
1368                 if (size > *pdwSize || !pTheirUdpTable)
1369                 {
1370                     *pdwSize = size;
1371                     ret = ERROR_INSUFFICIENT_BUFFER;
1372                 }
1373                 else
1374                 {
1375                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1376 
1377                     if (bOrder)
1378                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1379                               sizeof(MIB_UDPROW), UdpTableSorter);
1380                 }
1381 
1382                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1383             }
1384         }
1385         break;
1386 
1387         case UDP_TABLE_OWNER_PID:
1388         {
1389             PMIB_UDPTABLE_OWNER_PID pOurUdpTable = getUdpTable(ClassModulePid);
1390             PMIB_UDPTABLE_OWNER_PID pTheirUdpTable = pUdpTable;
1391 
1392             if (pOurUdpTable)
1393             {
1394                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID);
1395                 if (size > *pdwSize || !pTheirUdpTable)
1396                 {
1397                     *pdwSize = size;
1398                     ret = ERROR_INSUFFICIENT_BUFFER;
1399                 }
1400                 else
1401                 {
1402                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1403 
1404                     if (bOrder)
1405                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1406                               sizeof(MIB_UDPROW_OWNER_PID), UdpTableSorter);
1407                 }
1408 
1409                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1410             }
1411         }
1412         break;
1413 
1414         case UDP_TABLE_OWNER_MODULE:
1415         {
1416             PMIB_UDPTABLE_OWNER_MODULE pOurUdpTable = getUdpTable(ClassModule);
1417             PMIB_UDPTABLE_OWNER_MODULE pTheirUdpTable = pUdpTable;
1418 
1419             if (pOurUdpTable)
1420             {
1421                 size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_MODULE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_MODULE);
1422                 if (size > *pdwSize || !pTheirUdpTable)
1423                 {
1424                     *pdwSize = size;
1425                     ret = ERROR_INSUFFICIENT_BUFFER;
1426                 }
1427                 else
1428                 {
1429                     memcpy(pTheirUdpTable, pOurUdpTable, size);
1430 
1431                     if (bOrder)
1432                         qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
1433                               sizeof(MIB_UDPROW_OWNER_MODULE), UdpTableSorter);
1434                 }
1435 
1436                 HeapFree(GetProcessHeap(), 0, pOurUdpTable);
1437             }
1438         }
1439         break;
1440 
1441         default:
1442             ret = ERROR_INVALID_PARAMETER;
1443             break;
1444     }
1445 
1446     return ret;
1447 }
1448 
1449 
1450 /******************************************************************
1451  *    GetFriendlyIfIndex (IPHLPAPI.@)
1452  *
1453  * PARAMS
1454  *  IfIndex [In]
1455  *
1456  * RETURNS
1457  *  DWORD
1458  */
GetFriendlyIfIndex(DWORD IfIndex)1459 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
1460 {
1461   /* windows doesn't validate these, either, just makes sure the top byte is
1462      cleared.  I assume my ifenum module never gives an index with the top
1463      byte set. */
1464   TRACE("returning %ld\n", IfIndex);
1465   return IfIndex;
1466 }
1467 
1468 
1469 /******************************************************************
1470  *    GetIcmpStatistics (IPHLPAPI.@)
1471  *
1472  * PARAMS
1473  *  pStats [In/Out]
1474  *
1475  * RETURNS
1476  *  DWORD
1477  */
GetIcmpStatistics(PMIB_ICMP pStats)1478 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
1479 {
1480   DWORD ret;
1481 
1482   TRACE("pStats %p\n", pStats);
1483   ret = getICMPStats(pStats);
1484   TRACE("returning %ld\n", ret);
1485   return ret;
1486 }
1487 
1488 
1489 /******************************************************************
1490  *    GetIfEntry (IPHLPAPI.@)
1491  *
1492  * PARAMS
1493  *  pIfRow [In/Out]
1494  *
1495  * RETURNS
1496  *  DWORD
1497  */
GetIfEntry(PMIB_IFROW pIfRow)1498 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
1499 {
1500   DWORD ret;
1501   const char *name;
1502 
1503   TRACE("pIfRow %p\n", pIfRow);
1504   if (!pIfRow)
1505     return ERROR_INVALID_PARAMETER;
1506 
1507   name = getInterfaceNameByIndex(pIfRow->dwIndex);
1508   if (name) {
1509     ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
1510     if (ret == NO_ERROR)
1511       ret = getInterfaceStatsByName(name, pIfRow);
1512     consumeInterfaceName(name);
1513   }
1514   else
1515     ret = ERROR_INVALID_DATA;
1516   TRACE("returning %ld\n", ret);
1517   return ret;
1518 }
1519 
1520 
IfTableSorter(const void * a,const void * b)1521 static int IfTableSorter(const void *a, const void *b)
1522 {
1523   int ret;
1524 
1525   if (a && b)
1526     ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
1527   else
1528     ret = 0;
1529   return ret;
1530 }
1531 
1532 
1533 /******************************************************************
1534  *    GetIfTable (IPHLPAPI.@)
1535  *
1536  * PARAMS
1537  *  pIfTable [In/Out]
1538  *  pdwSize [In/Out]
1539  *  bOrder [In]
1540  *
1541  * RETURNS
1542  *  DWORD
1543  */
GetIfTable(PMIB_IFTABLE pIfTable,PULONG pdwSize,BOOL bOrder)1544 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
1545 {
1546   DWORD ret;
1547 
1548   TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
1549    (DWORD)bOrder);
1550   if (!pdwSize)
1551     ret = ERROR_INVALID_PARAMETER;
1552   else {
1553     DWORD numInterfaces = getNumInterfaces();
1554     ULONG size;
1555     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
1556     size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
1557 
1558     if (!pIfTable || *pdwSize < size) {
1559       *pdwSize = size;
1560       ret = ERROR_INSUFFICIENT_BUFFER;
1561     }
1562     else {
1563       InterfaceIndexTable *table = getInterfaceIndexTable();
1564 
1565       if (table) {
1566         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
1567          sizeof(MIB_IFROW);
1568         if (*pdwSize < size) {
1569           *pdwSize = size;
1570           ret = ERROR_INSUFFICIENT_BUFFER;
1571         }
1572         else {
1573           DWORD ndx;
1574 
1575           pIfTable->dwNumEntries = 0;
1576           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1577             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
1578             GetIfEntry(&pIfTable->table[ndx]);
1579             pIfTable->dwNumEntries++;
1580           }
1581           if (bOrder)
1582             qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
1583              IfTableSorter);
1584           ret = NO_ERROR;
1585         }
1586         free(table);
1587       }
1588       else
1589         ret = ERROR_OUTOFMEMORY;
1590     }
1591   }
1592   TRACE("returning %ld\n", ret);
1593   return ret;
1594 }
1595 
1596 
1597 /******************************************************************
1598  *    GetInterfaceInfo (IPHLPAPI.@)
1599  *
1600  * PARAMS
1601  *  pIfTable [In/Out]
1602  *  dwOutBufLen [In/Out]
1603  *
1604  * RETURNS
1605  *  DWORD
1606  */
GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable,PULONG dwOutBufLen)1607 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
1608 {
1609   DWORD ret;
1610 
1611   TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
1612   if (!dwOutBufLen)
1613     ret = ERROR_INVALID_PARAMETER;
1614   else {
1615     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
1616     ULONG size;
1617     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
1618     size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
1619      sizeof(IP_ADAPTER_INDEX_MAP);
1620 
1621     if (!pIfTable || *dwOutBufLen < size) {
1622       *dwOutBufLen = size;
1623       ret = ERROR_INSUFFICIENT_BUFFER;
1624     }
1625     else {
1626       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
1627 
1628       if (table) {
1629         TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
1630         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
1631          sizeof(IP_ADAPTER_INDEX_MAP);
1632         if (*dwOutBufLen < size) {
1633           *dwOutBufLen = size;
1634           ret = ERROR_INSUFFICIENT_BUFFER;
1635         }
1636         else {
1637           DWORD ndx;
1638 
1639           pIfTable->NumAdapters = 0;
1640           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1641             const char *walker, *name;
1642             WCHAR *assigner;
1643 
1644             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
1645             name = getInterfaceNameByIndex(table->indexes[ndx]);
1646             wcscpy(pIfTable->Adapter[ndx].Name, L"\\DEVICE\\TCPIP_");
1647             for (walker = name, assigner = &pIfTable->Adapter[ndx].Name[14];
1648              walker && *walker &&
1649              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1 - 14;
1650              walker++, assigner++)
1651               *assigner = *walker;
1652             *assigner = 0;
1653             consumeInterfaceName(name);
1654             pIfTable->NumAdapters++;
1655           }
1656           ret = NO_ERROR;
1657         }
1658         free(table);
1659       }
1660       else
1661         ret = ERROR_OUTOFMEMORY;
1662     }
1663   }
1664   TRACE("returning %ld\n", ret);
1665   return ret;
1666 }
1667 
1668 
IpAddrTableSorter(const void * a,const void * b)1669 static int IpAddrTableSorter(const void *a, const void *b)
1670 {
1671   int ret;
1672 
1673   if (a && b)
1674     ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
1675   else
1676     ret = 0;
1677   return ret;
1678 }
1679 
1680 
1681 /******************************************************************
1682  *    GetIpAddrTable (IPHLPAPI.@)
1683  *
1684  * PARAMS
1685  *  pIpAddrTable [In/Out]
1686  *  pdwSize [In/Out]
1687  *  bOrder [In]
1688  *
1689  * RETURNS
1690  *  DWORD
1691  */
GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable,PULONG pdwSize,BOOL bOrder)1692 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
1693 {
1694   DWORD ret;
1695 
1696   TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
1697    (DWORD)bOrder);
1698   if (!pdwSize)
1699     ret = ERROR_INVALID_PARAMETER;
1700   else {
1701     DWORD numInterfaces = getNumInterfaces();
1702     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
1703      sizeof(MIB_IPADDRROW);
1704 
1705     if (!pIpAddrTable || *pdwSize < size) {
1706       *pdwSize = size;
1707       ret = ERROR_INSUFFICIENT_BUFFER;
1708     }
1709     else {
1710       InterfaceIndexTable *table = getInterfaceIndexTable();
1711 
1712       if (table) {
1713         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
1714          sizeof(MIB_IPADDRROW);
1715         if (*pdwSize < size) {
1716           *pdwSize = size;
1717           ret = ERROR_INSUFFICIENT_BUFFER;
1718         }
1719         else {
1720           DWORD ndx, bcast;
1721 
1722           pIpAddrTable->dwNumEntries = 0;
1723           for (ndx = 0; ndx < table->numIndexes; ndx++) {
1724             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
1725             pIpAddrTable->table[ndx].dwAddr =
1726              getInterfaceIPAddrByIndex(table->indexes[ndx]);
1727             pIpAddrTable->table[ndx].dwMask =
1728              getInterfaceMaskByIndex(table->indexes[ndx]);
1729             /* the dwBCastAddr member isn't the broadcast address, it indicates
1730              * whether the interface uses the 1's broadcast address (1) or the
1731              * 0's broadcast address (0).
1732              */
1733             bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
1734             pIpAddrTable->table[ndx].dwBCastAddr =
1735              (bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
1736             /* FIXME: hardcoded reasm size, not sure where to get it */
1737             pIpAddrTable->table[ndx].dwReasmSize = 65535;
1738             pIpAddrTable->table[ndx].unused1 = 0;
1739             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
1740             pIpAddrTable->dwNumEntries++;
1741           }
1742           if (bOrder)
1743             qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
1744              sizeof(MIB_IPADDRROW), IpAddrTableSorter);
1745           ret = NO_ERROR;
1746         }
1747         free(table);
1748       }
1749       else
1750         ret = ERROR_OUTOFMEMORY;
1751     }
1752   }
1753   TRACE("returning %ld\n", ret);
1754   return ret;
1755 }
1756 
1757 
IpForwardTableSorter(const void * a,const void * b)1758 static int IpForwardTableSorter(const void *a, const void *b)
1759 {
1760   int ret;
1761 
1762   if (a && b) {
1763     PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
1764 
1765     ret = rowA->dwForwardDest - rowB->dwForwardDest;
1766     if (ret == 0) {
1767       ret = rowA->dwForwardProto - rowB->dwForwardProto;
1768       if (ret == 0) {
1769         ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
1770         if (ret == 0)
1771           ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
1772       }
1773     }
1774   }
1775   else
1776     ret = 0;
1777   return ret;
1778 }
1779 
1780 
1781 /******************************************************************
1782  *    GetIpForwardTable (IPHLPAPI.@)
1783  *
1784  * PARAMS
1785  *  pIpForwardTable [In/Out]
1786  *  pdwSize [In/Out]
1787  *  bOrder [In]
1788  *
1789  * RETURNS
1790  *  DWORD
1791  */
GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable,PULONG pdwSize,BOOL bOrder)1792 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
1793 {
1794   DWORD ret;
1795 
1796   TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
1797         pdwSize, (DWORD)bOrder);
1798   if (!pdwSize)
1799     ret = ERROR_INVALID_PARAMETER;
1800   else {
1801     DWORD numRoutes = getNumRoutes();
1802     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
1803      sizeof(MIB_IPFORWARDROW);
1804 
1805     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
1806       *pdwSize = sizeNeeded;
1807       ret = ERROR_INSUFFICIENT_BUFFER;
1808     }
1809     else {
1810       RouteTable *table = getRouteTable();
1811       if (table) {
1812         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
1813          sizeof(MIB_IPFORWARDROW);
1814         if (*pdwSize < sizeNeeded) {
1815           *pdwSize = sizeNeeded;
1816           ret = ERROR_INSUFFICIENT_BUFFER;
1817         }
1818         else {
1819           DWORD ndx;
1820 
1821           pIpForwardTable->dwNumEntries = table->numRoutes;
1822           for (ndx = 0; ndx < numRoutes; ndx++) {
1823             pIpForwardTable->table[ndx].dwForwardIfIndex =
1824              table->routes[ndx].ifIndex;
1825             pIpForwardTable->table[ndx].dwForwardDest =
1826              table->routes[ndx].dest;
1827             pIpForwardTable->table[ndx].dwForwardMask =
1828              table->routes[ndx].mask;
1829             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
1830             pIpForwardTable->table[ndx].dwForwardNextHop =
1831              table->routes[ndx].gateway;
1832             /* FIXME: this type is appropriate for local interfaces; may not
1833                always be appropriate */
1834             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
1835             /* FIXME: other protos might be appropriate, e.g. the default route
1836                is typically set with MIB_IPPROTO_NETMGMT instead */
1837             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
1838             /* punt on age and AS */
1839             pIpForwardTable->table[ndx].dwForwardAge = 0;
1840             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
1841             pIpForwardTable->table[ndx].dwForwardMetric1 =
1842              table->routes[ndx].metric;
1843             /* rest of the metrics are 0.. */
1844             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
1845             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
1846             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
1847             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
1848           }
1849           if (bOrder)
1850             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
1851              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
1852           ret = NO_ERROR;
1853         }
1854         HeapFree(GetProcessHeap(), 0, table);
1855       }
1856       else
1857         ret = ERROR_OUTOFMEMORY;
1858     }
1859   }
1860   TRACE("returning %ld\n", ret);
1861   return ret;
1862 }
1863 
1864 
IpNetTableSorter(const void * a,const void * b)1865 static int IpNetTableSorter(const void *a, const void *b)
1866 {
1867   int ret;
1868 
1869   if (a && b)
1870     ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
1871   else
1872     ret = 0;
1873   return ret;
1874 }
1875 
1876 
1877 /******************************************************************
1878  *    GetIpNetTable (IPHLPAPI.@)
1879  *
1880  * PARAMS
1881  *  pIpNetTable [In/Out]
1882  *  pdwSize [In/Out]
1883  *  bOrder [In]
1884  *
1885  * RETURNS
1886  *  DWORD
1887  */
GetIpNetTable(PMIB_IPNETTABLE pIpNetTable,PULONG pdwSize,BOOL bOrder)1888 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
1889 {
1890   DWORD ret = NO_ERROR;
1891 
1892   TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
1893    (DWORD)bOrder);
1894   if (!pdwSize)
1895     ret = ERROR_INVALID_PARAMETER;
1896   else {
1897     DWORD numEntries = getNumArpEntries();
1898     ULONG size = sizeof(MIB_IPNETTABLE);
1899 
1900     if (numEntries > 1)
1901       size += (numEntries - 1) * sizeof(MIB_IPNETROW);
1902     if (!pIpNetTable || *pdwSize < size) {
1903       *pdwSize = size;
1904       ret = ERROR_INSUFFICIENT_BUFFER;
1905     }
1906     else {
1907       PMIB_IPNETTABLE table = getArpTable();
1908       if (table) {
1909         size = sizeof(MIB_IPNETTABLE);
1910         if (table->dwNumEntries > 1)
1911           size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
1912         if (*pdwSize < size) {
1913           *pdwSize = size;
1914           ret = ERROR_INSUFFICIENT_BUFFER;
1915         }
1916         else {
1917           *pdwSize = size;
1918           memcpy(pIpNetTable, table, size);
1919           if (bOrder)
1920             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
1921              sizeof(MIB_IPNETROW), IpNetTableSorter);
1922           ret = NO_ERROR;
1923         }
1924         HeapFree(GetProcessHeap(), 0, table);
1925       }
1926     }
1927   }
1928   TRACE("returning %d\n", ret);
1929   return ret;
1930 }
1931 
1932 
1933 /******************************************************************
1934  *    GetIpStatistics (IPHLPAPI.@)
1935  *
1936  * PARAMS
1937  *  pStats [In/Out]
1938  *
1939  * RETURNS
1940  *  DWORD
1941  */
GetIpStatistics(PMIB_IPSTATS pStats)1942 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
1943 {
1944     return GetIpStatisticsEx(pStats, PF_INET);
1945 }
1946 
1947 /******************************************************************
1948  *    GetIpStatisticsEx (IPHLPAPI.@)
1949  *
1950  * PARAMS
1951  *  pStats [In/Out]
1952  *  dwFamily [In]
1953  *
1954  * RETURNS
1955  *  DWORD
1956  */
GetIpStatisticsEx(PMIB_IPSTATS pStats,DWORD dwFamily)1957 DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
1958 {
1959   DWORD ret;
1960 
1961   TRACE("pStats %p\n", pStats);
1962   ret = getIPStats(pStats, dwFamily);
1963   TRACE("returning %ld\n", ret);
1964   return ret;
1965 }
1966 
1967 /******************************************************************
1968  *    GetNetworkParams (IPHLPAPI.@)
1969  *
1970  * PARAMS
1971  *  pFixedInfo [In/Out]
1972  *  pOutBufLen [In/Out]
1973  *
1974  * RETURNS
1975  *  DWORD
1976  */
GetNetworkParams(PFIXED_INFO pFixedInfo,PULONG pOutBufLen)1977 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
1978 {
1979   DWORD ret, size, type;
1980   LONG regReturn;
1981   HKEY hKey;
1982   PIPHLP_RES_INFO resInfo;
1983 
1984   TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
1985   if (!pOutBufLen)
1986     return ERROR_INVALID_PARAMETER;
1987 
1988   resInfo = getResInfo();
1989   if (!resInfo)
1990     return ERROR_OUTOFMEMORY;
1991 
1992   size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
1993    sizeof(IP_ADDR_STRING) : 0);
1994   if (!pFixedInfo || *pOutBufLen < size) {
1995     *pOutBufLen = size;
1996     disposeResInfo( resInfo );
1997     return ERROR_BUFFER_OVERFLOW;
1998   }
1999 
2000   memset(pFixedInfo, 0, size);
2001   /* Check for DhcpHostname and DhcpDomain first */
2002   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2003                             "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
2004                             0,
2005                             KEY_READ,
2006                             &hKey);
2007   if (regReturn == ERROR_SUCCESS) {
2008       /* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
2009 #if 0
2010       type = REG_SZ;
2011       size = sizeof(pFixedInfo->HostName);
2012       regReturn = RegQueryValueExA(hKey,
2013                                       "DhcpHostname",
2014                                       NULL,
2015                                       &type,
2016                                       (LPBYTE)pFixedInfo->HostName,
2017                                       &size);
2018       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2019       {
2020 #endif
2021           type = REG_SZ;
2022           size = sizeof(pFixedInfo->HostName);
2023           regReturn = RegQueryValueExA(hKey,
2024                                           "Hostname",
2025                                           NULL,
2026                                           &type,
2027                                           (LPBYTE)pFixedInfo->HostName,
2028                                           &size);
2029 #if 0
2030       }
2031 #endif
2032 
2033       type = REG_SZ;
2034       size = sizeof(pFixedInfo->DomainName);
2035       regReturn = RegQueryValueExA(hKey,
2036                                       "DhcpDomain",
2037                                       NULL,
2038                                       &type,
2039                                       (LPBYTE)pFixedInfo->DomainName,
2040                                       &size);
2041       if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
2042       {
2043           type = REG_SZ;
2044           size = sizeof(pFixedInfo->DomainName);
2045           regReturn = RegQueryValueExA(hKey,
2046                                           "Domain",
2047                                           NULL,
2048                                           &type,
2049                                           (LPBYTE)pFixedInfo->DomainName,
2050                                           &size);
2051       }
2052       RegCloseKey(hKey);
2053   }
2054 
2055   TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
2056 
2057   if (resInfo->riCount > 0)
2058   {
2059     CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
2060     if (resInfo->riCount > 1)
2061     {
2062       IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
2063       IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
2064 
2065       pFixedInfo->DnsServerList.Next = pTarget;
2066 
2067       do
2068       {
2069         CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
2070         resInfo->riCount--;
2071         if (resInfo->riCount > 1)
2072         {
2073           pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
2074           pTarget = pTarget->Next;
2075           pSrc = pSrc->Next;
2076         }
2077         else
2078         {
2079           pTarget->Next = NULL;
2080           break;
2081         }
2082       }
2083       while(TRUE);
2084     }
2085     else
2086     {
2087       pFixedInfo->DnsServerList.Next = NULL;
2088     }
2089   }
2090 
2091   pFixedInfo->NodeType = HYBRID_NODETYPE;
2092   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2093    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
2094   if (regReturn != ERROR_SUCCESS)
2095     regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
2096      "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
2097      &hKey);
2098   if (regReturn == ERROR_SUCCESS)
2099   {
2100     DWORD size = sizeof(pFixedInfo->ScopeId);
2101 
2102     RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
2103     RegCloseKey(hKey);
2104   }
2105 
2106   disposeResInfo( resInfo );
2107   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
2108      I suppose could also check for a listener on port 53 to set EnableDns */
2109   ret = NO_ERROR;
2110   TRACE("returning %ld\n", ret);
2111 
2112   return ret;
2113 }
2114 
2115 
2116 /******************************************************************
2117  *    GetNumberOfInterfaces (IPHLPAPI.@)
2118  *
2119  * PARAMS
2120  *  pdwNumIf [In/Out]
2121  *
2122  * RETURNS
2123  *  DWORD
2124  */
GetNumberOfInterfaces(PDWORD pdwNumIf)2125 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
2126 {
2127   DWORD ret;
2128 
2129   TRACE("pdwNumIf %p\n", pdwNumIf);
2130   if (!pdwNumIf)
2131     ret = ERROR_INVALID_PARAMETER;
2132   else {
2133     *pdwNumIf = getNumInterfaces();
2134     ret = NO_ERROR;
2135   }
2136   TRACE("returning %ld\n", ret);
2137   return ret;
2138 }
2139 
2140 
GetOwnerModuleFromPidEntry(DWORD OwningPid,TCPIP_OWNER_MODULE_INFO_CLASS Class,PVOID Buffer,PDWORD pdwSize)2141 static DWORD GetOwnerModuleFromPidEntry(DWORD OwningPid, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2142 {
2143     HANDLE Process;
2144     DWORD FileLen, PathLen, Error;
2145     WCHAR File[MAX_PATH], Path[MAX_PATH];
2146     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2147 
2148     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2149         IsBadWritePtr(Buffer, *pdwSize))
2150     {
2151         return ERROR_INVALID_PARAMETER;
2152     }
2153 
2154     if (OwningPid == 0)
2155     {
2156         return ERROR_NOT_FOUND;
2157     }
2158 
2159     Process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, OwningPid);
2160     if (Process == NULL)
2161     {
2162         return GetLastError();
2163     }
2164 
2165     FileLen = GetModuleBaseNameW(Process, NULL, File, MAX_PATH);
2166     if (FileLen != 0)
2167     {
2168         PathLen = GetModuleFileNameExW(Process, NULL, Path, MAX_PATH);
2169         if (PathLen == 0)
2170         {
2171             CloseHandle(Process);
2172             return GetLastError();
2173         }
2174 
2175         /* Add NULL char */
2176         ++FileLen;
2177         ++PathLen;
2178         PathLen *= sizeof(WCHAR);
2179         FileLen *= sizeof(WCHAR);
2180     }
2181     else
2182     {
2183         Error = GetLastError();
2184 
2185         if (Error == ERROR_PARTIAL_COPY)
2186         {
2187             wcscpy(File, L"System");
2188             wcscpy(Path, L"System");
2189 
2190             PathLen = sizeof(L"System");
2191             FileLen = sizeof(L"System");
2192         }
2193         else
2194         {
2195             CloseHandle(Process);
2196             return Error;
2197         }
2198     }
2199 
2200     CloseHandle(Process);
2201 
2202     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen)
2203     {
2204         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2205         return ERROR_INSUFFICIENT_BUFFER;
2206     }
2207 
2208     BasicInfo = Buffer;
2209     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2210     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + FileLen);
2211     wcscpy(BasicInfo->pModuleName, File);
2212     wcscpy(BasicInfo->pModulePath, Path);
2213     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + PathLen + FileLen;
2214 
2215     return NO_ERROR;
2216 }
2217 
GetOwnerModuleFromTagEntry(DWORD OwningPid,DWORD OwningTag,TCPIP_OWNER_MODULE_INFO_CLASS Class,PVOID Buffer,PDWORD pdwSize)2218 static DWORD GetOwnerModuleFromTagEntry(DWORD OwningPid, DWORD OwningTag, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2219 {
2220     UINT Size;
2221     HRESULT Res;
2222     HANDLE hAdvapi32;
2223     WCHAR SysDir[MAX_PATH];
2224     PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo;
2225     ULONG (NTAPI *_I_QueryTagInformation)(PVOID, DWORD, PVOID);
2226     struct
2227     {
2228         DWORD ProcessId;
2229         DWORD ServiceTag;
2230         DWORD TagType;
2231         PWSTR Buffer;
2232     } ServiceQuery;
2233 
2234     if (IsBadWritePtr(pdwSize, sizeof(DWORD)) ||
2235         IsBadWritePtr(Buffer, *pdwSize))
2236     {
2237         return ERROR_INVALID_PARAMETER;
2238     }
2239 
2240     /* First, secure (avoid injections) load advapi32.dll */
2241     Size = GetSystemDirectoryW(SysDir, MAX_PATH);
2242     if (Size == 0)
2243     {
2244         return GetLastError();
2245     }
2246 
2247     Res = StringCchCatW(&SysDir[Size], MAX_PATH - Size, L"\\advapi32.dll");
2248     if (FAILED(Res))
2249     {
2250         return Res;
2251     }
2252 
2253     hAdvapi32 = GetModuleHandleW(SysDir);
2254     if (hAdvapi32 == NULL)
2255     {
2256         return GetLastError();
2257     }
2258 
2259     /* Now, we'll query the service associated with the tag */
2260     _I_QueryTagInformation = (PVOID)GetProcAddress(hAdvapi32, "I_QueryTagInformation");
2261     if (_I_QueryTagInformation == NULL)
2262     {
2263         return GetLastError();
2264     }
2265 
2266     /* Set tag and PID for the query */
2267     ServiceQuery.ProcessId = OwningPid;
2268     ServiceQuery.ServiceTag = OwningTag;
2269     ServiceQuery.TagType = 0;
2270     ServiceQuery.Buffer = NULL;
2271 
2272     /* And query */
2273     Res = _I_QueryTagInformation(NULL, 1, &ServiceQuery);
2274     if (Res != ERROR_SUCCESS)
2275     {
2276         return Res;
2277     }
2278 
2279     /* Compute service name length */
2280     Size = wcslen(ServiceQuery.Buffer) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
2281 
2282     /* We'll copy it twice, so make sure we have enough room */
2283     if (*pdwSize < sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size)
2284     {
2285         *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2286         LocalFree(ServiceQuery.Buffer);
2287         return ERROR_INSUFFICIENT_BUFFER;
2288     }
2289 
2290     /* Copy back data */
2291     BasicInfo = Buffer;
2292     BasicInfo->pModuleName = (PVOID)((ULONG_PTR)BasicInfo + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO));
2293     BasicInfo->pModulePath = (PVOID)((ULONG_PTR)BasicInfo->pModuleName + Size);
2294     wcscpy(BasicInfo->pModuleName, ServiceQuery.Buffer);
2295     wcscpy(BasicInfo->pModulePath, ServiceQuery.Buffer);
2296     *pdwSize = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 2 * Size;
2297     LocalFree(ServiceQuery.Buffer);
2298 
2299     return NO_ERROR;
2300 }
2301 
2302 /******************************************************************
2303  *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
2304  *
2305  * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
2306  *
2307  * PARAMS
2308  *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
2309  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2310  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2311  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2312  *
2313  * RETURNS
2314  *  Success: NO_ERROR
2315  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2316  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2317  *
2318  * NOTES
2319  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2320  */
GetOwnerModuleFromTcpEntry(PMIB_TCPROW_OWNER_MODULE pTcpEntry,TCPIP_OWNER_MODULE_INFO_CLASS Class,PVOID Buffer,PDWORD pdwSize)2321 DWORD WINAPI GetOwnerModuleFromTcpEntry(PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2322 {
2323     /* If we have a service tag, that's a service connection */
2324     if (pTcpEntry->OwningModuleInfo[0] != 0)
2325     {
2326         return GetOwnerModuleFromTagEntry(pTcpEntry->dwOwningPid, (DWORD)(pTcpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2327     }
2328     else
2329     {
2330         return GetOwnerModuleFromPidEntry(pTcpEntry->dwOwningPid, Class, Buffer, pdwSize);
2331     }
2332 }
2333 
2334 /******************************************************************
2335  *    GetOwnerModuleFromUdpEntry (IPHLPAPI.@)
2336  *
2337  * Get data about the module that issued the context bind for a specific IPv4 UDP endpoint in a MIB table row
2338  *
2339  * PARAMS
2340  *  pUdpEntry [in]    pointer to a MIB_UDPROW_OWNER_MODULE structure
2341  *  Class [in]    	TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
2342  *  Buffer [out]     	pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
2343  *  pdwSize [in, out]	estimated size of the structure returned in Buffer, in bytes
2344  *
2345  * RETURNS
2346  *  Success: NO_ERROR
2347  *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
2348  * 	       ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
2349  *
2350  * NOTES
2351  * The type of data returned in Buffer is indicated by the value of the Class parameter.
2352  */
GetOwnerModuleFromUdpEntry(PMIB_UDPROW_OWNER_MODULE pUdpEntry,TCPIP_OWNER_MODULE_INFO_CLASS Class,PVOID Buffer,PDWORD pdwSize)2353 DWORD WINAPI GetOwnerModuleFromUdpEntry(PMIB_UDPROW_OWNER_MODULE pUdpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
2354 {
2355     /* If we have a service tag, that's a service connection */
2356     if (pUdpEntry->OwningModuleInfo[0] != 0)
2357     {
2358         return GetOwnerModuleFromTagEntry(pUdpEntry->dwOwningPid, (DWORD)(pUdpEntry->OwningModuleInfo[0]), Class, Buffer, pdwSize);
2359     }
2360     else
2361     {
2362         return GetOwnerModuleFromPidEntry(pUdpEntry->dwOwningPid, Class, Buffer, pdwSize);
2363     }
2364 }
2365 
CreateNameServerListEnumNamesFunc(PWCHAR Interface,PWCHAR Server,PVOID Data)2366 static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
2367 {
2368   IP_ADDR_STRING *pNext;
2369   PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
2370 
2371   if (!Context->NumServers)
2372   {
2373     if (Context->uSizeAvailable >= Context->uSizeRequired)
2374     {
2375       WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
2376       Context->pData->DnsServerList.IpAddress.String[15] = '\0';
2377       Context->pLastAddr = &Context->pData->DnsServerList;
2378     }
2379   }
2380   else
2381   {
2382      Context->uSizeRequired += sizeof(IP_ADDR_STRING);
2383      if (Context->uSizeAvailable >= Context->uSizeRequired)
2384      {
2385          pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
2386          WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
2387          pNext->IpAddress.String[15] = '\0';
2388          Context->pLastAddr->Next = pNext;
2389          Context->pLastAddr = pNext;
2390          pNext->Next = NULL;
2391      }
2392   }
2393   Context->NumServers++;
2394 }
2395 
2396 /******************************************************************
2397  *    GetPerAdapterInfo (IPHLPAPI.@)
2398  *
2399  * PARAMS
2400  *  IfIndex [In]
2401  *  pPerAdapterInfo [In/Out]
2402  *  pOutBufLen [In/Out]
2403  *
2404  * RETURNS
2405  *  DWORD
2406  */
GetPerAdapterInfo(ULONG IfIndex,PIP_PER_ADAPTER_INFO pPerAdapterInfo,PULONG pOutBufLen)2407 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
2408 {
2409   HKEY hkey;
2410   DWORD dwSize = 0;
2411   const char *ifName;
2412   NAME_SERVER_LIST_CONTEXT Context;
2413   WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
2414 
2415   if (!pOutBufLen)
2416     return ERROR_INVALID_PARAMETER;
2417 
2418   if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
2419   {
2420     *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
2421     return ERROR_BUFFER_OVERFLOW;
2422   }
2423 
2424   ifName = getInterfaceNameByIndex(IfIndex);
2425   if (!ifName)
2426     return ERROR_INVALID_PARAMETER;
2427 
2428   MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
2429   HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
2430 
2431   if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
2432   {
2433     return ERROR_NOT_SUPPORTED;
2434   }
2435   Context.NumServers = 0;
2436   Context.uSizeAvailable = *pOutBufLen;
2437   Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
2438   Context.pData = pPerAdapterInfo;
2439 
2440   if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
2441     ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
2442 
2443   EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
2444 
2445   if (Context.uSizeRequired > Context.uSizeAvailable)
2446   {
2447     *pOutBufLen = Context.uSizeRequired;
2448     RegCloseKey(hkey);
2449     return ERROR_BUFFER_OVERFLOW;
2450   }
2451 
2452   if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
2453   {
2454     pPerAdapterInfo->AutoconfigActive = FALSE;
2455   }
2456   else
2457   {
2458     pPerAdapterInfo->AutoconfigActive = TRUE;
2459   }
2460 
2461   RegCloseKey(hkey);
2462   return NOERROR;
2463 }
2464 
2465 
2466 /******************************************************************
2467  *    GetRTTAndHopCount (IPHLPAPI.@)
2468  *
2469  * PARAMS
2470  *  DestIpAddress [In]
2471  *  HopCount [In/Out]
2472  *  MaxHops [In]
2473  *  RTT [In/Out]
2474  *
2475  * RETURNS
2476  *  BOOL
2477  */
GetRTTAndHopCount(IPAddr DestIpAddress,PULONG HopCount,ULONG MaxHops,PULONG RTT)2478 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
2479 {
2480   TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
2481    DestIpAddress, HopCount, MaxHops, RTT);
2482   FIXME(":stub\n");
2483   return (BOOL) 0;
2484 }
2485 
2486 
2487 /******************************************************************
2488  *    GetTcpStatisticsEx (IPHLPAPI.@)
2489  *
2490  * PARAMS
2491  *  pStats [In/Out]
2492  *  dwFamily [In]
2493  *
2494  * RETURNS
2495  *  DWORD
2496  */
GetTcpStatisticsEx(PMIB_TCPSTATS pStats,DWORD dwFamily)2497 DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
2498 {
2499   DWORD ret;
2500 
2501   TRACE("pStats %p\n", pStats);
2502   ret = getTCPStats(pStats, dwFamily);
2503   TRACE("returning %ld\n", ret);
2504   return ret;
2505 }
2506 
2507 /******************************************************************
2508  *    GetTcpStatistics (IPHLPAPI.@)
2509  *
2510  * PARAMS
2511  *  pStats [In/Out]
2512  *
2513  * RETURNS
2514  *  DWORD
2515  */
GetTcpStatistics(PMIB_TCPSTATS pStats)2516 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
2517 {
2518     return GetTcpStatisticsEx(pStats, PF_INET);
2519 }
2520 
2521 
2522 /******************************************************************
2523  *    GetTcpTable (IPHLPAPI.@)
2524  *
2525  * Get the table of active TCP connections.
2526  *
2527  * PARAMS
2528  *  pTcpTable [Out]    buffer for TCP connections table
2529  *  pdwSize   [In/Out] length of output buffer
2530  *  bOrder    [In]     whether to order the table
2531  *
2532  * RETURNS
2533  *  Success: NO_ERROR
2534  *  Failure: error code from winerror.h
2535  *
2536  * NOTES
2537  *  If pdwSize is less than required, the function will return
2538  *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
2539  *  the required byte size.
2540  *  If bOrder is true, the returned table will be sorted, first by
2541  *  local address and port number, then by remote address and port
2542  *  number.
2543  */
GetTcpTable(PMIB_TCPTABLE pTcpTable,PDWORD pdwSize,BOOL bOrder)2544 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
2545 {
2546     return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
2547 }
2548 
2549 
2550 /******************************************************************
2551  *    GetUdpStatisticsEx (IPHLPAPI.@)
2552  *
2553  * PARAMS
2554  *  pStats [In/Out]
2555  *  dwFamily [In]
2556  *
2557  * RETURNS
2558  *  DWORD
2559  */
GetUdpStatisticsEx(PMIB_UDPSTATS pStats,DWORD dwFamily)2560 DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
2561 {
2562   DWORD ret;
2563 
2564   TRACE("pStats %p\n", pStats);
2565   ret = getUDPStats(pStats, dwFamily);
2566   TRACE("returning %ld\n", ret);
2567   return ret;
2568 }
2569 
2570 /******************************************************************
2571  *    GetUdpStatistics (IPHLPAPI.@)
2572  *
2573  * PARAMS
2574  *  pStats [In/Out]
2575  *
2576  * RETURNS
2577  *  DWORD
2578  */
GetUdpStatistics(PMIB_UDPSTATS pStats)2579 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
2580 {
2581     return GetUdpStatisticsEx(pStats, PF_INET);
2582 }
2583 
2584 
2585 /******************************************************************
2586  *    GetUdpTable (IPHLPAPI.@)
2587  *
2588  * PARAMS
2589  *  pUdpTable [In/Out]
2590  *  pdwSize [In/Out]
2591  *  bOrder [In]
2592  *
2593  * RETURNS
2594  *  DWORD
2595  */
GetUdpTable(PMIB_UDPTABLE pUdpTable,PDWORD pdwSize,BOOL bOrder)2596 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
2597 {
2598     return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
2599 }
2600 
2601 
2602 /******************************************************************
2603  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
2604  *
2605  * This is a Win98-only function to get information on "unidirectional"
2606  * adapters.  Since this is pretty nonsensical in other contexts, it
2607  * never returns anything.
2608  *
2609  * PARAMS
2610  *  pIPIfInfo   [Out] buffer for adapter infos
2611  *  dwOutBufLen [Out] length of the output buffer
2612  *
2613  * RETURNS
2614  *  Success: NO_ERROR
2615  *  Failure: error code from winerror.h
2616  *
2617  * FIXME
2618  *  Stub, returns ERROR_NOT_SUPPORTED.
2619  */
GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo,PULONG dwOutBufLen)2620 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
2621 {
2622   TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
2623   /* a unidirectional adapter?? not bloody likely! */
2624   return ERROR_NOT_SUPPORTED;
2625 }
2626 
2627 
2628 /******************************************************************
2629  *    IpReleaseAddress (IPHLPAPI.@)
2630  *
2631  * Release an IP obtained through DHCP,
2632  *
2633  * PARAMS
2634  *  AdapterInfo [In] adapter to release IP address
2635  *
2636  * RETURNS
2637  *  Success: NO_ERROR
2638  *  Failure: error code from winerror.h
2639  */
IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)2640 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2641 {
2642   DWORD Status, Version = 0;
2643 
2644   if (!AdapterInfo)
2645       return ERROR_INVALID_PARAMETER;
2646 
2647   /* Maybe we should do this in DllMain */
2648   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2649       return ERROR_PROC_NOT_FOUND;
2650 
2651   if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
2652       Status = ERROR_SUCCESS;
2653   else
2654       Status = ERROR_PROC_NOT_FOUND;
2655 
2656   DhcpCApiCleanup();
2657 
2658   return Status;
2659 }
2660 
2661 
2662 /******************************************************************
2663  *    IpRenewAddress (IPHLPAPI.@)
2664  *
2665  * Renew an IP obtained through DHCP.
2666  *
2667  * PARAMS
2668  *  AdapterInfo [In] adapter to renew IP address
2669  *
2670  * RETURNS
2671  *  Success: NO_ERROR
2672  *  Failure: error code from winerror.h
2673  */
IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)2674 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
2675 {
2676   DWORD Status, Version = 0;
2677 
2678   if (!AdapterInfo)
2679       return ERROR_INVALID_PARAMETER;
2680 
2681   /* Maybe we should do this in DllMain */
2682   if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
2683       return ERROR_PROC_NOT_FOUND;
2684 
2685   if (DhcpRenewIpAddressLease(AdapterInfo->Index))
2686       Status = ERROR_SUCCESS;
2687   else
2688       Status = ERROR_PROC_NOT_FOUND;
2689 
2690   DhcpCApiCleanup();
2691 
2692   return Status;
2693 }
2694 
2695 
2696 /******************************************************************
2697  *    NotifyAddrChange (IPHLPAPI.@)
2698  *
2699  * Notify caller whenever the ip-interface map is changed.
2700  *
2701  * PARAMS
2702  *  Handle     [Out] handle usable in asynchronous notification
2703  *  overlapped [In]  overlapped structure that notifies the caller
2704  *
2705  * RETURNS
2706  *  Success: NO_ERROR
2707  *  Failure: error code from winerror.h
2708  *
2709  * FIXME
2710  *  Stub, returns ERROR_NOT_SUPPORTED.
2711  */
NotifyAddrChange(PHANDLE Handle,LPOVERLAPPED overlapped)2712 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2713 {
2714   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2715   if (Handle) *Handle = INVALID_HANDLE_VALUE;
2716   if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
2717   return ERROR_IO_PENDING;
2718 }
2719 
2720 
2721 /******************************************************************
2722  *    NotifyRouteChange (IPHLPAPI.@)
2723  *
2724  * Notify caller whenever the ip routing table is changed.
2725  *
2726  * PARAMS
2727  *  Handle     [Out] handle usable in asynchronous notification
2728  *  overlapped [In]  overlapped structure that notifies the caller
2729  *
2730  * RETURNS
2731  *  Success: NO_ERROR
2732  *  Failure: error code from winerror.h
2733  *
2734  * FIXME
2735  *  Stub, returns ERROR_NOT_SUPPORTED.
2736  */
NotifyRouteChange(PHANDLE Handle,LPOVERLAPPED overlapped)2737 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
2738 {
2739   FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
2740   return ERROR_NOT_SUPPORTED;
2741 }
2742 
2743 /******************************************************************
2744  *    SendARP (IPHLPAPI.@)
2745  *
2746  * Send an ARP request.
2747  *
2748  * PARAMS
2749  *  DestIP     [In]     attempt to obtain this IP
2750  *  SrcIP      [In]     optional sender IP address
2751  *  pMacAddr   [Out]    buffer for the mac address
2752  *  PhyAddrLen [In/Out] length of the output buffer
2753  *
2754  * RETURNS
2755  *  Success: NO_ERROR
2756  *  Failure: error code from winerror.h
2757  */
SendARP(IPAddr DestIP,IPAddr SrcIP,PULONG pMacAddr,PULONG PhyAddrLen)2758 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
2759 {
2760   IPAddr IPs[2];
2761   ULONG Size;
2762 
2763   if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
2764     return ERROR_INVALID_PARAMETER;
2765 
2766   IPs[0] = DestIP;
2767   IPs[1] = SrcIP;
2768   Size = sizeof(IPs);
2769   return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
2770 }
2771 
2772 
2773 /******************************************************************
2774  *    SetIfEntry (IPHLPAPI.@)
2775  *
2776  * Set the administrative status of an interface.
2777  *
2778  * PARAMS
2779  *  pIfRow [In] dwAdminStatus member specifies the new status.
2780  *
2781  * RETURNS
2782  *  Success: NO_ERROR
2783  *  Failure: error code from winerror.h
2784  *
2785  * FIXME
2786  *  Stub, returns ERROR_NOT_SUPPORTED.
2787  */
SetIfEntry(PMIB_IFROW pIfRow)2788 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
2789 {
2790   FIXME("(pIfRow %p): stub\n", pIfRow);
2791   /* this is supposed to set an interface administratively up or down.
2792      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
2793      this sort of down is indistinguishable from other sorts of down (e.g. no
2794      link). */
2795   return ERROR_NOT_SUPPORTED;
2796 }
2797 
2798 
2799 /******************************************************************
2800  *    SetIpForwardEntry (IPHLPAPI.@)
2801  *
2802  * Modify an existing route.
2803  *
2804  * PARAMS
2805  *  pRoute [In] route with the new information
2806  *
2807  * RETURNS
2808  *  Success: NO_ERROR
2809  *  Failure: error code from winerror.h
2810  */
SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)2811 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
2812 {
2813     return setIpForwardEntry( pRoute );
2814 }
2815 
2816 
2817 /******************************************************************
2818  *    SetIpNetEntry (IPHLPAPI.@)
2819  *
2820  * Modify an existing ARP entry.
2821  *
2822  * PARAMS
2823  *  pArpEntry [In] ARP entry with the new information
2824  *
2825  * RETURNS
2826  *  Success: NO_ERROR
2827  *  Failure: error code from winerror.h
2828  */
SetIpNetEntry(PMIB_IPNETROW pArpEntry)2829 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
2830 {
2831   HANDLE tcpFile;
2832   NTSTATUS status;
2833   TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
2834       TCP_REQUEST_SET_INFORMATION_INIT;
2835   TDIEntityID id;
2836   DWORD returnSize;
2837   PMIB_IPNETROW arpBuff;
2838 
2839   if (!pArpEntry)
2840       return ERROR_INVALID_PARAMETER;
2841 
2842   if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
2843       return ERROR_NOT_SUPPORTED;
2844 
2845   if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
2846   {
2847       closeTcpFile(tcpFile);
2848       return ERROR_INVALID_PARAMETER;
2849   }
2850 
2851   req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
2852   req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
2853   req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
2854   req.Req.ID.toi_entity.tei_instance = id.tei_instance;
2855   req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
2856   req.Req.BufferSize = sizeof(MIB_IPNETROW);
2857   arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
2858 
2859   RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
2860 
2861   status = DeviceIoControl( tcpFile,
2862                             IOCTL_TCP_SET_INFORMATION_EX,
2863                             &req,
2864                             sizeof(req),
2865                             NULL,
2866                             0,
2867                             &returnSize,
2868                             NULL );
2869 
2870   closeTcpFile(tcpFile);
2871 
2872   if (status)
2873      return NO_ERROR;
2874   else
2875      return ERROR_INVALID_PARAMETER;
2876 }
2877 
2878 
2879 /******************************************************************
2880  *    SetIpStatistics (IPHLPAPI.@)
2881  *
2882  * Toggle IP forwarding and det the default TTL value.
2883  *
2884  * PARAMS
2885  *  pIpStats [In] IP statistics with the new information
2886  *
2887  * RETURNS
2888  *  Success: NO_ERROR
2889  *  Failure: error code from winerror.h
2890  *
2891  * FIXME
2892  *  Stub, returns NO_ERROR.
2893  */
SetIpStatistics(PMIB_IPSTATS pIpStats)2894 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
2895 {
2896   FIXME("(pIpStats %p): stub\n", pIpStats);
2897   return 0;
2898 }
2899 
2900 
2901 /******************************************************************
2902  *    SetIpTTL (IPHLPAPI.@)
2903  *
2904  * Set the default TTL value.
2905  *
2906  * PARAMS
2907  *  nTTL [In] new TTL value
2908  *
2909  * RETURNS
2910  *  Success: NO_ERROR
2911  *  Failure: error code from winerror.h
2912  *
2913  * FIXME
2914  *  Stub, returns NO_ERROR.
2915  */
SetIpTTL(UINT nTTL)2916 DWORD WINAPI SetIpTTL(UINT nTTL)
2917 {
2918   FIXME("(nTTL %d): stub\n", nTTL);
2919   return 0;
2920 }
2921 
2922 
2923 /******************************************************************
2924  *    SetTcpEntry (IPHLPAPI.@)
2925  *
2926  * Set the state of a TCP connection.
2927  *
2928  * PARAMS
2929  *  pTcpRow [In] specifies connection with new state
2930  *
2931  * RETURNS
2932  *  Success: NO_ERROR
2933  *  Failure: error code from winerror.h
2934  *
2935  * FIXME
2936  *  Stub, returns NO_ERROR.
2937  */
SetTcpEntry(PMIB_TCPROW pTcpRow)2938 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
2939 {
2940   FIXME("(pTcpRow %p): stub\n", pTcpRow);
2941   return 0;
2942 }
2943 
2944 
2945 /******************************************************************
2946  *    UnenableRouter (IPHLPAPI.@)
2947  *
2948  * Decrement the IP-forwarding reference count. Turn off IP-forwarding
2949  * if it reaches zero.
2950  *
2951  * PARAMS
2952  *  pOverlapped     [In/Out] should be the same as in EnableRouter()
2953  *  lpdwEnableCount [Out]    optional, receives reference count
2954  *
2955  * RETURNS
2956  *  Success: NO_ERROR
2957  *  Failure: error code from winerror.h
2958  *
2959  * FIXME
2960  *  Stub, returns ERROR_NOT_SUPPORTED.
2961  */
UnenableRouter(OVERLAPPED * pOverlapped,LPDWORD lpdwEnableCount)2962 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
2963 {
2964   FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
2965    lpdwEnableCount);
2966   return ERROR_NOT_SUPPORTED;
2967 }
2968 
2969 /*
2970  * @unimplemented
2971  */
GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)2972 DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
2973 {
2974     FIXME(":stub\n");
2975     return 0L;
2976 }
2977 
2978 
2979 /*
2980  * @unimplemented
2981  */
GetAdapterOrderMap(VOID)2982 PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
2983 {
2984     FIXME(":stub\n");
2985     return 0L;
2986 }
2987 
2988 #ifdef GetAdaptersAddressesV1
GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)2989 DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
2990 {
2991     InterfaceIndexTable *indexTable;
2992     IFInfo ifInfo;
2993     int i;
2994     ULONG ret, requiredSize = 0;
2995     PIP_ADAPTER_ADDRESSES currentAddress;
2996     PUCHAR currentLocation;
2997     HANDLE tcpFile;
2998 
2999     if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
3000     if (Reserved) return ERROR_INVALID_PARAMETER;
3001 
3002     indexTable = getInterfaceIndexTable();
3003     if (!indexTable)
3004         return ERROR_NOT_ENOUGH_MEMORY;
3005 
3006     ret = openTcpFile(&tcpFile, FILE_READ_DATA);
3007     if (!NT_SUCCESS(ret))
3008     {
3009         free(indexTable);
3010         return ERROR_NO_DATA;
3011     }
3012 
3013     for (i = indexTable->numIndexes; i >= 0; i--)
3014     {
3015         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3016                                            NULL,
3017                                            indexTable->indexes[i],
3018                                            &ifInfo)))
3019         {
3020             /* The whole struct */
3021             requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
3022 
3023             /* Friendly name */
3024             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3025                 requiredSize += ifInfo.if_info.ent.if_descrlen + 1; //FIXME
3026 
3027             /* Adapter name */
3028             requiredSize += ifInfo.if_info.ent.if_descrlen + 1;
3029 
3030             /* Unicast address */
3031             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3032                 requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3033 
3034             /* FIXME: Implement multicast, anycast, and dns server stuff */
3035 
3036             /* FIXME: Implement dns suffix and description */
3037             requiredSize += 2 * sizeof(WCHAR);
3038 
3039             /* We're only going to implement what's required for XP SP0 */
3040         }
3041     }
3042     TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
3043     if (!pAdapterAddresses || *pOutBufLen < requiredSize)
3044     {
3045         *pOutBufLen = requiredSize;
3046         closeTcpFile(tcpFile);
3047         free(indexTable);
3048         return ERROR_BUFFER_OVERFLOW;
3049     }
3050 
3051     RtlZeroMemory(pAdapterAddresses, requiredSize);
3052 
3053     /* Let's set up the pointers */
3054     currentAddress = pAdapterAddresses;
3055     for (i = indexTable->numIndexes; i >= 0; i--)
3056     {
3057         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3058                                            NULL,
3059                                            indexTable->indexes[i],
3060                                            &ifInfo)))
3061         {
3062             currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
3063 
3064             /* FIXME: Friendly name */
3065             if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
3066             {
3067                 currentAddress->FriendlyName = (PVOID)currentLocation;
3068                 currentLocation += sizeof(WCHAR);
3069             }
3070 
3071             /* Adapter name */
3072             currentAddress->AdapterName = (PVOID)currentLocation;
3073             currentLocation += ifInfo.if_info.ent.if_descrlen + 1;
3074 
3075             /* Unicast address */
3076             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3077             {
3078                 currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
3079                 currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3080                 currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
3081                 currentLocation += sizeof(struct sockaddr);
3082             }
3083 
3084             /* FIXME: Implement multicast, anycast, and dns server stuff */
3085 
3086             /* FIXME: Implement dns suffix and description */
3087             currentAddress->DnsSuffix = (PVOID)currentLocation;
3088             currentLocation += sizeof(WCHAR);
3089 
3090             currentAddress->Description = (PVOID)currentLocation;
3091             currentLocation += sizeof(WCHAR);
3092 
3093             currentAddress->Next = (PVOID)currentLocation;
3094             /* Terminate the last address correctly */
3095             if(i==0)
3096                 currentAddress->Next = NULL;
3097 
3098             /* We're only going to implement what's required for XP SP0 */
3099 
3100             currentAddress = currentAddress->Next;
3101         }
3102     }
3103 
3104     /* Now again, for real this time */
3105 
3106     currentAddress = pAdapterAddresses;
3107     for (i = indexTable->numIndexes; i >= 0; i--)
3108     {
3109         if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
3110                                            NULL,
3111                                            indexTable->indexes[i],
3112                                            &ifInfo)))
3113         {
3114             /* Make sure we're not looping more than we hoped for */
3115             ASSERT(currentAddress);
3116 
3117             /* Alignment information */
3118             currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
3119             currentAddress->IfIndex = indexTable->indexes[i];
3120 
3121             /* Adapter name */
3122             memcpy(currentAddress->AdapterName, ifInfo.if_info.ent.if_descr, ifInfo.if_info.ent.if_descrlen);
3123             currentAddress->AdapterName[ifInfo.if_info.ent.if_descrlen] = '\0';
3124 
3125             if (!(Flags & GAA_FLAG_SKIP_UNICAST))
3126             {
3127                 currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
3128                 currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
3129                 currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
3130                 currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
3131                 memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
3132                        &ifInfo.ip_addr.iae_addr,
3133                        sizeof(ifInfo.ip_addr.iae_addr));
3134                 currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
3135                 currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
3136                 currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
3137                 currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
3138                 currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
3139                 currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
3140                 currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
3141             }
3142 
3143             /* FIXME: Implement multicast, anycast, and dns server stuff */
3144             currentAddress->FirstAnycastAddress = NULL;
3145             currentAddress->FirstMulticastAddress = NULL;
3146             currentAddress->FirstDnsServerAddress = NULL;
3147 
3148             /* FIXME: Implement dns suffix, description, and friendly name */
3149             currentAddress->DnsSuffix[0] = UNICODE_NULL;
3150             currentAddress->Description[0] = UNICODE_NULL;
3151             currentAddress->FriendlyName[0] = UNICODE_NULL;
3152 
3153             /* Physical Address */
3154             memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
3155             currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
3156 
3157             /* Flags */
3158             currentAddress->Flags = 0; //FIXME
3159 
3160             /* MTU */
3161             currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
3162 
3163             /* Interface type */
3164             currentAddress->IfType = ifInfo.if_info.ent.if_type;
3165 
3166             /* Operational status */
3167             if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
3168                 currentAddress->OperStatus = IfOperStatusUp;
3169             else
3170                 currentAddress->OperStatus = IfOperStatusDown;
3171 
3172             /* We're only going to implement what's required for XP SP0 */
3173 
3174             /* Move to the next address */
3175             currentAddress = currentAddress->Next;
3176         }
3177     }
3178 
3179     closeTcpFile(tcpFile);
3180     free(indexTable);
3181 
3182     return NO_ERROR;
3183 }
3184 #endif
3185 
3186 /*
3187  * @unimplemented
3188  */
CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)3189 BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
3190 {
3191     FIXME(":stub\n");
3192     return 0L;
3193 }
3194 
3195 /*
3196  * @unimplemented
3197  */
GetBestInterfaceEx(struct sockaddr * pDestAddr,PDWORD pdwBestIfIndex)3198 DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
3199 {
3200     FIXME(":stub\n");
3201     return 0L;
3202 }
3203 
3204 /*
3205  * @unimplemented
3206  */
NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO ** ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)3207 DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
3208 {
3209     FIXME(":stub\n");
3210     return 0L;
3211 }
3212 
3213 /*
3214  * @unimplemented
3215  */
GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)3216 DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
3217 {
3218     FIXME(":stub\n");
3219 
3220     if (!pStats)
3221         return ERROR_INVALID_PARAMETER;
3222 
3223     if (dwFamily != AF_INET && dwFamily != AF_INET6)
3224         return ERROR_INVALID_PARAMETER;
3225 
3226     return 0L;
3227 }
3228 
3229 DWORD WINAPI
SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)3230 SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
3231 {
3232     FIXME("SetIpForwardEntryToStack() stub\n");
3233     return 0L;
3234 }
3235 
GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,_Out_writes_bytes_to_ (* pOutBufLen,* pOutBufLen)PWCHAR pInterfaceName,_Inout_ PULONG pOutBufLen)3236 DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
3237                                _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3238                                _Inout_ PULONG pOutBufLen)
3239 {
3240     UNICODE_STRING GuidString;
3241     DWORD result, type;
3242     WCHAR szKeyName[2*MAX_PATH];
3243     HRESULT hr;
3244     HKEY hKey;
3245 
3246     if (pInterfaceGUID == NULL || pOutBufLen == NULL)
3247         return ERROR_INVALID_PARAMETER;
3248 
3249     result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
3250 
3251     if (!NT_SUCCESS(result))
3252     {
3253         // failed to convert guid to string
3254         return RtlNtStatusToDosError(result);
3255     }
3256 
3257     hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
3258     RtlFreeUnicodeString(&GuidString);
3259 
3260     if (FAILED(hr))
3261     {
3262         // key name is too long
3263         return ERROR_BUFFER_OVERFLOW;
3264     }
3265 
3266     result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
3267 
3268     if (result != ERROR_SUCCESS)
3269     {
3270         // failed to find adapter entry
3271         return ERROR_NOT_FOUND;
3272     }
3273 
3274     result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
3275 
3276     RegCloseKey(hKey);
3277 
3278     if (result == ERROR_MORE_DATA)
3279     {
3280         *pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
3281         return ERROR_INSUFFICIENT_BUFFER;
3282     }
3283 
3284     if (result != ERROR_SUCCESS || type != REG_SZ)
3285     {
3286         // failed to read adapter name
3287         return ERROR_NO_DATA;
3288     }
3289     return ERROR_SUCCESS;
3290 }
3291 
3292 DWORD WINAPI
NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,_Out_writes_bytes_to_ (* pOutBufLen,* pOutBufLen)PWCHAR pInterfaceName,_Inout_ PULONG pOutBufLen,DWORD dwUnknown4,DWORD dwUnknown5)3293 NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
3294                                  _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3295                                  _Inout_ PULONG pOutBufLen,
3296                                  DWORD dwUnknown4,
3297                                  DWORD dwUnknown5)
3298 {
3299     SetLastError(ERROR_SUCCESS);
3300 
3301     if (pInterfaceName == NULL)
3302         return ERROR_INVALID_PARAMETER;
3303 
3304     return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3305 }
3306 
3307 DWORD WINAPI
NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,_Out_writes_bytes_to_ (* pOutBufLen,* pOutBufLen)PWCHAR pInterfaceName,_Inout_ PULONG pOutBufLen,DWORD dwUnknown4,DWORD dwUnknown5)3308 NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
3309                            _Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
3310                            _Inout_ PULONG pOutBufLen,
3311                            DWORD dwUnknown4,
3312                            DWORD dwUnknown5)
3313 {
3314     DWORD result;
3315 
3316     result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
3317 
3318     if (result == ERROR_NOT_FOUND)
3319         SetLastError(ERROR_PATH_NOT_FOUND);
3320 
3321     return result;
3322 }
3323