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