iphlpapi: Add support for GetTcpTable on Mac OS X.
diff --git a/configure b/configure
index 483725a..266f7af 100755
--- a/configure
+++ b/configure
@@ -6820,6 +6820,7 @@
 
 
 
+
 for ac_header in \
 	AudioUnit/AudioUnit.h \
 	Carbon/Carbon.h \
@@ -6913,6 +6914,7 @@
 	sys/shm.h \
 	sys/signal.h \
 	sys/socket.h \
+	sys/socketvar.h \
 	sys/sockio.h \
 	sys/soundcard.h \
 	sys/statvfs.h \
@@ -7216,7 +7218,9 @@
 
 
 
-for ac_header in net/if.h net/if_arp.h net/if_dl.h net/if_types.h net/route.h netipx/ipx.h
+
+
+for ac_header in netinet/in_pcb.h netinet/ip_var.h net/if.h net/if_arp.h net/if_dl.h net/if_types.h net/route.h netipx/ipx.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_header" >&5
@@ -7276,6 +7280,80 @@
 
 done
 
+     #if HAVE_SYS_SOCKETVAR_H
+     # include <sys/socketvar.h>
+     #endif
+
+
+for ac_header in netinet/tcp_var.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+     #if HAVE_SYS_SOCKET_H
+     # include <sys/socket.h>
+     #endif
+     #if HAVE_SYS_SOCKETVAR_H
+     # include <sys/socketvar.h>
+     #endif
+     #if HAVE_NETINET_IN_H
+     # include <netinet/in.h>
+     #endif
+     #ifdef HAVE_NETINET_TCP_H
+     # include <netinet/tcp.h>
+     #endif
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
 
 
 for ac_header in linux/ipx.h
diff --git a/configure.ac b/configure.ac
index 2dd7cb9..a03f097 100644
--- a/configure.ac
+++ b/configure.ac
@@ -249,6 +249,7 @@
 	sys/shm.h \
 	sys/signal.h \
 	sys/socket.h \
+	sys/socketvar.h \
 	sys/sockio.h \
 	sys/soundcard.h \
 	sys/statvfs.h \
@@ -278,11 +279,29 @@
      # include <sys/param.h>
      #endif])
 
-AC_CHECK_HEADERS([net/if.h net/if_arp.h net/if_dl.h net/if_types.h net/route.h netipx/ipx.h],,,
+AC_CHECK_HEADERS([netinet/in_pcb.h netinet/ip_var.h net/if.h net/if_arp.h net/if_dl.h net/if_types.h net/route.h netipx/ipx.h],,,
     [#include <sys/types.h>
      #if HAVE_SYS_SOCKET_H
      # include <sys/socket.h>
      #endif])
+     #if HAVE_SYS_SOCKETVAR_H
+     # include <sys/socketvar.h>
+     #endif
+
+AC_CHECK_HEADERS([netinet/tcp_var.h],,,
+    [#include <sys/types.h>
+     #if HAVE_SYS_SOCKET_H
+     # include <sys/socket.h>
+     #endif
+     #if HAVE_SYS_SOCKETVAR_H
+     # include <sys/socketvar.h>
+     #endif
+     #if HAVE_NETINET_IN_H
+     # include <netinet/in.h>
+     #endif
+     #ifdef HAVE_NETINET_TCP_H
+     # include <netinet/tcp.h>
+     #endif])
 
 AC_CHECK_HEADERS([linux/ipx.h],,,
     [#include <sys/types.h>
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index 6b7fa62..799f7fc 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -336,7 +336,9 @@
 
   TRACE("ppTcpTable %p, bOrder %d, heap %p, flags 0x%08x\n",
    ppTcpTable, bOrder, heap, flags);
-  ret = getTcpTable(ppTcpTable, heap, flags);
+
+  *ppTcpTable = NULL;
+  ret = getTcpTable(ppTcpTable, 0, heap, flags);
   if (!ret && bOrder)
     qsort((*ppTcpTable)->table, (*ppTcpTable)->dwNumEntries,
      sizeof(MIB_TCPROW), TcpTableSorter);
@@ -1545,25 +1547,16 @@
       ret = ERROR_INSUFFICIENT_BUFFER;
     }
     else {
-      PMIB_TCPTABLE table;
-
-      ret = getTcpTable(&table, GetProcessHeap(), 0);
+      ret = getTcpTable(&pTcpTable, numEntries, 0, 0);
       if (!ret) {
-        size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) *
+        size = sizeof(MIB_TCPTABLE) + (pTcpTable->dwNumEntries - 1) *
          sizeof(MIB_TCPROW);
-        if (*pdwSize < size) {
-          *pdwSize = size;
-          ret = ERROR_INSUFFICIENT_BUFFER;
-        }
-        else {
-          *pdwSize = size;
-          memcpy(pTcpTable, table, size);
+        *pdwSize = size;
+
           if (bOrder)
-            qsort(pTcpTable->table, pTcpTable->dwNumEntries,
-             sizeof(MIB_TCPROW), TcpTableSorter);
+             qsort(pTcpTable->table, pTcpTable->dwNumEntries,
+                   sizeof(MIB_TCPROW), TcpTableSorter);
           ret = NO_ERROR;
-        }
-        HeapFree(GetProcessHeap(), 0, table);
       }
       else
         ret = ERROR_OUTOFMEMORY;
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index b80cf61..7c6488c 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 2003,2006 Juan Lang
+ * Copyright (C) 2007 TransGaming Technologies Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,9 @@
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif
+#ifdef HAVE_SYS_SOCKETVAR_H
+#include <sys/socketvar.h>
+#endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
@@ -52,13 +56,27 @@
 #include <netinet/tcp_fsm.h>
 #endif
 
+#ifdef HAVE_NETINET_IN_PCB_H
+#include <netinet/in_pcb.h>
+#endif
+#ifdef HAVE_NETINET_TCP_VAR_H
+#include <netinet/tcp_var.h>
+#endif
+#ifdef HAVE_NETINET_IP_VAR_H
+#include <netinet/ip_var.h>
+#endif
+
 #ifdef HAVE_SYS_SYSCTL_H
 #include <sys/sysctl.h>
 #endif
 
+#ifndef ROUNDUP
 #define ROUNDUP(a) \
 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#endif
+#ifndef ADVANCE
 #define ADVANCE(x, n) (x += ROUNDUP(((struct sockaddr *)n)->sa_len))
+#endif
 
 #include "windef.h"
 #include "winbase.h"
@@ -66,7 +84,7 @@
 #include "ifenum.h"
 #include "ipstats.h"
 
-#ifdef linux
+#ifndef HAVE_NETINET_TCP_FSM_H
 #define TCPS_ESTABLISHED  1
 #define TCPS_SYN_SENT     2
 #define TCPS_SYN_RECEIVED 3
@@ -564,6 +582,100 @@
 
 static DWORD getNumWithOneHeader(const char *filename)
 {
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
+   size_t Len = 0;
+   char *Buf;
+   struct xinpgen *pXIG, *pOrigXIG;
+   int Protocol;
+   DWORD NumEntries = 0;
+
+   if (!strcmp (filename, "net.inet.tcp.pcblist"))
+      Protocol = IPPROTO_TCP;
+   else if (!strcmp (filename, "net.inet.udp.pcblist"))
+      Protocol = IPPROTO_UDP;
+   else
+   {
+      ERR ("Unsupported mib '%s', needs protocol mapping\n",
+           filename);
+      return 0;
+   }
+
+   if (sysctlbyname (filename, NULL, &Len, NULL, 0) < 0)
+   {
+      WARN ("Unable to read '%s' via sysctlbyname\n", filename);
+      return 0;
+   }
+
+   Buf = HeapAlloc (GetProcessHeap (), 0, Len);
+   if (!Buf)
+   {
+      ERR ("Out of memory!\n");
+      return 0;
+   }
+
+   if (sysctlbyname (filename, Buf, &Len, NULL, 0) < 0)
+   {
+      ERR ("Failure to read '%s' via sysctlbyname!\n", filename);
+      HeapFree (GetProcessHeap (), 0, Buf);
+      return 0;
+   }
+
+   /* Might be nothing here; first entry is just a header it seems */
+   if (Len <= sizeof (struct xinpgen))
+   {
+      HeapFree (GetProcessHeap (), 0, Buf);
+      return 0;
+   }
+
+   pOrigXIG = (struct xinpgen *)Buf;
+   pXIG = pOrigXIG;
+
+   for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
+        pXIG->xig_len > sizeof (struct xinpgen);
+        pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
+   {
+      struct tcpcb *pTCPData = NULL;
+      struct inpcb *pINData;
+      struct xsocket *pSockData;
+
+      if (Protocol == IPPROTO_TCP)
+      {
+         pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
+         pINData = &((struct xtcpcb *)pXIG)->xt_inp;
+         pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
+      }
+      else
+      {
+         pINData = &((struct xinpcb *)pXIG)->xi_inp;
+         pSockData = &((struct xinpcb *)pXIG)->xi_socket;
+      }
+
+      /* Ignore sockets for other protocols */
+      if (pSockData->xso_protocol != Protocol)
+         continue;
+
+      /* Ignore PCBs that were freed while generating the data */
+      if (pINData->inp_gencnt > pOrigXIG->xig_gen)
+         continue;
+
+      /* we're only interested in IPv4 addresses */
+      if (!(pINData->inp_vflag & INP_IPV4) ||
+          (pINData->inp_vflag & INP_IPV6))
+         continue;
+
+      /* If all 0's, skip it */
+      if (!pINData->inp_laddr.s_addr &&
+          !pINData->inp_lport &&
+          !pINData->inp_faddr.s_addr &&
+          !pINData->inp_fport)
+         continue;
+
+      NumEntries++;
+   }
+
+   HeapFree (GetProcessHeap (), 0, Buf);
+   return NumEntries;
+#else
   FILE *fp;
   int ret = 0;
 
@@ -586,6 +698,7 @@
      ERR ("Unable to open '%s' to count entries!\n", filename);
 
   return ret;
+#endif
 }
 
 DWORD getNumRoutes(void)
@@ -1026,132 +1139,209 @@
   return ret;
 }
 
+
 DWORD getNumTcpEntries(void)
 {
-  return getNumWithOneHeader("/proc/net/tcp");
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
+   return getNumWithOneHeader ("net.inet.tcp.pcblist");
+#else
+   return getNumWithOneHeader ("/proc/net/tcp");
+#endif
 }
 
-DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags)
-{
-  DWORD ret;
 
-#if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP)
-  ERR ("unimplemented!\n");
-  return ERROR_INVALID_PARAMETER;
+/* Why not a lookup table? Because the TCPS_* constants are different
+   on different platforms */
+static DWORD TCPStateToMIBState (int state)
+{
+   switch (state)
+   {
+      case TCPS_ESTABLISHED: return MIB_TCP_STATE_ESTAB;
+      case TCPS_SYN_SENT: return MIB_TCP_STATE_SYN_SENT;
+      case TCPS_SYN_RECEIVED: return MIB_TCP_STATE_SYN_RCVD;
+      case TCPS_FIN_WAIT_1: return MIB_TCP_STATE_FIN_WAIT1;
+      case TCPS_FIN_WAIT_2: return MIB_TCP_STATE_FIN_WAIT2;
+      case TCPS_TIME_WAIT: return MIB_TCP_STATE_TIME_WAIT;
+      case TCPS_CLOSE_WAIT: return MIB_TCP_STATE_CLOSE_WAIT;
+      case TCPS_LAST_ACK: return MIB_TCP_STATE_LAST_ACK;
+      case TCPS_LISTEN: return MIB_TCP_STATE_LISTEN;
+      case TCPS_CLOSING: return MIB_TCP_STATE_CLOSING;
+      default:
+      case TCPS_CLOSED: return MIB_TCP_STATE_CLOSED;
+   }
+}
+
+
+DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
+                  DWORD flags)
+{
+   DWORD numEntries;
+   PMIB_TCPTABLE table;
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
+   size_t Len = 0;
+   char *Buf;
+   struct xinpgen *pXIG, *pOrigXIG;
+#else
+   FILE *fp;
+   char buf[512] = { 0 }, *ptr;
 #endif
 
-  if (!ppTcpTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else {
-    DWORD numEntries = getNumTcpEntries();
-    PMIB_TCPTABLE table = HeapAlloc(heap, flags,
-     sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW));
+   if (!ppTcpTable)
+      return ERROR_INVALID_PARAMETER;
 
-    if (table) {
-      FILE *fp;
+   numEntries = getNumTcpEntries ();
 
-      ret = NO_ERROR;
-      *ppTcpTable = table;
-      table->dwNumEntries = 0;
-      /* get from /proc/net/tcp, no error if can't */
-      fp = fopen("/proc/net/tcp", "r");
-      if (fp) {
-        char buf[512] = { 0 }, *ptr;
-
-        /* skip header line */
-        ptr = fgets(buf, sizeof(buf), fp);
-        while (ptr && table->dwNumEntries < numEntries) {
-          memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
-          ptr = fgets(buf, sizeof(buf), fp);
-          if (ptr) {
-            char *endPtr;
-
-            while (ptr && *ptr && *ptr != ':')
-              ptr++;
-            if (ptr && *ptr)
-              ptr++;
-            if (ptr && *ptr) {
-              table->table[table->dwNumEntries].dwLocalAddr = strtoul(ptr,
-               &endPtr, 16);
-              ptr = endPtr;
-            }
-            if (ptr && *ptr) {
-              ptr++;
-              table->table[table->dwNumEntries].dwLocalPort = strtoul(ptr,
-               &endPtr, 16);
-              ptr = endPtr;
-            }
-            if (ptr && *ptr) {
-              table->table[table->dwNumEntries].dwRemoteAddr = strtoul(ptr,
-               &endPtr, 16);
-              ptr = endPtr;
-            }
-            if (ptr && *ptr) {
-              ptr++;
-              table->table[table->dwNumEntries].dwRemotePort = strtoul(ptr,
-               &endPtr, 16);
-              ptr = endPtr;
-            }
-            if (ptr && *ptr) {
-              DWORD state = strtoul(ptr, &endPtr, 16);
-
-              switch (state)
-              {
-                case TCPS_ESTABLISHED:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_ESTAB;
-                  break;
-                case TCPS_SYN_SENT:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_SYN_SENT;
-                  break;
-                case TCPS_SYN_RECEIVED:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_SYN_RCVD;
-                  break;
-                case TCPS_FIN_WAIT_1:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_FIN_WAIT1;
-                  break;
-                case TCPS_FIN_WAIT_2:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_FIN_WAIT2;
-                  break;
-                case TCPS_TIME_WAIT:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_TIME_WAIT;
-                  break;
-                case TCPS_CLOSED:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_CLOSED;
-                  break;
-                case TCPS_CLOSE_WAIT:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_CLOSE_WAIT;
-                  break;
-                case TCPS_LAST_ACK:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_LAST_ACK;
-                  break;
-                case TCPS_LISTEN:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_LISTEN;
-                  break;
-                case TCPS_CLOSING:
-                  table->table[table->dwNumEntries].dwState =
-                   MIB_TCP_STATE_CLOSING;
-                  break;
-              }
-              ptr = endPtr;
-            }
-            table->dwNumEntries++;
-          }
-        }
-        fclose(fp);
+   if (!*ppTcpTable)
+   {
+      *ppTcpTable = HeapAlloc (heap, flags,
+                               sizeof (MIB_TCPTABLE) +
+                               (numEntries - 1) * sizeof (MIB_TCPROW));
+      if (!*ppTcpTable)
+      {
+         ERR ("Out of memory!\n");
+         return ERROR_OUTOFMEMORY;
       }
-    }
-    else
-      ret = ERROR_OUTOFMEMORY;
-  }
-  return ret;
+      maxEntries = numEntries;
+   }
+
+   table = *ppTcpTable;
+   table->dwNumEntries = 0;
+   if (!numEntries)
+      return NO_ERROR;
+
+#if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_NETINET_IN_PCB_H)
+
+   if (sysctlbyname ("net.inet.tcp.pcblist", NULL, &Len, NULL, 0) < 0)
+   {
+      ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
+      return ERROR_OUTOFMEMORY;
+   }
+
+   Buf = HeapAlloc (GetProcessHeap (), 0, Len);
+   if (!Buf)
+   {
+      ERR ("Out of memory!\n");
+      return ERROR_OUTOFMEMORY;
+   }
+
+   if (sysctlbyname ("net.inet.tcp.pcblist", Buf, &Len, NULL, 0) < 0)
+   {
+      ERR ("Failure to read net.inet.tcp.pcblist via sysctlbyname!\n");
+      HeapFree (GetProcessHeap (), 0, Buf);
+      return ERROR_OUTOFMEMORY;
+   }
+
+   /* Might be nothing here; first entry is just a header it seems */
+   if (Len <= sizeof (struct xinpgen))
+   {
+      HeapFree (GetProcessHeap (), 0, Buf);
+      return NO_ERROR;
+   }
+
+   pOrigXIG = (struct xinpgen *)Buf;
+   pXIG = pOrigXIG;
+
+   for (pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len);
+        (pXIG->xig_len > sizeof (struct xinpgen)) &&
+           (table->dwNumEntries < maxEntries);
+        pXIG = (struct xinpgen *)((char *)pXIG + pXIG->xig_len))
+   {
+      struct tcpcb *pTCPData = NULL;
+      struct inpcb *pINData;
+      struct xsocket *pSockData;
+
+      pTCPData = &((struct xtcpcb *)pXIG)->xt_tp;
+      pINData = &((struct xtcpcb *)pXIG)->xt_inp;
+      pSockData = &((struct xtcpcb *)pXIG)->xt_socket;
+
+      /* Ignore sockets for other protocols */
+      if (pSockData->xso_protocol != IPPROTO_TCP)
+         continue;
+
+      /* Ignore PCBs that were freed while generating the data */
+      if (pINData->inp_gencnt > pOrigXIG->xig_gen)
+         continue;
+
+      /* we're only interested in IPv4 addresses */
+      if (!(pINData->inp_vflag & INP_IPV4) ||
+          (pINData->inp_vflag & INP_IPV6))
+         continue;
+
+      /* If all 0's, skip it */
+      if (!pINData->inp_laddr.s_addr &&
+          !pINData->inp_lport &&
+          !pINData->inp_faddr.s_addr &&
+          !pINData->inp_fport)
+         continue;
+
+      /* Fill in structure details */
+      table->table[table->dwNumEntries].dwLocalAddr =
+         pINData->inp_laddr.s_addr;
+      table->table[table->dwNumEntries].dwLocalPort =
+         pINData->inp_lport;
+      table->table[table->dwNumEntries].dwRemoteAddr =
+         pINData->inp_faddr.s_addr;
+      table->table[table->dwNumEntries].dwRemotePort =
+         pINData->inp_fport;
+      table->table[table->dwNumEntries].dwState =
+         TCPStateToMIBState (pTCPData->t_state);
+
+      table->dwNumEntries++;
+   }
+
+   HeapFree (GetProcessHeap (), 0, Buf);
+#else
+   /* get from /proc/net/tcp, no error if can't */
+   fp = fopen("/proc/net/tcp", "r");
+   if (!fp)
+      return NO_ERROR;
+
+   /* skip header line */
+   ptr = fgets(buf, sizeof(buf), fp);
+   while (ptr && table->dwNumEntries < maxEntries) {
+      memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_TCPROW));
+      ptr = fgets(buf, sizeof(buf), fp);
+      if (ptr) {
+         char *endPtr;
+
+         while (ptr && *ptr && *ptr != ':')
+            ptr++;
+         if (ptr && *ptr)
+            ptr++;
+         if (ptr && *ptr) {
+            table->table[table->dwNumEntries].dwLocalAddr =
+               strtoul(ptr, &endPtr, 16);
+            ptr = endPtr;
+         }
+         if (ptr && *ptr) {
+            ptr++;
+            table->table[table->dwNumEntries].dwLocalPort =
+               strtoul(ptr, &endPtr, 16);
+            ptr = endPtr;
+         }
+         if (ptr && *ptr) {
+            table->table[table->dwNumEntries].dwRemoteAddr =
+               strtoul(ptr, &endPtr, 16);
+            ptr = endPtr;
+         }
+         if (ptr && *ptr) {
+            ptr++;
+            table->table[table->dwNumEntries].dwRemotePort =
+               strtoul(ptr, &endPtr, 16);
+            ptr = endPtr;
+         }
+         if (ptr && *ptr) {
+            DWORD state = strtoul(ptr, &endPtr, 16);
+
+            table->table[table->dwNumEntries].dwState =
+               TCPStateToMIBState (state);
+            ptr = endPtr;
+         }
+         table->dwNumEntries++;
+      }
+   }
+   fclose(fp);
+#endif
+
+   return NO_ERROR;
 }
diff --git a/dlls/iphlpapi/ipstats.h b/dlls/iphlpapi/ipstats.h
index 147276e..ec8dcb0 100644
--- a/dlls/iphlpapi/ipstats.h
+++ b/dlls/iphlpapi/ipstats.h
@@ -83,6 +83,7 @@
 /* Allocates the TCP state table from heap and returns it to you in *ppTcpTable.
  * Returns NO_ERROR on success, something else on failure.
  */
-DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, HANDLE heap, DWORD flags);
+DWORD getTcpTable(PMIB_TCPTABLE *ppTcpTable, DWORD maxEntries, HANDLE heap,
+                  DWORD flags);
 
 #endif /* ndef WINE_IPSTATS_H_ */
diff --git a/include/config.h.in b/include/config.h.in
index 9366a9f..c95abd0 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -426,15 +426,24 @@
 /* Define to 1 if you have the <netinet/in.h> header file. */
 #undef HAVE_NETINET_IN_H
 
+/* Define to 1 if you have the <netinet/in_pcb.h> header file. */
+#undef HAVE_NETINET_IN_PCB_H
+
 /* Define to 1 if you have the <netinet/in_systm.h> header file. */
 #undef HAVE_NETINET_IN_SYSTM_H
 
+/* Define to 1 if you have the <netinet/ip_var.h> header file. */
+#undef HAVE_NETINET_IP_VAR_H
+
 /* Define to 1 if you have the <netinet/tcp_fsm.h> header file. */
 #undef HAVE_NETINET_TCP_FSM_H
 
 /* Define to 1 if you have the <netinet/tcp.h> header file. */
 #undef HAVE_NETINET_TCP_H
 
+/* Define to 1 if you have the <netinet/tcp_var.h> header file. */
+#undef HAVE_NETINET_TCP_VAR_H
+
 /* Define to 1 if you have the <netipx/ipx.h> header file. */
 #undef HAVE_NETIPX_IPX_H
 
@@ -777,6 +786,9 @@
 /* Define to 1 if you have the <sys/signal.h> header file. */
 #undef HAVE_SYS_SIGNAL_H
 
+/* Define to 1 if you have the <sys/socketvar.h> header file. */
+#undef HAVE_SYS_SOCKETVAR_H
+
 /* Define to 1 if you have the <sys/socket.h> header file. */
 #undef HAVE_SYS_SOCKET_H