Free the debug info when making a critical section global.
[wine] / dlls / iphlpapi / iphlpapi_main.c
1 /*
2  * iphlpapi dll implementation
3  *
4  * Copyright (C) 2003 Juan Lang
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <sys/types.h>
25 #ifdef HAVE_NETINET_IN_H
26 # include <netinet/in.h>
27 #endif
28 #ifdef HAVE_ARPA_NAMESER_H
29 # include <arpa/nameser.h>
30 #endif
31 #ifdef HAVE_RESOLV_H
32 # include <resolv.h>
33 #endif
34
35 #include "winbase.h"
36 #include "iphlpapi.h"
37 #include "ifenum.h"
38 #include "ipstats.h"
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
42
43
44 /******************************************************************
45  *    AddIPAddress (IPHLPAPI.@)
46  *
47  *
48  * PARAMS
49  *
50  *  Address [In]
51  *  IpMask [In]
52  *  IfIndex [In]
53  *  NTEContext [In/Out]
54  *  NTEInstance [In/Out]
55  *
56  * RETURNS
57  *
58  *  DWORD
59  *
60  */
61 DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance)
62 {
63   FIXME(":stub\n");
64   /* marking Win2K+ functions not supported */
65   return ERROR_NOT_SUPPORTED;
66 }
67
68
69 /******************************************************************
70  *    CreateIpForwardEntry (IPHLPAPI.@)
71  *
72  *
73  * PARAMS
74  *
75  *  pRoute [In/Out]
76  *
77  * RETURNS
78  *
79  *  DWORD
80  *
81  */
82 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
83 {
84   /* could use SIOCADDRT, not sure I want to */
85   FIXME(":stub\n");
86   return (DWORD) 0;
87 }
88
89
90 /******************************************************************
91  *    CreateIpNetEntry (IPHLPAPI.@)
92  *
93  *
94  * PARAMS
95  *
96  *  pArpEntry [In/Out]
97  *
98  * RETURNS
99  *
100  *  DWORD
101  *
102  */
103 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
104 {
105   /* could use SIOCSARP on systems that support it, not sure I want to */
106   FIXME(":stub\n");
107   return (DWORD) 0;
108 }
109
110
111 /******************************************************************
112  *    CreateProxyArpEntry (IPHLPAPI.@)
113  *
114  *
115  * PARAMS
116  *
117  *  dwAddress [In]
118  *  dwMask [In]
119  *  dwIfIndex [In]
120  *
121  * RETURNS
122  *
123  *  DWORD
124  *
125  */
126 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
127 {
128   FIXME(":stub\n");
129   /* marking Win2K+ functions not supported */
130   return ERROR_NOT_SUPPORTED;
131 }
132
133
134 /******************************************************************
135  *    DeleteIPAddress (IPHLPAPI.@)
136  *
137  *
138  * PARAMS
139  *
140  *  NTEContext [In]
141  *
142  * RETURNS
143  *
144  *  DWORD
145  *
146  */
147 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
148 {
149   FIXME(":stub\n");
150   /* marking Win2K+ functions not supported */
151   return ERROR_NOT_SUPPORTED;
152 }
153
154
155 /******************************************************************
156  *    DeleteIpForwardEntry (IPHLPAPI.@)
157  *
158  *
159  * PARAMS
160  *
161  *  pRoute [In/Out]
162  *
163  * RETURNS
164  *
165  *  DWORD
166  *
167  */
168 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
169 {
170   /* could use SIOCDELRT, not sure I want to */
171   FIXME(":stub\n");
172   return (DWORD) 0;
173 }
174
175
176 /******************************************************************
177  *    DeleteIpNetEntry (IPHLPAPI.@)
178  *
179  *
180  * PARAMS
181  *
182  *  pArpEntry [In/Out]
183  *
184  * RETURNS
185  *
186  *  DWORD
187  *
188  */
189 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
190 {
191   /* could use SIOCDARP on systems that support it, not sure I want to */
192   FIXME(":stub\n");
193   return (DWORD) 0;
194 }
195
196
197 /******************************************************************
198  *    DeleteProxyArpEntry (IPHLPAPI.@)
199  *
200  *
201  * PARAMS
202  *
203  *  dwAddress [In]
204  *  dwMask [In]
205  *  dwIfIndex [In]
206  *
207  * RETURNS
208  *
209  *  DWORD
210  *
211  */
212 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
213 {
214   FIXME(":stub\n");
215   /* marking Win2K+ functions not supported */
216   return ERROR_NOT_SUPPORTED;
217 }
218
219
220 /******************************************************************
221  *    EnableRouter (IPHLPAPI.@)
222  *
223  *
224  * PARAMS
225  *
226  *  pHandle [In/Out]
227  *  pOverlapped [In/Out]
228  *
229  * RETURNS
230  *
231  *  DWORD
232  *
233  */
234 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
235 {
236   FIXME(":stub\n");
237   /* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
238      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
239      marking Win2K+ functions not supported */
240   return ERROR_NOT_SUPPORTED;
241 }
242
243
244 /******************************************************************
245  *    FlushIpNetTable (IPHLPAPI.@)
246  *
247  *
248  * PARAMS
249  *
250  *  dwIfIndex [In]
251  *
252  * RETURNS
253  *
254  *  DWORD
255  *
256  */
257 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
258 {
259   FIXME(":stub\n");
260   /* this flushes the arp cache of the given index
261      marking Win2K+ functions not supported */
262   return ERROR_NOT_SUPPORTED;
263 }
264
265
266 /******************************************************************
267  *    GetAdapterIndex (IPHLPAPI.@)
268  *
269  *
270  * PARAMS
271  *
272  *  AdapterName [In/Out]
273  *  IfIndex [In/Out]
274  *
275  * RETURNS
276  *
277  *  DWORD
278  *
279  */
280 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
281 {
282   FIXME(":stub\n");
283   /* marking Win2K+ functions not supported */
284   return ERROR_NOT_SUPPORTED;
285 }
286
287
288 /******************************************************************
289  *    GetAdaptersInfo (IPHLPAPI.@)
290  *
291  *
292  * PARAMS
293  *
294  *  pAdapterInfo [In/Out]
295  *  pOutBufLen [In/Out]
296  *
297  * RETURNS
298  *
299  *  DWORD
300  *
301  */
302 DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
303 {
304   DWORD ret;
305
306   if (!pOutBufLen)
307     ret = ERROR_INVALID_PARAMETER;
308   else {
309     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
310
311     if (numNonLoopbackInterfaces > 0) {
312       /* this calculation assumes only one address in the IP_ADDR_STRING lists.
313          that's okay, because:
314          - we don't get multiple addresses per adapter anyway
315          - we don't know about per-adapter gateways
316          - we don't know about DHCP or WINS (and these must be single anyway) */
317       ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
318
319       if (!pAdapterInfo || *pOutBufLen < size) {
320         *pOutBufLen = size;
321         ret = ERROR_BUFFER_OVERFLOW;
322       }
323       else {
324         InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
325
326         if (table) {
327           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
328           if (*pOutBufLen < size) {
329             *pOutBufLen = size;
330             ret = ERROR_INSUFFICIENT_BUFFER;
331           }
332           else {
333             DWORD ndx;
334
335             memset(pAdapterInfo, 0, size);
336             for (ndx = 0; ndx < table->numIndexes; ndx++) {
337               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
338               DWORD addrLen = sizeof(ptr->Address), type;
339
340               /* on Win98 this is left empty, but whatever */
341               strncpy(ptr->AdapterName,
342                getInterfaceNameByIndex(table->indexes[ndx]),
343                sizeof(ptr->AdapterName));
344               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
345               getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
346                ptr->Address, &type);
347               /* MS defines address length and type as UINT in some places and
348                  DWORD in others, **sigh**.  Don't want to assume that PUINT and
349                  PDWORD are equiv (64-bit?) */
350               ptr->AddressLength = addrLen;
351               ptr->Type = type;
352               ptr->Index = table->indexes[ndx];
353               toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
354                ptr->IpAddressList.IpAddress.String);
355               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
356                ptr->IpAddressList.IpMask.String);
357               if (ndx < table->numIndexes + 1)
358                 ptr->Next = (ndx == table->numIndexes - 1) ? NULL : &pAdapterInfo[ndx + 1];
359             }
360             ret = NO_ERROR;
361           }
362           free(table);
363         }
364         else
365           ret = ERROR_OUTOFMEMORY;
366       }
367     }
368     else
369       ret = ERROR_NO_DATA;
370   }
371   return ret;
372 }
373
374
375 /******************************************************************
376  *    GetBestInterface (IPHLPAPI.@)
377  *
378  *
379  * PARAMS
380  *
381  *  dwDestAddr [In]
382  *  pdwBestIfIndex [In/Out]
383  *
384  * RETURNS
385  *
386  *  DWORD
387  *
388  */
389 DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
390 {
391   FIXME(":stub\n");
392   return (DWORD) 0;
393 }
394
395
396 /******************************************************************
397  *    GetBestRoute (IPHLPAPI.@)
398  *
399  *
400  * PARAMS
401  *
402  *  dwDestAddr [In]
403  *  dwSourceAddr [In]
404  *  OUT [In]
405  *
406  * RETURNS
407  *
408  *  DWORD
409  *
410  */
411 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
412 {
413   FIXME(":stub\n");
414   return (DWORD) 0;
415 }
416
417
418 /******************************************************************
419  *    GetFriendlyIfIndex (IPHLPAPI.@)
420  *
421  *
422  * PARAMS
423  *
424  *  IfIndex [In]
425  *
426  * RETURNS
427  *
428  *  DWORD
429  *
430  */
431 DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
432 {
433   /* windows doesn't validate these, either, just makes sure the top byte is
434      cleared.  I assume my ipshared module never gives an index with the top
435      byte set. */
436   return IfIndex;
437 }
438
439
440 /******************************************************************
441  *    GetIcmpStatistics (IPHLPAPI.@)
442  *
443  *
444  * PARAMS
445  *
446  *  pStats [In/Out]
447  *
448  * RETURNS
449  *
450  *  DWORD
451  *
452  */
453 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
454 {
455   return getICMPStats(pStats);
456 }
457
458
459 /******************************************************************
460  *    GetIfEntry (IPHLPAPI.@)
461  *
462  *
463  * PARAMS
464  *
465  *  pIfRow [In/Out]
466  *
467  * RETURNS
468  *
469  *  DWORD
470  *
471  */
472 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
473 {
474   DWORD ret;
475   const char *name;
476
477   if (!pIfRow)
478     return ERROR_INVALID_PARAMETER;
479
480   name = getInterfaceNameByIndex(pIfRow->dwIndex);
481   if (name) {
482     ret = getInterfaceEntryByName(name, pIfRow);
483     if (ret == NO_ERROR)
484       ret = getInterfaceStatsByName(name, pIfRow);
485   }
486   else
487     ret = ERROR_INVALID_DATA;
488   return ret;
489 }
490
491
492 /******************************************************************
493  *    GetIfTable (IPHLPAPI.@)
494  *
495  *
496  * PARAMS
497  *
498  *  pIfTable [In/Out]
499  *  pdwSize [In/Out]
500  *  bOrder [In]
501  *
502  * RETURNS
503  *
504  *  DWORD
505  *
506  */
507 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
508 {
509   DWORD ret;
510
511   if (!pdwSize)
512     ret = ERROR_INVALID_PARAMETER;
513   else {
514     DWORD numInterfaces = getNumInterfaces();
515     ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
516
517     if (!pIfTable || *pdwSize < size) {
518       *pdwSize = size;
519       ret = ERROR_INSUFFICIENT_BUFFER;
520     }
521     else {
522       InterfaceIndexTable *table = getInterfaceIndexTable();
523
524       if (table) {
525         size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
526          sizeof(MIB_IFROW);
527         if (*pdwSize < size) {
528           *pdwSize = size;
529           ret = ERROR_INSUFFICIENT_BUFFER;
530         }
531         else {
532           DWORD ndx;
533
534           if (bOrder)
535             FIXME(":order not implemented");
536           pIfTable->dwNumEntries = 0;
537           for (ndx = 0; ndx < table->numIndexes; ndx++) {
538             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
539             GetIfEntry(&pIfTable->table[ndx]);
540             pIfTable->dwNumEntries++;
541           }
542           ret = NO_ERROR;
543         }
544         free(table);
545       }
546       else
547         ret = ERROR_OUTOFMEMORY;
548     }
549   }
550   return ret;
551 }
552
553
554 /******************************************************************
555  *    GetInterfaceInfo (IPHLPAPI.@)
556  *
557  *
558  * PARAMS
559  *
560  *  pIfTable [In/Out]
561  *  dwOutBufLen [In/Out]
562  *
563  * RETURNS
564  *
565  *  DWORD
566  *
567  */
568 DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
569 {
570   DWORD ret;
571
572   if (!dwOutBufLen)
573     ret = ERROR_INVALID_PARAMETER;
574   else {
575     DWORD numInterfaces = getNumInterfaces();
576     ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) *
577      sizeof(IP_ADAPTER_INDEX_MAP);
578
579     if (!pIfTable || *dwOutBufLen < size) {
580       *dwOutBufLen = size;
581       ret = ERROR_INSUFFICIENT_BUFFER;
582     }
583     else {
584       InterfaceIndexTable *table = getInterfaceIndexTable();
585
586       if (table) {
587         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
588          sizeof(IP_ADAPTER_INDEX_MAP);
589         if (*dwOutBufLen < size) {
590           *dwOutBufLen = size;
591           ret = ERROR_INSUFFICIENT_BUFFER;
592         }
593         else {
594           DWORD ndx;
595
596           pIfTable->NumAdapters = 0;
597           for (ndx = 0; ndx < table->numIndexes; ndx++) {
598             const char *walker, *name;
599             WCHAR *assigner;
600
601             pIfTable->Adapter[ndx].Index = table->indexes[ndx];
602             name = getInterfaceNameByIndex(table->indexes[ndx]);
603             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
604              walker && *walker &&
605              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
606              walker++, assigner++)
607               *assigner = *walker;
608             *assigner = 0;
609             pIfTable->NumAdapters++;
610           }
611           ret = NO_ERROR;
612         }
613         free(table);
614       }
615       else
616         ret = ERROR_OUTOFMEMORY;
617     }
618   }
619   return ret;
620 }
621
622
623 /******************************************************************
624  *    GetIpAddrTable (IPHLPAPI.@)
625  *
626  *
627  * PARAMS
628  *
629  *  pIpAddrTable [In/Out]
630  *  pdwSize [In/Out]
631  *  bOrder [In]
632  *
633  * RETURNS
634  *
635  *  DWORD
636  *
637  */
638 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
639 {
640   DWORD ret;
641
642   if (!pdwSize)
643     ret = ERROR_INVALID_PARAMETER;
644   else {
645     DWORD numInterfaces = getNumInterfaces();
646     ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
647      sizeof(MIB_IPADDRROW);
648
649     if (!pIpAddrTable || *pdwSize < size) {
650       *pdwSize = size;
651       ret = ERROR_INSUFFICIENT_BUFFER;
652     }
653     else {
654       InterfaceIndexTable *table = getInterfaceIndexTable();
655
656       if (table) {
657         size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
658          sizeof(MIB_IPADDRROW);
659         if (*pdwSize < size) {
660           *pdwSize = size;
661           ret = ERROR_INSUFFICIENT_BUFFER;
662         }
663         else {
664           DWORD ndx;
665
666           if (bOrder)
667             FIXME(":order not implemented");
668           pIpAddrTable->dwNumEntries = 0;
669           for (ndx = 0; ndx < table->numIndexes; ndx++) {
670             pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
671             pIpAddrTable->table[ndx].dwAddr =
672              getInterfaceIPAddrByIndex(table->indexes[ndx]);
673             pIpAddrTable->table[ndx].dwMask =
674              getInterfaceMaskByIndex(table->indexes[ndx]);
675             pIpAddrTable->table[ndx].dwBCastAddr =
676              getInterfaceBCastAddrByIndex(table->indexes[ndx]);
677             /* FIXME: hardcoded reasm size, not sure where to get it */
678             pIpAddrTable->table[ndx].dwReasmSize = 65535;
679             pIpAddrTable->table[ndx].unused1 = 0;
680             pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
681             pIpAddrTable->dwNumEntries++;
682           }
683           ret = NO_ERROR;
684         }
685         free(table);
686       }
687       else
688         ret = ERROR_OUTOFMEMORY;
689     }
690   }
691   return ret;
692 }
693
694
695 /******************************************************************
696  *    GetIpForwardTable (IPHLPAPI.@)
697  *
698  *
699  * PARAMS
700  *
701  *  pIpForwardTable [In/Out]
702  *  pdwSize [In/Out]
703  *  bOrder [In]
704  *
705  * RETURNS
706  *
707  *  DWORD
708  *
709  */
710 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
711 {
712   DWORD ret;
713
714   if (!pdwSize)
715     ret = ERROR_INVALID_PARAMETER;
716   else {
717     DWORD numRoutes = getNumRoutes();
718     ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
719      sizeof(MIB_IPFORWARDROW);
720
721     if (!pIpForwardTable || *pdwSize < sizeNeeded) {
722       *pdwSize = sizeNeeded;
723       ret = ERROR_INSUFFICIENT_BUFFER;
724     }
725     else {
726       RouteTable *table = getRouteTable();
727       if (table) {
728         sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
729          sizeof(MIB_IPFORWARDROW);
730         if (*pdwSize < sizeNeeded) {
731           *pdwSize = sizeNeeded;
732           ret = ERROR_INSUFFICIENT_BUFFER;
733         }
734         else {
735           DWORD ndx;
736
737           if (bOrder)
738             FIXME(":order not implemented");
739           pIpForwardTable->dwNumEntries = table->numRoutes;
740           for (ndx = 0; ndx < numRoutes; ndx++) {
741             pIpForwardTable->table[ndx].dwForwardIfIndex =
742              table->routes[ndx].ifIndex;
743             pIpForwardTable->table[ndx].dwForwardDest =
744              table->routes[ndx].dest;
745             pIpForwardTable->table[ndx].dwForwardMask =
746              table->routes[ndx].mask;
747             pIpForwardTable->table[ndx].dwForwardPolicy = 0;
748             pIpForwardTable->table[ndx].dwForwardNextHop =
749              table->routes[ndx].gateway;
750             /* FIXME: this type is appropriate for local interfaces; may not
751                always be appropriate */
752             pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
753             /* FIXME: other protos might be appropriate, e.g. the default route
754                is typically set with MIB_IPPROTO_NETMGMT instead */
755             pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
756             /* punt on age and AS */
757             pIpForwardTable->table[ndx].dwForwardAge = 0;
758             pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
759             pIpForwardTable->table[ndx].dwForwardMetric1 =
760              table->routes[ndx].metric;
761             /* rest of the metrics are 0.. */
762             pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
763             pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
764             pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
765             pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
766           }
767           ret = NO_ERROR;
768         }
769         free(table);
770       }
771       else
772         ret = ERROR_OUTOFMEMORY;
773     }
774   }
775   return ret;
776 }
777
778
779 /******************************************************************
780  *    GetIpNetTable (IPHLPAPI.@)
781  *
782  *
783  * PARAMS
784  *
785  *  pIpNetTable [In/Out]
786  *  pdwSize [In/Out]
787  *  bOrder [In]
788  *
789  * RETURNS
790  *
791  *  DWORD
792  *
793  */
794 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
795 {
796   DWORD ret;
797
798   if (!pdwSize)
799     ret = ERROR_INVALID_PARAMETER;
800   else {
801     DWORD numEntries = getNumArpEntries();
802     ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
803      sizeof(MIB_IPNETROW);
804
805     if (!pIpNetTable || *pdwSize < size) {
806       *pdwSize = size;
807       ret = ERROR_INSUFFICIENT_BUFFER;
808     }
809     else {
810       PMIB_IPNETTABLE table = getArpTable();
811
812       if (table) {
813         size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
814          sizeof(MIB_IPNETROW);
815         if (*pdwSize < size) {
816           *pdwSize = size;
817           ret = ERROR_INSUFFICIENT_BUFFER;
818         }
819         else {
820           if (bOrder)
821             FIXME(":order not implemented");
822           memcpy(pIpNetTable, table, size);
823           ret = NO_ERROR;
824         }
825         free(table);
826       }
827       else
828         ret = ERROR_OUTOFMEMORY;
829     }
830   }
831   return ret;
832 }
833
834
835 /******************************************************************
836  *    GetIpStatistics (IPHLPAPI.@)
837  *
838  *
839  * PARAMS
840  *
841  *  pStats [In/Out]
842  *
843  * RETURNS
844  *
845  *  DWORD
846  *
847  */
848 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
849 {
850   return getIPStats(pStats);
851 }
852
853
854 /******************************************************************
855  *    GetNetworkParams (IPHLPAPI.@)
856  *
857  *
858  * PARAMS
859  *
860  *  pFixedInfo [In/Out]
861  *  pOutBufLen [In/Out]
862  *
863  * RETURNS
864  *
865  *  DWORD
866  *
867  */
868 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
869 {
870   DWORD size;
871
872   if (!pOutBufLen)
873     return ERROR_INVALID_PARAMETER;
874
875   size = sizeof(FIXED_INFO) + min(1, (_res.nscount  - 1) *
876    sizeof(IP_ADDR_STRING));
877   if (!pFixedInfo || *pOutBufLen < size) {
878     *pOutBufLen = size;
879     return ERROR_BUFFER_OVERFLOW;
880   }
881
882   memset(pFixedInfo, 0, size);
883   size = sizeof(pFixedInfo->HostName);
884   GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size);
885   size = sizeof(pFixedInfo->DomainName);
886   GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size);
887   if (_res.nscount > 0) {
888     PIP_ADDR_STRING ptr;
889     int i;
890
891     for (i = 0, ptr = &pFixedInfo->DnsServerList; i < _res.nscount;
892      i++, ptr = ptr->Next) {
893       toIPAddressString(_res.nsaddr_list[i].sin_addr.s_addr,
894        ptr->IpAddress.String);
895       ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDRESS_STRING));
896     }
897   }
898   /* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
899      I suppose could also check for a listener on port 53 to set EnableDns */
900   return NO_ERROR;
901 }
902
903
904 /******************************************************************
905  *    GetNumberOfInterfaces (IPHLPAPI.@)
906  *
907  *
908  * PARAMS
909  *
910  *  pdwNumIf [In/Out]
911  *
912  * RETURNS
913  *
914  *  DWORD
915  *
916  */
917 DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
918 {
919   DWORD ret;
920
921   if (!pdwNumIf)
922     ret = ERROR_INVALID_PARAMETER;
923   else {
924     *pdwNumIf = getNumInterfaces();
925     ret = NO_ERROR;
926   }
927   return ret;
928 }
929
930
931 /******************************************************************
932  *    GetPerAdapterInfo (IPHLPAPI.@)
933  *
934  *
935  * PARAMS
936  *
937  *  IfIndex [In]
938  *  pPerAdapterInfo [In/Out]
939  *  pOutBufLen [In/Out]
940  *
941  * RETURNS
942  *
943  *  DWORD
944  *
945  */
946 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
947 {
948   FIXME(":stub\n");
949   /* marking Win2K+ functions not supported */
950   return ERROR_NOT_SUPPORTED;
951 }
952
953
954 /******************************************************************
955  *    GetRTTAndHopCount (IPHLPAPI.@)
956  *
957  *
958  * PARAMS
959  *
960  *  DestIpAddress [In]
961  *  HopCount [In/Out]
962  *  MaxHops [In]
963  *  RTT [In/Out]
964  *
965  * RETURNS
966  *
967  *  BOOL
968  *
969  */
970 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
971 {
972   FIXME(":stub\n");
973   return (BOOL) 0;
974 }
975
976
977 /******************************************************************
978  *    GetTcpStatistics (IPHLPAPI.@)
979  *
980  *
981  * PARAMS
982  *
983  *  pStats [In/Out]
984  *
985  * RETURNS
986  *
987  *  DWORD
988  *
989  */
990 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
991 {
992   return getTCPStats(pStats);
993 }
994
995
996 /******************************************************************
997  *    GetTcpTable (IPHLPAPI.@)
998  *
999  *
1000  * PARAMS
1001  *
1002  *  pTcpTable [In/Out]
1003  *  pdwSize [In/Out]
1004  *  bOrder [In]
1005  *
1006  * RETURNS
1007  *
1008  *  DWORD
1009  *
1010  */
1011 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
1012 {
1013   DWORD ret;
1014
1015   if (!pdwSize)
1016     ret = ERROR_INVALID_PARAMETER;
1017   else {
1018     DWORD numEntries = getNumTcpEntries();
1019     ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW);
1020
1021     if (!pTcpTable || *pdwSize < size) {
1022       *pdwSize = size;
1023       ret = ERROR_INSUFFICIENT_BUFFER;
1024     }
1025     else {
1026       PMIB_TCPTABLE table = getTcpTable();
1027
1028       if (table) {
1029         size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
1030          sizeof(MIB_TCPROW);
1031         if (*pdwSize < size) {
1032           *pdwSize = size;
1033           ret = ERROR_INSUFFICIENT_BUFFER;
1034         }
1035         else {
1036           if (bOrder)
1037             FIXME(":order not implemented");
1038           memcpy(pTcpTable, table, size);
1039           ret = NO_ERROR;
1040         }
1041         free(table);
1042       }
1043       else
1044         ret = ERROR_OUTOFMEMORY;
1045     }
1046   }
1047   return ret;
1048 }
1049
1050
1051 /******************************************************************
1052  *    GetUdpStatistics (IPHLPAPI.@)
1053  *
1054  *
1055  * PARAMS
1056  *
1057  *  pStats [In/Out]
1058  *
1059  * RETURNS
1060  *
1061  *  DWORD
1062  *
1063  */
1064 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
1065 {
1066   return getUDPStats(pStats);
1067 }
1068
1069
1070 /******************************************************************
1071  *    GetUdpTable (IPHLPAPI.@)
1072  *
1073  *
1074  * PARAMS
1075  *
1076  *  pUdpTable [In/Out]
1077  *  pdwSize [In/Out]
1078  *  bOrder [In]
1079  *
1080  * RETURNS
1081  *
1082  *  DWORD
1083  *
1084  */
1085 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
1086 {
1087   DWORD ret;
1088
1089   if (!pdwSize)
1090     ret = ERROR_INVALID_PARAMETER;
1091   else {
1092     DWORD numEntries = getNumUdpEntries();
1093     ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW);
1094
1095     if (!pUdpTable || *pdwSize < size) {
1096       *pdwSize = size;
1097       ret = ERROR_INSUFFICIENT_BUFFER;
1098     }
1099     else {
1100       PMIB_UDPTABLE table = getUdpTable();
1101
1102       if (table) {
1103         size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
1104          sizeof(MIB_UDPROW);
1105         if (*pdwSize < size) {
1106           *pdwSize = size;
1107           ret = ERROR_INSUFFICIENT_BUFFER;
1108         }
1109         else {
1110           if (bOrder)
1111             FIXME(":order not implemented");
1112           memcpy(pUdpTable, table, size);
1113           ret = NO_ERROR;
1114         }
1115         free(table);
1116       }
1117       else
1118         ret = ERROR_OUTOFMEMORY;
1119     }
1120   }
1121   return ret;
1122 }
1123
1124
1125 /******************************************************************
1126  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
1127  *
1128  *
1129  * PARAMS
1130  *
1131  *  pIPIfInfo [In/Out]
1132  *  dwOutBufLen [In/Out]
1133  *
1134  * RETURNS
1135  *
1136  *  DWORD
1137  *
1138  */
1139 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
1140 {
1141   /* a unidirectional adapter?? not bloody likely! */
1142   return ERROR_NOT_SUPPORTED;
1143 }
1144
1145
1146 /******************************************************************
1147  *    IpReleaseAddress (IPHLPAPI.@)
1148  *
1149  *
1150  * PARAMS
1151  *
1152  *  AdapterInfo [In/Out]
1153  *
1154  * RETURNS
1155  *
1156  *  DWORD
1157  *
1158  */
1159 DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1160 {
1161   /* not a stub, never going to support this (and I never mark an adapter as
1162      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1163   return ERROR_NOT_SUPPORTED;
1164 }
1165
1166
1167 /******************************************************************
1168  *    IpRenewAddress (IPHLPAPI.@)
1169  *
1170  *
1171  * PARAMS
1172  *
1173  *  AdapterInfo [In/Out]
1174  *
1175  * RETURNS
1176  *
1177  *  DWORD
1178  *
1179  */
1180 DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
1181 {
1182   /* not a stub, never going to support this (and I never mark an adapter as
1183      DHCP enabled, see GetAdaptersInfo, so this should never get called) */
1184   return ERROR_NOT_SUPPORTED;
1185 }
1186
1187
1188 /******************************************************************
1189  *    NotifyAddrChange (IPHLPAPI.@)
1190  *
1191  *
1192  * PARAMS
1193  *
1194  *  Handle [In/Out]
1195  *  overlapped [In/Out]
1196  *
1197  * RETURNS
1198  *
1199  *  DWORD
1200  *
1201  */
1202 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1203 {
1204   FIXME(":stub\n");
1205   /* marking Win2K+ functions not supported */
1206   return ERROR_NOT_SUPPORTED;
1207 }
1208
1209
1210 /******************************************************************
1211  *    NotifyRouteChange (IPHLPAPI.@)
1212  *
1213  *
1214  * PARAMS
1215  *
1216  *  Handle [In/Out]
1217  *  overlapped [In/Out]
1218  *
1219  * RETURNS
1220  *
1221  *  DWORD
1222  *
1223  */
1224 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
1225 {
1226   FIXME(":stub\n");
1227   /* marking Win2K+ functions not supported */
1228   return ERROR_NOT_SUPPORTED;
1229 }
1230
1231
1232 /******************************************************************
1233  *    SendARP (IPHLPAPI.@)
1234  *
1235  *
1236  * PARAMS
1237  *
1238  *  DestIP [In]
1239  *  SrcIP [In]
1240  *  pMacAddr [In/Out]
1241  *  PhyAddrLen [In/Out]
1242  *
1243  * RETURNS
1244  *
1245  *  DWORD
1246  *
1247  */
1248 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
1249 {
1250   FIXME(":stub\n");
1251   /* marking Win2K+ functions not supported */
1252   return ERROR_NOT_SUPPORTED;
1253 }
1254
1255
1256 /******************************************************************
1257  *    SetIfEntry (IPHLPAPI.@)
1258  *
1259  *
1260  * PARAMS
1261  *
1262  *  pIfRow [In/Out]
1263  *
1264  * RETURNS
1265  *
1266  *  DWORD
1267  *
1268  */
1269 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
1270 {
1271   /* this is supposed to set an administratively interface up or down.
1272      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
1273      this sort of down is indistinguishable from other sorts of down (e.g. no
1274      link). */
1275   FIXME(":stub\n");
1276   return ERROR_NOT_SUPPORTED;
1277 }
1278
1279
1280 /******************************************************************
1281  *    SetIpForwardEntry (IPHLPAPI.@)
1282  *
1283  *
1284  * PARAMS
1285  *
1286  *  pRoute [In/Out]
1287  *
1288  * RETURNS
1289  *
1290  *  DWORD
1291  *
1292  */
1293 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
1294 {
1295   /* this is to add a route entry, how's it distinguishable from
1296      CreateIpForwardEntry?
1297      could use SIOCADDRT, not sure I want to */
1298   FIXME(":stub\n");
1299   return (DWORD) 0;
1300 }
1301
1302
1303 /******************************************************************
1304  *    SetIpNetEntry (IPHLPAPI.@)
1305  *
1306  *
1307  * PARAMS
1308  *
1309  *  pArpEntry [In/Out]
1310  *
1311  * RETURNS
1312  *
1313  *  DWORD
1314  *
1315  */
1316 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
1317 {
1318   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
1319   FIXME(":stub\n");
1320   return (DWORD) 0;
1321 }
1322
1323
1324 /******************************************************************
1325  *    SetIpStatistics (IPHLPAPI.@)
1326  *
1327  *
1328  * PARAMS
1329  *
1330  *  pIpStats [In/Out]
1331  *
1332  * RETURNS
1333  *
1334  *  DWORD
1335  *
1336  */
1337 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
1338 {
1339   FIXME(":stub\n");
1340   return (DWORD) 0;
1341 }
1342
1343
1344 /******************************************************************
1345  *    SetIpTTL (IPHLPAPI.@)
1346  *
1347  *
1348  * PARAMS
1349  *
1350  *  nTTL [In]
1351  *
1352  * RETURNS
1353  *
1354  *  DWORD
1355  *
1356  */
1357 DWORD WINAPI SetIpTTL(UINT nTTL)
1358 {
1359   /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I
1360      want to.  Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */
1361   FIXME(":stub\n");
1362   return (DWORD) 0;
1363 }
1364
1365
1366 /******************************************************************
1367  *    SetTcpEntry (IPHLPAPI.@)
1368  *
1369  *
1370  * PARAMS
1371  *
1372  *  pTcpRow [In/Out]
1373  *
1374  * RETURNS
1375  *
1376  *  DWORD
1377  *
1378  */
1379 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
1380 {
1381   FIXME(":stub\n");
1382   return (DWORD) 0;
1383 }
1384
1385
1386 /******************************************************************
1387  *    UnenableRouter (IPHLPAPI.@)
1388  *
1389  *
1390  * PARAMS
1391  *
1392  *  pOverlapped [In/Out]
1393  *  lpdwEnableCount [In/Out]
1394  *
1395  * RETURNS
1396  *
1397  *  DWORD
1398  *
1399  */
1400 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
1401 {
1402   FIXME(":stub\n");
1403   /* could echo "0" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
1404      could map EACCESS to ERROR_ACCESS_DENIED, I suppose
1405      marking Win2K+ functions not supported */
1406   return ERROR_NOT_SUPPORTED;
1407 }