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