patches/wine-03-iphlpapi.diff
author jurikm
Sun, 12 Feb 2012 14:04:10 +0000
changeset 8245 383896da4129
parent 1650 2486e311009b
permissions -rw-r--r--
SFEsauerbraten.spec: add IPS package name

diff -urN wine-1.1.13.orig/configure.ac wine-1.1.13/configure.ac
--- wine-1.1.13.orig/configure.ac	2009-01-16 17:28:07.000000000 +0100
+++ wine-1.1.13/configure.ac	2009-01-24 18:49:24.000000000 +0100
@@ -272,9 +272,11 @@
 	getopt.h \
 	grp.h \
 	ieeefp.h \
+	inet/ip.h \
 	io.h \
 	jack/jack.h \
 	jpeglib.h \
+	kstat.h \
 	lber.h \
 	lcms.h \
 	lcms/lcms.h \
@@ -319,6 +321,7 @@
 	soundcard.h \
 	stdint.h \
 	strings.h \
+	stropts.h \
 	sys/asoundlib.h \
 	sys/cdio.h \
 	sys/elf32.h \
@@ -350,10 +353,13 @@
 	sys/sockio.h \
 	sys/soundcard.h \
 	sys/statvfs.h \
+	sys/stream.h \
 	sys/strtio.h \
 	sys/syscall.h \
+	sys/tihdr.h \
 	sys/time.h \
 	sys/times.h \
+	sys/tiuser.h \
 	sys/uio.h \
 	sys/un.h \
 	sys/utsname.h \
@@ -1040,6 +1046,39 @@
     LIBS="$ac_save_LIBS"
 fi
 
+dnl **** Check for Solaris kstat library ***
+AC_SUBST(KSTATLIBS,"")
+if test "$ac_cv_header_kstat_h" = "yes"
+then
+    AC_CHECK_LIB(kstat, kstat_open,
+        [AC_DEFINE(HAVE_KSTAT, 1, [Define if you have the Solaris kstat library and header])
+         KSTATLIBS="-lkstat"])
+fi
+
+dnl **** Check for STREAMS Transport Provider Interface (TPI) ***
+if test "$ac_cv_header_stropts_h" = "yes" -a "$ac_cv_header_sys_stream_h" = "yes" -a \
+    "$ac_cv_header_sys_tihdr_h" = "yes" -a "$ac_cv_header_sys_tiuser_h" = "yes" -a \
+    "$ac_cv_header_inet_ip_h" = "yes"
+then
+    AC_CACHE_CHECK([for the STREAMS Transport Provider Interface (TPI)],
+        ac_cv_c_streams_tpi,
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <stropts.h>
+#include <sys/stream.h>
+#include <sys/tihdr.h>
+#include <sys/tiuser.h>
+#include <inet/ip.h>
+struct T_optmgmt_req *tor = (struct T_optmgmt_req *)NULL;
+        ]], [[ioctl(1, I_PUSH, NULL)]])], [ac_cv_c_streams_tpi=yes],[ac_cv_c_streams_tpi=no])
+   )
+
+   if test "$ac_cv_c_streams_tpi" = "yes"
+   then
+      AC_DEFINE(HAVE_STREAMS_TPI, 1,
+                [Define if you have the STREAMS Transport Provider Interface (TPI)])
+   fi
+fi
+
 dnl **** Check for LittleCMS ***
 AC_SUBST(LCMSLIBS,"")
 if test "$ac_cv_header_lcms_h" = "yes" -o "$ac_cv_header_lcms_lcms_h" = "yes"
diff -urN wine-1.1.13.orig/dlls/iphlpapi/Makefile.in wine-1.1.13/dlls/iphlpapi/Makefile.in
--- wine-1.1.13.orig/dlls/iphlpapi/Makefile.in	2009-01-16 17:28:07.000000000 +0100
+++ wine-1.1.13/dlls/iphlpapi/Makefile.in	2009-01-24 18:50:35.000000000 +0100
@@ -5,7 +5,7 @@
 MODULE    = iphlpapi.dll
 IMPORTLIB = iphlpapi
 IMPORTS   = advapi32 kernel32
-EXTRALIBS = @RESOLVLIBS@
+EXTRALIBS = @RESOLVLIBS@ @KSTATLIBS@
 
 C_SRCS = \
 	icmp.c \
diff -urN wine-1.1.13.orig/dlls/iphlpapi/ipstats.c wine-1.1.13/dlls/iphlpapi/ipstats.c
--- wine-1.1.13.orig/dlls/iphlpapi/ipstats.c	2009-01-16 17:28:07.000000000 +0100
+++ wine-1.1.13/dlls/iphlpapi/ipstats.c	2009-01-24 22:01:41.756459359 +0100
@@ -1,5 +1,21 @@
 /* Copyright (C) 2003,2006 Juan Lang
  * Copyright (C) 2007 TransGaming Technologies Inc.
+ * Copyright (c) 2008 Albert Lee <[email protected]>
+ * Portions derived from netstat.c with the following copyright:
+ * Copyright (c) Sun Microsystems, Inc.  1994. All rights reserved.
+ *
+ * License is granted to copy, to use, and to make and to use derivative works
+ * for research and evaluation purposes, provided that Sun Microsystems is
+ * acknowledged in all documentation pertaining to any such copy or
+ * derivative work. Sun Microsystems grants no other licenses expressed or
+ * implied. The Sun Microsystems  trade name should not be used in any
+ * advertising without its written permission.
+ *
+ * SUN MICROSYSTEMS MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS
+ * SOFTWARE FOR ANY PARTICULAR PURPOSE.  The software is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this software.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,7 +32,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
  * This file implements statistics getting using the /proc filesystem exported
- * by Linux, and maybe other OSes.
+ * by Linux, BSD sysctls, Solaris libkstat, and TPI on platforms with STREAMS.
  */
 
 #include "config.h"
@@ -102,6 +118,32 @@
 #include <sys/sysctl.h>
 #endif
 
+#ifdef HAVE_KSTAT_H
+#include <kstat.h>
+#endif
+
+#ifdef HAVE_STROPTS_H
+#include <stropts.h>
+#ifdef HAVE_SYS_STREAM_H
+#include <sys/stream.h>
+#endif
+#ifdef HAVE_SYS_TIHDR_H
+#include <sys/tihdr.h>
+#endif
+#ifdef HAVE_SYS_TIUSER_H
+#include <sys/tiuser.h>
+#endif
+#ifdef HAVE_INET_IP_H
+#include <inet/ip.h>
+#ifndef IRE_CACHETABLE
+#define IRE_CACHETABLE (IRE_CACHE|IRE_BROADCAST|IRE_LOCAL|IRE_LOOPBACK)
+#endif
+/* To work around redefined ERR macro */
+#undef ERR
+#define ERR WINE_ERR
+#endif
+#endif
+
 #ifndef ROUNDUP
 #define ROUNDUP(a) \
 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
@@ -136,6 +178,180 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
 
+#ifdef HAVE_KSTAT
+struct kstat_mib_map {
+  const char *name;
+  unsigned int offset;
+};
+#endif
+
+#ifdef HAVE_STREAMS_TPI
+typedef struct mib_item_s {
+  struct mib_item_s *next_item;
+  long group;
+  long mib_id;
+  long length;
+  char *valp;
+} mib_item_t;
+
+static int mibopen(void);
+static mib_item_t *mibget(int sd);
+static void mibfree(mib_item_t *);
+
+static const char mib_dev[] = "/dev/arp";
+
+static int mibopen(void)
+{
+   int sd;
+   if ((sd = open(mib_dev, O_RDWR)) < 0)
+   {
+     return -1;
+   }
+
+   if ((ioctl(sd, I_PUSH, "tcp") < 0) ||
+       (ioctl(sd, I_PUSH, "udp") < 0) ||
+       (ioctl(sd, I_PUSH, "icmp") < 0)) {
+     close(sd);
+     return -1;
+   }
+
+   return sd;
+}
+
+static mib_item_t *
+mibget(int sd)
+{
+  char buf[512];
+  int flags;
+  int j, getcode;
+  struct strbuf ctlbuf, databuf;
+  struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
+  struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
+  struct T_error_ack   *tea = (struct T_error_ack *)buf;
+  struct opthdr *req;
+  mib_item_t    *first_item = NULL;
+  mib_item_t    *last_item  = NULL;
+  mib_item_t    *temp;
+
+#ifdef T_SVR4_OPTMGMT_REQ
+  tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
+#else
+  tor->PRIM_type = T_OPTMGMT_REQ;
+#endif
+  tor->OPT_offset = sizeof(struct T_optmgmt_req);
+  tor->OPT_length = sizeof(struct opthdr);
+  tor->MGMT_flags = T_CURRENT;
+
+  req = (struct opthdr *)(tor + 1);
+  req->level = MIB2_IP;
+  req->name = req->len = 0;
+
+  ctlbuf.buf = buf;
+  ctlbuf.maxlen = sizeof(buf);
+  ctlbuf.len = tor->OPT_length + tor->OPT_offset;
+  flags = 0;
+  if (putmsg(sd, &ctlbuf, (struct strbuf *)NULL, flags) == -1)
+  {
+    ERR ("mibget putmsg(ctl) failed\n");
+    goto error_exit;
+  }
+
+  req = (struct opthdr *)(toa + 1);
+  for (j=1; ; j++)
+  {
+    flags = 0;
+    getcode = getmsg(sd, &ctlbuf, (struct strbuf *)NULL, &flags);
+    if (getcode == -1)
+    {
+      ERR ("mibget getmsg(ctl) failed\n");
+      goto error_exit;
+    }
+    if (getcode == 0
+        && ctlbuf.len >= sizeof(struct T_optmgmt_ack)
+        && toa->PRIM_type == T_OPTMGMT_ACK
+        && toa->MGMT_flags == T_SUCCESS
+        && req->len == 0) {
+      return first_item;    /* this is EOD msg */
+    }
+
+    if (ctlbuf.len >= sizeof(struct T_error_ack)
+    && tea->PRIM_type == T_ERROR_ACK) {
+      ERR (
+      "mibget %d gives (%d) T_ERROR_ACK: TLI_error = 0x%lx, UNIX_error = 0x%lx\n",
+        j, getcode, tea->TLI_error, tea->UNIX_error);
+      goto error_exit;
+    }
+
+    if (getcode != MOREDATA
+        || ctlbuf.len < sizeof(struct T_optmgmt_ack)
+        || toa->PRIM_type != T_OPTMGMT_ACK
+        || toa->MGMT_flags != T_SUCCESS)
+    {
+      ERR (
+      "mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %ld\n",
+         j, getcode, ctlbuf.len, toa->PRIM_type);
+      if (toa->PRIM_type == T_OPTMGMT_ACK)
+        ERR (
+        "T_OPTMGMT_ACK: MGMT_flags = 0x%lx, req->len = %ld\n",
+          toa->MGMT_flags, req->len);
+      goto error_exit;
+    }
+
+    temp = (mib_item_t *)HeapAlloc(GetProcessHeap(), 0, sizeof(mib_item_t));
+    if (!temp)
+    {
+      ERR ("mibget malloc failed\n");
+      goto error_exit;
+    }
+    if (last_item)
+      last_item->next_item = temp;
+    else
+      first_item = temp;
+    last_item = temp;
+    last_item->next_item = NULL;
+    last_item->group = req->level;
+    last_item->mib_id = req->name;
+    last_item->length = req->len;
+    last_item->valp = (char *)HeapAlloc(GetProcessHeap(), 0, req->len);
+
+    databuf.maxlen = last_item->length;
+    databuf.buf    = last_item->valp;
+    databuf.len    = 0;
+    flags = 0;
+    getcode = getmsg(sd, (struct strbuf *)NULL, &databuf, &flags);
+    if (getcode == -1)
+    {
+      ERR ("mibget getmsg(data) failed\n");
+      goto error_exit;
+    } else if (getcode != 0)
+    {
+      ERR (
+      "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
+         getcode, databuf.maxlen, databuf.len);
+      goto error_exit;
+    }
+  }
+
+error_exit:;
+  mibfree(first_item);
+  return NULL;
+}
+
+static void
+mibfree(mib_item_t * first_item)
+{
+  mib_item_t *last_item;
+
+  while (first_item) {
+    last_item = first_item;
+    first_item = first_item->next_item;
+    if (last_item->valp)
+      HeapFree(GetProcessHeap(), 0, last_item->valp);
+    HeapFree(GetProcessHeap(), 0, last_item);
+  }
+}
+#endif
+
 DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry)
 {
 #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_IFLIST)
@@ -185,7 +401,73 @@
       }
       HeapFree (GetProcessHeap (), 0, buf);
       return ERROR_NOT_SUPPORTED;
-#else
+#elif defined(HAVE_KSTAT)
+  static const struct kstat_mib_map ifrow_map[] =
+  {
+    { "rbytes", offsetof(MIB_IFROW, dwInOctets) },
+    { "norcvbuf", offsetof(MIB_IFROW, dwInDiscards) },
+    { "ierrors", offsetof(MIB_IFROW, dwInErrors) },
+    { "unknowns", offsetof(MIB_IFROW, dwInUnknownProtos) },
+    { "obytes", offsetof(MIB_IFROW, dwOutOctets) },
+    { "noxmtbuf", offsetof(MIB_IFROW, dwOutDiscards) },
+    { "oerrors", offsetof(MIB_IFROW, dwOutErrors) },
+    { NULL, 0 },
+  };
+
+  kstat_ctl_t *kc;
+  kstat_t *ksp, *mac_ksp;
+  kstat_named_t *knp;
+
+  if (!name || !entry)
+    return ERROR_INVALID_PARAMETER;
+
+  /* get interface stats from driver or mac module
+     no outQLen */
+  kc = kstat_open();
+  ksp = kstat_lookup(kc, NULL, -1, (char *)name);
+  if (ksp)
+  { /* Check if the interface has a MAC, and use that instead */
+    int i;
+    if ((mac_ksp = kstat_lookup(kc, ksp->ks_module, ksp->ks_instance, (char *)"mac")) != NULL)
+      ksp = mac_ksp;
+    kstat_read(kc, ksp, NULL);
+    for (i = 0; ifrow_map[i].name != NULL; i++)
+    {
+      if ((knp = kstat_data_lookup(ksp, (char *)ifrow_map[i].name)) != NULL)
+        *(DWORD *)((char *)entry + ifrow_map[i].offset) = knp->value.ui32;
+    }
+    if ((knp = kstat_data_lookup(ksp, (char *)"ifspeed")) != NULL)
+    {
+      entry->dwSpeed = knp->value.ui64;
+      /* Windows doesn't believe in 10G Ethernet */
+      if (knp->value.ui64 >= ((unsigned long)-1))
+         entry->dwSpeed = ((unsigned long)-1);
+    }
+    if ((knp = kstat_data_lookup(ksp, (char *)"link_up")) != NULL)
+      entry->dwOperStatus = knp->value.ui32 ?
+        MIB_IF_OPER_STATUS_OPERATIONAL : MIB_IF_OPER_STATUS_DISCONNECTED;
+    if ((knp = kstat_data_lookup(ksp, (char *)"multircv")) != NULL)
+      entry->dwInNUcastPkts = knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"brdcstrcv")) != NULL)
+      entry->dwInNUcastPkts += knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"ipackets")) != NULL)
+      entry->dwInUcastPkts = knp->value.ui32 - entry->dwInNUcastPkts;
+    if ((knp = kstat_data_lookup(ksp, (char *)"multixmt")) != NULL)
+      entry->dwOutNUcastPkts = knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"brdcstxmt")) != NULL)
+      entry->dwOutNUcastPkts += knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"opackets")) != NULL)
+      entry->dwOutUcastPkts = knp->value.ui32 - entry->dwOutNUcastPkts;
+    kstat_close(kc);
+  }
+  else
+  {
+    kstat_close(kc);
+    return ERROR_NOT_SUPPORTED;
+  }
+
+  return NO_ERROR;
+#elif defined(__linux__)
   /* get interface stats from /proc/net/dev, no error if can't
      no inUnknownProtos, outNUcastPkts, outQLen */
   FILE *fp;
@@ -332,7 +614,68 @@
   stats->stats.icmpOutStats.dwAddrMaskReps = icmp_stat.icps_outhist[ICMP_MASKREPLY];
 
   return NO_ERROR;
-#else
+#elif defined(HAVE_KSTAT)
+  static const struct kstat_mib_map icmp_map[] =
+  {
+    { "inMsgs", offsetof(MIB_ICMP, stats.icmpInStats.dwMsgs) },
+    { "inErrors", offsetof(MIB_ICMP, stats.icmpInStats.dwErrors) },
+    { "inDestUnreachs", offsetof(MIB_ICMP, stats.icmpInStats.dwDestUnreachs) },
+    { "inTimeExcds", offsetof(MIB_ICMP, stats.icmpInStats.dwTimeExcds) },
+    { "inParmProbs", offsetof(MIB_ICMP, stats.icmpInStats.dwParmProbs) },
+    { "inSrcQuenchs", offsetof(MIB_ICMP, stats.icmpInStats.dwSrcQuenchs) },
+    { "inRedirects", offsetof(MIB_ICMP, stats.icmpInStats.dwRedirects) },
+    { "inEchos", offsetof(MIB_ICMP, stats.icmpInStats.dwEchos) },
+    { "inEchoReps", offsetof(MIB_ICMP, stats.icmpInStats.dwEchoReps) },
+    { "inTimestamps", offsetof(MIB_ICMP, stats.icmpInStats.dwTimestamps) },
+    { "inTimestampReps", offsetof(MIB_ICMP, stats.icmpInStats.dwTimestampReps) },
+    { "inAddrMasks", offsetof(MIB_ICMP, stats.icmpInStats.dwAddrMasks) },
+    { "inAddrMaskReps", offsetof(MIB_ICMP, stats.icmpInStats.dwAddrMaskReps) },
+    { "outMsgs", offsetof(MIB_ICMP, stats.icmpOutStats.dwMsgs) },
+    { "outErrors", offsetof(MIB_ICMP, stats.icmpOutStats.dwErrors) },
+    { "outDestUnreachs", offsetof(MIB_ICMP, stats.icmpOutStats.dwDestUnreachs) },
+    { "outTimeExcds", offsetof(MIB_ICMP, stats.icmpOutStats.dwTimeExcds) },
+    { "outParmProbs", offsetof(MIB_ICMP, stats.icmpOutStats.dwParmProbs) },
+    { "outSrcQuenchs", offsetof(MIB_ICMP, stats.icmpOutStats.dwSrcQuenchs) },
+    { "outRedirects", offsetof(MIB_ICMP, stats.icmpOutStats.dwRedirects) },
+    { "outEchos", offsetof(MIB_ICMP, stats.icmpOutStats.dwEchos) },
+    { "outEchoReps", offsetof(MIB_ICMP, stats.icmpOutStats.dwEchoReps) },
+    { "outTimestamps", offsetof(MIB_ICMP, stats.icmpOutStats.dwTimestamps) },
+    { "outTimestampReps", offsetof(MIB_ICMP, stats.icmpOutStats.dwTimestampReps) },
+    { "outAddrMasks", offsetof(MIB_ICMP, stats.icmpOutStats.dwAddrMasks) },
+    { "outAddrMaskReps", offsetof(MIB_ICMP, stats.icmpOutStats.dwAddrMaskReps) },
+    { NULL, 0 }
+  };
+
+  kstat_ctl_t *kc;
+  kstat_t *ksp;
+  kstat_named_t *knp;
+  int i;
+
+  if (!stats)
+    return ERROR_INVALID_PARAMETER;
+  
+  memset(stats, 0, sizeof(MIB_ICMP));
+
+  kc = kstat_open();
+  ksp = kstat_lookup(kc, (char *)"ip", 0, (char *)"icmp");
+  if (ksp)
+  {
+    kstat_read(kc, ksp, NULL);
+    for (i = 0; icmp_map[i].name != NULL; i++)
+    {
+      if ((knp = kstat_data_lookup(ksp, (char *)icmp_map[i].name)) != NULL)
+        *(DWORD *)((char *)stats + icmp_map[i].offset) = knp->value.ui32;
+    }
+    kstat_close(kc);
+  }
+  else
+  {
+    kstat_close(kc);
+    return ERROR_NOT_SUPPORTED;
+  }
+
+  return NO_ERROR;
+#elif defined(__linux__)
   FILE *fp;
 
   if (!stats)
@@ -517,7 +860,62 @@
   stats->dwReasmReqds = ip_stat.ips_fragments;
 
   return NO_ERROR;
-#else
+#elif defined(HAVE_KSTAT)
+  static const struct kstat_mib_map ipstats_map[] =
+  {
+    { "forwarding", offsetof(MIB_IPSTATS, dwForwarding) },
+    { "defaultTTL", offsetof(MIB_IPSTATS, dwDefaultTTL) },
+    { "inReceives", offsetof(MIB_IPSTATS, dwInReceives) },
+    { "inHdrErrors", offsetof(MIB_IPSTATS, dwInHdrErrors) },
+    { "inAddrErrors", offsetof(MIB_IPSTATS, dwInAddrErrors) },
+    { "forwDatagrams", offsetof(MIB_IPSTATS, dwForwDatagrams) },
+    { "inUnknownProtos", offsetof(MIB_IPSTATS, dwInUnknownProtos) },
+    { "inDiscards", offsetof(MIB_IPSTATS, dwInDiscards) },
+    { "inDelivers", offsetof(MIB_IPSTATS, dwInDelivers) },
+    { "outRequests", offsetof(MIB_IPSTATS, dwOutRequests) },
+    { "routingDiscards", offsetof(MIB_IPSTATS, dwRoutingDiscards) },
+    { "outDiscards", offsetof(MIB_IPSTATS, dwOutDiscards) },
+    { "outNoRoutes", offsetof(MIB_IPSTATS, dwOutNoRoutes) },
+    { "reasmTimeout", offsetof(MIB_IPSTATS, dwReasmTimeout) },
+    { "reasmReqds", offsetof(MIB_IPSTATS, dwReasmReqds) },
+    { "reasmOks", offsetof(MIB_IPSTATS, dwReasmOks) },
+    { "reasmFails", offsetof(MIB_IPSTATS, dwReasmFails) },
+    { "fragOks", offsetof(MIB_IPSTATS, dwFragOks) },
+    { "fragFails", offsetof(MIB_IPSTATS, dwFragFails) },
+    { "fragCreates", offsetof(MIB_IPSTATS, dwFragCreates) },
+    { NULL, 0 }
+  };
+
+  kstat_ctl_t *kc;
+  kstat_t *ksp;
+  kstat_named_t *knp;
+  int i;
+
+  if (!stats)
+    return ERROR_INVALID_PARAMETER;
+
+  memset(stats, 0, sizeof(MIB_IPSTATS));
+
+  kc = kstat_open();
+  ksp = kstat_lookup(kc, (char *)"ip", 0, (char *)"ip");
+  if (ksp)
+  {
+    kstat_read(kc, ksp, NULL);
+    for (i = 0; ipstats_map[i].name != NULL; i++)
+    {
+      if ((knp = kstat_data_lookup(ksp, (char *)ipstats_map[i].name)) != NULL)
+        *(DWORD *)((char *)stats + ipstats_map[i].offset) = knp->value.ui32;
+    }
+    kstat_close(kc);
+  }
+  else
+  {
+    kstat_close(kc);
+    return ERROR_NOT_SUPPORTED;
+  }
+
+  return NO_ERROR;
+#elif defined(__linux__)
   FILE *fp;
 
   if (!stats)
@@ -675,7 +1073,55 @@
 
   return NO_ERROR;
 
-#else
+#elif defined(HAVE_KSTAT)
+  static const struct kstat_mib_map tcpstats_map[] =
+  {
+    { "rtoAlgorithm", offsetof(MIB_TCPSTATS, dwRtoAlgorithm) },
+    { "rtoMin", offsetof(MIB_TCPSTATS, dwRtoMin) },
+    { "rtoMax", offsetof(MIB_TCPSTATS, dwRtoMax) },
+    { "maxConn", offsetof(MIB_TCPSTATS, dwMaxConn) },
+    { "activeOpens", offsetof(MIB_TCPSTATS, dwActiveOpens) },
+    { "passiveOpens", offsetof(MIB_TCPSTATS, dwPassiveOpens) },
+    { "attemptFails", offsetof(MIB_TCPSTATS, dwAttemptFails) },
+    { "estabResets", offsetof(MIB_TCPSTATS, dwEstabResets) },
+    { "currEstab", offsetof(MIB_TCPSTATS, dwCurrEstab) },
+    { "inSegs", offsetof(MIB_TCPSTATS, dwInSegs) },
+    { "outSegs", offsetof(MIB_TCPSTATS, dwOutSegs) },
+    { "retransSegs", offsetof(MIB_TCPSTATS, dwRetransSegs) },
+    { "inErrs", offsetof(MIB_TCPSTATS, dwInErrs) },
+    { "outRsts", offsetof(MIB_TCPSTATS, dwOutRsts) },
+    { NULL, 0 }
+  };
+  kstat_ctl_t *kc;
+  kstat_t *ksp;
+  kstat_named_t *knp;
+  int i;
+
+  if (!stats)
+    return ERROR_INVALID_PARAMETER;
+
+  memset(stats, 0, sizeof(MIB_TCPSTATS));
+
+  kc = kstat_open();
+  ksp = kstat_lookup(kc, (char *)"tcp", 0, (char *)"tcp");
+  if (ksp)
+  {
+    kstat_read(kc, ksp, NULL);
+    for (i = 0; tcpstats_map[i].name != NULL; i++)
+    {
+      if ((knp = kstat_data_lookup(ksp, (char *)tcpstats_map[i].name)) != NULL)
+        *(DWORD *)((char *)stats + tcpstats_map[i].offset) = knp->value.ui32;
+    }
+    kstat_close(kc);
+  }
+  else
+  {
+    kstat_close(kc);
+    return ERROR_NOT_SUPPORTED;
+  }
+
+  return NO_ERROR;
+#elif defined(__linux__)
   FILE *fp;
 
   if (!stats)
@@ -796,7 +1242,37 @@
   stats->dwNumAddrs = getNumUdpEntries();
 
   return NO_ERROR;
-#else
+#elif defined(HAVE_KSTAT)
+  kstat_ctl_t *kc;
+  kstat_t *ksp;
+  kstat_named_t *knp;
+
+  if (!stats)
+    return ERROR_INVALID_PARAMETER;
+
+  memset(stats, 0, sizeof(MIB_UDPSTATS));
+
+  kc = kstat_open();
+  ksp = kstat_lookup(kc, (char *)"udp", 0, (char *)"udp");
+  if (ksp)
+  {
+    kstat_read(kc, ksp, NULL);
+    if ((knp = kstat_data_lookup(ksp, (char *)"inDatagrams")) != NULL)
+      stats->dwInDatagrams = knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"inErrors")) != NULL)
+      stats->dwInErrors = knp->value.ui32;
+    if ((knp = kstat_data_lookup(ksp, (char *)"outDatagrams")) != NULL)
+      stats->dwOutDatagrams = knp->value.ui32;
+    kstat_close(kc);
+  }
+  else
+  {
+    kstat_close(kc);
+    return ERROR_NOT_SUPPORTED;
+  }
+
+  return NO_ERROR;
+#elif defined(__linux__)
   FILE *fp;
 
   if (!stats)
@@ -855,6 +1331,7 @@
 #endif
 }
 
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H) || defined(__linux__)
 static DWORD getNumWithOneHeader(const char *filename)
 {
 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
@@ -975,6 +1452,7 @@
   return ret;
 #endif
 }
+#endif
 
 DWORD getNumRoutes(void)
 {
@@ -1023,8 +1501,46 @@
 
    HeapFree (GetProcessHeap (), 0, buf);
    return RouteCount;
-#else
+#elif defined(HAVE_STREAMS_TPI)
+   DWORD RouteCount = 0;
+   int sd;
+   mib_item_t *head, *item;
+   mib2_ipRouteEntry_t *rp;
+
+   if ((sd = mibopen()) < 0)
+   {
+     ERR ("Unable to open %s to count routes!\n", mib_dev);
+     return 0;
+   }
+
+   if ((head = mibget(sd)) == NULL)
+   {
+     close(sd);
+     return 0;
+   }
+
+   for (item = head; item; item = item->next_item)
+   {
+     if ((item->group != MIB2_IP) || (item->mib_id != MIB2_IP_21))
+       continue;
+
+     for (rp = (mib2_ipRouteEntry_t *)item->valp;
+          (char *)rp < (char *)item->valp + item->length; rp++)
+     {
+       if ((rp->ipRouteInfo.re_ire_type & IRE_CACHETABLE) != 0)
+         continue;
+
+       RouteCount++;
+     }
+   }
+
+   mibfree(head);
+   close(sd);
+   return RouteCount;
+#elif defined(__linux__)
    return getNumWithOneHeader("/proc/net/route");
+#else
+   return 0;
 #endif
 }
 
@@ -1053,21 +1569,21 @@
        if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0)
        {
           ERR ("sysctl 1 failed!\n");
-          HeapFree (GetProcessHeap (), 0, table);
+          HeapFree (heap, 0, table);
           return NO_ERROR;
        }
 
        buf = HeapAlloc (GetProcessHeap (), 0, needed);
        if (!buf)
        {
-          HeapFree (GetProcessHeap (), 0, table);
+          HeapFree (heap, 0, table);
           return ERROR_OUTOFMEMORY;
        }
 
        if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0)
        {
           ERR ("sysctl 2 failed!\n");
-          HeapFree (GetProcessHeap (), 0, table);
+          HeapFree (heap, 0, table);
           HeapFree (GetProcessHeap (), 0, buf);
           return NO_ERROR;
        }
@@ -1158,7 +1674,76 @@
 
        HeapFree (GetProcessHeap (), 0, buf);
        ret = NO_ERROR;
-#else
+#elif defined(HAVE_STREAMS_TPI)
+       DWORD RouteCount = 0;
+       int sd;
+       mib_item_t *head, *item;
+       mib2_ipRouteEntry_t *rp;
+
+       if ((sd = mibopen()) < 0)
+       {
+         ERR ("Unable to open %s to list routes!\n", mib_dev);
+         HeapFree(heap, 0, table);
+         return ERROR_NOT_SUPPORTED;
+       }
+
+       if ((head = mibget(sd)) == NULL)
+       {
+         HeapFree(heap, 0, table);
+         close(sd);
+         return ERROR_NOT_SUPPORTED;
+       }
+
+       for (item = head; item; item = item->next_item)
+       {
+         if ((item->group != MIB2_IP) || (item->mib_id != MIB2_IP_21))
+           continue;
+
+         for (rp = (mib2_ipRouteEntry_t *)item->valp;
+              (char *)rp < (char *)item->valp + item->length; rp++) {
+           char name[IF_NAMESIZE];
+           int len;
+           DWORD index;
+
+           if (RouteCount == numRoutes) /* in case of race */
+             break;
+
+           if ((rp->ipRouteInfo.re_ire_type & IRE_CACHETABLE) != 0)
+             continue;
+
+           memset(&table->table[RouteCount], 0, sizeof(MIB_IPFORWARDROW));
+
+           table->table[RouteCount].dwForwardDest = rp->ipRouteDest;
+           table->table[RouteCount].dwForwardMask = rp->ipRouteMask;
+           table->table[RouteCount].dwForwardNextHop = rp->ipRouteNextHop;
+             
+           len = rp->ipRouteIfIndex.o_length;
+           if (len > IF_NAMESIZE - 1)
+             len = IF_NAMESIZE - 1;
+           memcpy(name, rp->ipRouteIfIndex.o_bytes, len);
+           name[len] = '\0';
+           if (getInterfaceIndexByName(name, &index) == NO_ERROR)
+             table->table[RouteCount].dwForwardIfIndex = index;
+
+           table->table[RouteCount].dwForwardType = rp->ipRouteType;
+           table->table[RouteCount].dwForwardProto = rp->ipRouteProto;
+           table->table[RouteCount].dwForwardAge = rp->ipRouteAge;
+           table->table[RouteCount].dwForwardMetric1 = rp->ipRouteMetric1;
+           table->table[RouteCount].dwForwardMetric2 = rp->ipRouteMetric2;
+           table->table[RouteCount].dwForwardMetric3 = rp->ipRouteMetric3;
+           table->table[RouteCount].dwForwardMetric4 = rp->ipRouteMetric4;
+           table->table[RouteCount].dwForwardMetric5 = rp->ipRouteMetric5;
+
+           RouteCount++;
+         }
+       }
+
+       *ppIpForwardTable = table;
+       table->dwNumEntries = RouteCount;
+       ret = NO_ERROR;
+       mibfree(head);
+       close(sd);
+#elif defined(__linux__)
       FILE *fp;
 
       ret = NO_ERROR;
@@ -1243,6 +1828,9 @@
         ERR ("unimplemented!\n");
         return ERROR_NOT_SUPPORTED;
       }
+#else
+      ERR ("unimplemented!\n");
+      return ERROR_NOT_SUPPORTED; 
 #endif
     }
     else
@@ -1292,8 +1880,42 @@
   }
   HeapFree (GetProcessHeap (), 0, buf);
   return arpEntries;
-#endif
+#elif defined(HAVE_STREAMS_TPI)
+   DWORD ArpCount = 0;
+   int sd;
+   mib_item_t *head, *item;
+   mib2_ipNetToMediaEntry_t *np;
+
+   if ((sd = mibopen()) < 0)
+   {
+     ERR ("Unable to open %s to count ARP entries!\n", mib_dev);
+     return 0;
+   }
+
+   if ((head = mibget(sd)) == NULL) {
+     close(sd);
+     return 0;
+   }
+
+   for (item = head; item; item = item->next_item)
+   {
+     if ((item->group != MIB2_IP) || (item->mib_id != MIB2_IP_MEDIA))
+       continue;
+
+     for (np = (mib2_ipNetToMediaEntry_t *)item->valp;
+            (char *)np < (char *)item->valp + item->length; np++)
+       ArpCount++;
+   }
+
+   mibfree(head);
+   close(sd);
+   return ArpCount;
+#elif defined(__linux__)
   return getNumWithOneHeader("/proc/net/arp");
+#else
+  ERR ("unimplemented!\n");
+  return ERROR_NOT_SUPPORTED;
+#endif
 }
 
 DWORD getArpTable(PMIB_IPNETTABLE *ppIpNetTable, HANDLE heap, DWORD flags)
@@ -1375,7 +1997,76 @@
     else
         ret = ERROR_OUTOFMEMORY;
   return ret;
-#endif
+#elif defined(HAVE_STREAMS_TPI)
+    if (table)
+    {
+      DWORD ArpCount = 0;
+      int sd;
+      mib_item_t *head, *item;
+      mib2_ipNetToMediaEntry_t *np;
+ 
+      if ((sd = mibopen()) < 0)
+      {
+        ERR ("Unable to open %s to count ARP entries!\n", mib_dev);
+        HeapFree(heap, 0, table);
+        return ERROR_NOT_SUPPORTED;
+      }
+
+      if ((head = mibget(sd)) == NULL)
+      {
+        HeapFree(heap, 0, table);
+        close(sd);
+        return ERROR_NOT_SUPPORTED;
+      }
+
+      for (item = head; item; item = item->next_item)
+      {
+        if ((item->group != MIB2_IP) || (item->mib_id != MIB2_IP_MEDIA))
+          continue;
+
+        for (np = (mib2_ipNetToMediaEntry_t *)item->valp;
+               (char *)np < (char *)item->valp + item->length; np++) {
+          char name[IF_NAMESIZE];
+          int len;
+          DWORD index;
+
+          if (ArpCount == numEntries) /* in case of race */
+            break;
+
+          memset(&table->table[ArpCount], 0, sizeof(MIB_IPNETROW));
+
+          len = np->ipNetToMediaIfIndex.o_length;
+          if (len > IF_NAMESIZE - 1)
+            len = IF_NAMESIZE - 1;
+          memcpy(name, np->ipNetToMediaIfIndex.o_bytes, len);
+          name[len] = '\0';
+          if (getInterfaceIndexByName(name, &index) == NO_ERROR)
+            table->table[ArpCount].dwIndex = index;
+
+          len = np->ipNetToMediaPhysAddress.o_length;
+          if (len > MAXLEN_PHYSADDR)
+             len = MAXLEN_PHYSADDR;
+          table->table[ArpCount].dwPhysAddrLen = len;
+          memcpy(table->table[ArpCount].bPhysAddr, np->ipNetToMediaPhysAddress.o_bytes, len);
+
+          table->table[ArpCount].dwAddr = np->ipNetToMediaNetAddress;
+          table->table[ArpCount].dwType = np->ipNetToMediaType;
+
+          ArpCount++;
+        }
+      }
+
+      *ppIpNetTable = table;
+      table->dwNumEntries = ArpCount;
+      ret = NO_ERROR;
+      mibfree(head);
+      close(sd);
+    }
+    else
+      ret = ERROR_OUTOFMEMORY;
+  }
+  return ret;
+#elif defined(__linux__)
 
     if (table) {
       FILE *fp;
@@ -1452,14 +2143,52 @@
       ret = ERROR_OUTOFMEMORY;
   }
   return ret;
+#else
+  ERR ("unimplemented!\n");
+  return ERROR_NOT_SUPPORTED;
+#endif
 }
 
 DWORD getNumUdpEntries(void)
 {
 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
    return getNumWithOneHeader ("net.inet.udp.pcblist");
-#else
+#elif defined(HAVE_STREAMS_TPI)
+   DWORD UdpCount = 0;
+   int sd;
+   mib_item_t *head, *item;
+   mib2_udpEntry_t *ude;
+
+   if ((sd = mibopen()) < 0)
+   {
+     ERR ("Unable to open %s to count UDP entries!\n", mib_dev);
+     return 0;
+   }
+
+   if ((head = mibget(sd)) == NULL)
+   {
+     close(sd);
+     return 0;
+   }
+
+   for (item = head; item; item = item->next_item)
+   {
+     if ((item->group != MIB2_UDP) || (item->mib_id != MIB2_UDP_ENTRY))
+       continue;
+
+     for (ude = (mib2_udpEntry_t *)item->valp;
+            (char *)ude < (char *)item->valp + item->length; ude++) {
+       UdpCount++;
+     }
+   }
+
+   mibfree(head);
+   close(sd);
+   return UdpCount;
+#elif defined(__linux__)
   return getNumWithOneHeader("/proc/net/udp");
+#else
+  return 0;
 #endif
 }
 
@@ -1467,10 +2196,70 @@
 {
   DWORD ret;
 
-#if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
-  ERR ("unimplemented!\n");
-  return ERROR_NOT_SUPPORTED;
-#endif
+#ifdef HAVE_STREAMS_TPI
+  if (!ppUdpTable)
+    ret = ERROR_INVALID_PARAMETER;
+  else {
+    DWORD numEntries = getNumUdpEntries();
+    DWORD size = sizeof(MIB_UDPTABLE);
+    PMIB_UDPTABLE table;
+
+    if (numEntries > 1)
+      size += (numEntries - 1) * sizeof(MIB_IPNETROW);
+    table = HeapAlloc(heap, flags, size);
+    if (table)
+    {
+      DWORD UdpCount = 0;
+      int sd;
+      mib_item_t *head, *item;
+      mib2_udpEntry_t *ude;
+
+      if ((sd = mibopen()) < 0)
+      {
+        ERR ("Unable to open %s to list UDP entries!\n", mib_dev);
+        HeapFree(heap, 0, table);
+        return ERROR_NOT_SUPPORTED;
+      }
+
+      if ((head = mibget(sd)) == NULL)
+      {
+        HeapFree(heap, 0, table);
+        close(sd);
+        return ERROR_NOT_SUPPORTED;
+      }
+
+      for (item = head; item; item = item->next_item)
+      {
+        if ((item->group != MIB2_UDP) || (item->mib_id != MIB2_UDP_ENTRY))
+          continue;
+
+        for (ude = (mib2_udpEntry_t *)item->valp;
+               (char *)ude < (char *)item->valp + item->length; ude++)
+        {
+
+          if (UdpCount == numEntries) /* in case of race */
+            break;
+
+          memset(&table->table[UdpCount], 0, sizeof(MIB_UDPROW));
+
+          table->table[UdpCount].dwLocalAddr = ude->udpLocalAddress;
+          table->table[UdpCount].dwLocalPort = ude->udpLocalPort;
+
+          UdpCount++;
+        }
+      }
+
+      *ppUdpTable = table;
+      table->dwNumEntries = UdpCount;
+      ret = NO_ERROR;
+      mibfree(head);
+      close(sd);
+    }
+    else
+      ret = ERROR_OUTOFMEMORY;
+  }
+  return ret;
+#elif defined(__linux__)
 
   if (!ppUdpTable)
     ret = ERROR_INVALID_PARAMETER;
@@ -1529,6 +2318,10 @@
       ret = ERROR_OUTOFMEMORY;
   }
   return ret;
+#else
+  ERR ("unimplemented!\n");
+  return ERROR_NOT_SUPPORTED;
+#endif
 }
 
 
@@ -1536,14 +2329,48 @@
 {
 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
    return getNumWithOneHeader ("net.inet.tcp.pcblist");
-#else
+#elif defined(HAVE_STREAMS_TPI)
+   DWORD TcpCount = 0;
+   int sd;
+   mib_item_t *head, *item;
+   mib2_tcpConnEntry_t *tp;
+
+   if ((sd = mibopen()) < 0)
+   {
+     ERR ("Unable to open %s to count TCP entries!\n", mib_dev);
+     return 0;
+   }
+
+   if ((head = mibget(sd)) == NULL)
+   {
+     close(sd);
+     return 0;
+   }
+
+   for (item = head; item; item = item->next_item)
+   {
+     if ((item->group != MIB2_TCP) || (item->mib_id != MIB2_TCP_CONN))
+       continue;
+
+     for (tp = (mib2_tcpConnEntry_t *)item->valp;
+            (char *)tp < (char *)item->valp + item->length; tp++)
+       TcpCount++;
+   }
+
+   mibfree(head);
+   close(sd);
+   return TcpCount;
+#elif defined(__linux__)
    return getNumWithOneHeader ("/proc/net/tcp");
+#else
+   return 0;
 #endif
 }
 
 
 /* Why not a lookup table? Because the TCPS_* constants are different
    on different platforms */
+#if (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)) || defined(__linux__)
 static DWORD TCPStateToMIBState (int state)
 {
    switch (state)
@@ -1562,6 +2389,7 @@
       case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
    }
 }
+#endif
 
 
 DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
@@ -1573,7 +2401,12 @@
    size_t Len = 0;
    char *Buf;
    struct xinpgen *pXIG, *pOrigXIG;
-#else
+#elif defined(HAVE_STREAMS_TPI)
+   DWORD TcpCount = 0;
+   int sd;
+   mib_item_t *head, *item;
+   mib2_tcpConnEntry_t *tp;
+#elif defined(__linux__)
    FILE *fp;
    char buf[512] = { 0 }, *ptr;
 #endif
@@ -1684,7 +2517,47 @@
    }
 
    HeapFree (GetProcessHeap (), 0, Buf);
-#else
+#elif defined(HAVE_STREAMS_TPI)
+
+   if ((sd = mibopen()) < 0)
+   {
+     ERR ("Unable to open %s to list TCP entries!\n", mib_dev);
+     return ERROR_NOT_SUPPORTED;
+   }
+
+   if ((head = mibget(sd)) == NULL)
+   {
+     close(sd);
+     return ERROR_NOT_SUPPORTED;
+   }
+
+   for (item = head; item; item = item->next_item)
+   {
+     if ((item->group != MIB2_TCP) || (item->mib_id != MIB2_TCP_CONN))
+       continue;
+
+     for (tp = (mib2_tcpConnEntry_t *)item->valp;
+         (char *)tp < (char *)item->valp + item->length; tp++) {
+
+       if (TcpCount == numEntries) /* in case of race */
+         break;
+
+       memset(&table->table[TcpCount], 0, sizeof(MIB_TCPROW));
+
+       table->table[TcpCount].dwState = tp->tcpConnState;
+       table->table[TcpCount].dwLocalAddr = tp->tcpConnLocalAddress;
+       table->table[TcpCount].dwLocalPort = tp->tcpConnLocalPort;
+       table->table[TcpCount].dwRemoteAddr = tp->tcpConnRemAddress;
+       table->table[TcpCount].dwRemotePort = tp->tcpConnRemPort;
+
+       TcpCount++;
+     }
+   }
+
+   table->dwNumEntries = TcpCount;
+   mibfree(head);
+   close(sd);
+#elif defined(__linux__)
    /* get from /proc/net/tcp, no error if can't */
    fp = fopen("/proc/net/tcp", "r");
    if (!fp)
@@ -1735,6 +2608,9 @@
       }
    }
    fclose(fp);
+#else
+   ERR ("unimplemented!\n");
+   return ERROR_NOT_SUPPORTED;
 #endif
 
    return NO_ERROR;