Hello, I'm an academic student from Brazil, and I have a project of
updating and porting to Linux an application called YANA(Yet Another
Network Analyzer). You can find it on the following link:
http://sourceforge.net/projects/yana/.

The latest version was written using Lazarus 0.9.22 and seemingly Free
Pascal 2.0.4(I'm not entirely sure of it), which was back in 2007. Since
then, much has changed in these two tools, and many things need to be
reworked on YANA.

But the first problem is that I can't even compile the code provided by the
author, because it uses Kylix compatibility-only units for Linux, libc and
kernelioctl, and it relies on a specific dll of Windows, IP Helper DLL.
Therefore, this fact locks the software to Windows and Linux running on a
i386 platform.

I successfully compiled and ran all the utility modules that composes it as
separate programs, but when they are put together with a particular unit,
which I will send as an attachment to this e-mail, the whole process broke
down in others platforms.

My intent is to remove this dependency and make the software more
cross-platform possible, but I actually have no clue about how to do it, so
please: can any of you help me by telling the first steps which I must
take, the beginning is hard, but once the flow is established, the outcome
will be a natural consequence of it.

Thank you in advance for any help.
{TODO : remove Windows dll dependency - currently it may work only under Win32 }
{TODO : redo string grid lines append - scrolls to top on timer}
{TODO : Datagrams Discarded (Out) }
{TODO : Forward Policy }
{TODO : Age (sec) }
{TODO : Adapters info tab; Description }
{TODO : change adapters inormation: +DescriptionÄ™ +Ip AddressÄ™ +WINS +Secondary WINS Server.}

{TODO : Change interface informationas as follows:
Index of Interface          - Shows the index that identifies the interface.
Type of Interface           - Shows the type of interface.
Max Transmission Unit       - Shows the Maximum Transmission Unit (MTU).
Speed of Interface          - Shows the speed of the interface in bits
                              per second.
Physical Address of Adapter - Shows the length of the physical address.
Administrative Status       - Shows whether the interface is administratively
                              enabled or disabled.
Operational Status          - Shows the operational status of the interface.
                              The following values are available:
                              NON_OPERATIONAL, UNREACHABLE, DISCONNECTED,
                              CONNECTING, CONNECTED, OPERATIONAL.
Bytes Received              - Shows the number of octets of data received
                              through this interface.
+Unicast Packets Received    - Shows the number of unicast packets received
                              through this interface.
+Non Unicast Packets Received- Shows the number of non-unicast packets
                              received through this interface. Broadcast
                              and multicast packets are included.
+Received packets discarded  - Shows the number of incoming packets that
                              were discarded even though they did not
                              have errors.
+Erroneous packets received  - Shows the number of incoming packets that were
                              discarded because of errors.
+Unknown Protocol packets received - Shows the number of incoming packets
                              that were discarded because the protocol
                              was unknown.
Bytes Sent -                - Shows the number of octets of data sent
                              through this interface.
+Unicast Packets sent        - Shows the number of unicast packets sent
                              through this interface.
+Non Unicast Packets sent    - Shows the number of non-unicast packets
                              sent through this interface. Broadcast and
                              multicast packets are included.
+Outgoing packets discarded  - Shows the number of outgoing packets that
                              were discarded even though they did not
                              have errors.
+Erroneous packets sent	    - Shows the number of outgoing packets that were
                              discarded because of errors.
+Output Queue Length	    - Shows the output queue length.
}

(*
  ==========================
  Delphi IPHelper functions
  ==========================
  Required OS : NT4/SP4 or higher, WIN98/WIN98se
  Developed on:  D6 Ent. & Prof.
  Tested on   :  WIN-NT4/SP6, WIN98se, WIN95/OSR1
              :  WIN98, W2K-SP2, 3, 4
              :  W2K, W2K prof, W2K server

  Warning - currently only supports Delphi 5 and later unless int64 is removed
  (Int64 is only used to force Format to show unsigned 32-bit numbers)

  ================================================================
                    This software is FREEWARE
                    -------------------------
  If this software works, it was surely written by Dirk Claessens
                    dirkcl@@pandora.be
        (If it doesn't, I don't know anything about it.)
  ================================================================

List of Fixes & Additions

v1.1  dirkcl
-----
Fix :  wrong errorcode reported in GetNetworkParams()
Fix :  RTTI MaxHops 20 > 128
Add :  ICMP -statistics
Add :  Well-Known port numbers
Add :  RecentIP list
Add :  Timer update

v1.2   dirkcl
----
Fix :  Recent IP's correct update
ADD :  ICMP-error codes translated

v1.3 - 18th September 2001
----
  Angus Robertson, Magenta Systems Ltd, England
     delphi@@magsys.co.uk, http://www.magsys.co.uk/delphi/
  Slowly converting procs into functions that can be used by other programs,
     ie Get_ becomes IpHlp
  Primary improvements are that current DNS server is now shown, also
     in/out bytes for each interface (aka adaptor)
  All functions are dynamically loaded so program can be used on W95/NT4
  Tested with Delphi 6 on Windows 2000 and XP

v1.4 - 28th February 2002 - Angus
----
  Fixed major memory leak in IpHlpIfTable (except instead of finally)
  Fixed major memory leak in Get_AdaptersInfo (incremented buffer pointer)
  Created IpHlpAdaptersInfo which returns TAdaptorRows


  Note: IpHlpNetworkParams returns dynamic DNS address (and other stuff)
  Note: IpHlpIfEntry returns bytes in/out for a network adaptor

v1.5 - 5th October 2003
----
  Jean-Pierre Turchi "From South of France" <jpturchi@@mageos.com>
  Cosmetic (more readable) and add-in's from iana.org in "WellKnownPorts"

v1.6 - 1st April 2007
----
  Sergei Kostigoff <sergei@@kostigoff.net>
  Minor cosmetics
  Output results to string grids

v1.7 - 12th May 2007
----
  Sergei Kostigoff <sergei@@kostigoff.net>
  Proto type strings moved to RFC1213ip unit
  IPForwTypes strings moved to RFC1213ip unit (and renamed to sIpRouteTypeString)
  ARPEntryType strings moved to RFC1213ip unit (and renamed to...
  
*)

{ @abstract(@bold(uIpHelper); no forms. IP helper functions) @br
Original source has been written by Dirk Claessens <dirkcl@@pandora.be>. @br
Original license message is as follows:
@preformatted(
  ==========================
  Delphi IPHelper functions
  ==========================
  Required OS : NT4/SP4 or higher, WIN98/WIN98se
  Developed on:  D6 Ent. & Prof.
  Tested on   :  WIN-NT4/SP6, WIN98se, WIN95/OSR1
              :  WIN98, W2K-SP2, 3, 4
              :  W2K, W2K prof, W2K server

  Warning - currently only supports Delphi 5 and later unless int64 is removed
  (Int64 is only used to force Format to show unsigned 32-bit numbers)
  ================================================================
                    This software is FREEWARE
                    -------------------------
  If this software works, it was surely written by Dirk Claessens
                    dirkcl@@pandora.be
        (If it doesn't, I don't know anything about it.)
  ================================================================
)
Miscellaneous IP functions collection.
}
unit uIpHelper;

{$H+}
{$IFDEF FPC}
{$mode Delphi}
{$ENDIF}

interface

uses
{$IFDEF LINUX}
  Libc, Types, KernelIoctl,
{$ELSE}
  Windows, Classes,
{$ENDIF}

  SysUtils,
  Grids,
  rfc1213const,
  rfc1213if,
  rfc1213ip,
  rfc1213tcp,
  
  uYanaUtil,
  uIpHlpApi; // replace or remove on beta stage!!!
  
var
  { List of recent IP addresses}
  RecentIPs     : TStringList;

//------conversion of well-known port numbers to service names----------------

type
  { well known port record structure }
  TWellKnownPort = record
    Prt: DWORD;
    Srv: string[15];
  end;


const
    // Only most "popular" services. Names and descriptions given
    // as per http://www.iana.org/assignments/port-numbers
  WellKnownPorts: array[1..37] of TWellKnownPort
  = (
//    ( Prt: 0; Srv:   'RESRVED' ),     { Reserved }
    ( Prt: 7; Srv:   'echo' ),        { Ping }
    ( Prt: 9; Srv:   'discard' ),     { Discard }
    ( Prt: 11; Srv:  'systat' ),      { Active Users }
    ( Prt: 13; Srv:  'daytime' ),     { Daytime (RFC 867) }
    ( Prt: 17; Srv:  'qotd' ),        { Quote of the Day }
    ( Prt: 19; Srv:  'chargen' ),     { Character Generator }
    ( Prt: 20; Srv:  'ftp-data' ),    { File Transfer [Default Data] }
    ( Prt: 21; Srv:  'ftp' ),         { File Transfer [Control] }
    ( Prt: 22; Srv:  'ssh' ),         { SSH Remote Login Protocol }
    ( Prt: 23; Srv:  'telnet' ),      { Telnet }
    ( Prt: 25; Srv:  'smtp' ),        { Simple Mail Transfer }
    ( Prt: 37; Srv:  'time' ),        { Time }
    ( Prt: 43; Srv:  'nicname' ),     { Who Is }
    ( Prt: 53; Srv:  'domain' ),      { Domain Name Server }
    ( Prt: 67; Srv:  'bootps' ),      { Bootstrap Protocol Server }
    ( Prt: 68; Srv:  'bootpc' ),      { Bootstrap Protocol Client }
    ( Prt: 69; Srv:  'tftp' ),        { Trivial File Transfer }
    ( Prt: 70; Srv:  'gopher' ),      { Gopher }
    ( Prt: 79; Srv:  'finger' ),      { Finger }
    ( Prt: 80; Srv:  'http' ),        { World Wide Web HTTP }
    ( Prt: 88; Srv:  'kerberos' ),    { Kerberos }
    ( Prt: 109; Srv: 'pop2' ),        { Post Office Protocol - Version 2 }
    ( Prt: 110; Srv: 'pop3' ),        { Post Office Protocol - Version 3 }
    ( Prt: 111; Srv: 'sunrpc' ),      { SUN Remote Procedure Call }
    ( Prt: 119; Srv: 'nntp' ),        { Network News Transfer Protocol }
    ( Prt: 123; Srv: 'ntp' ),         { Network Time protocol }
    ( Prt: 135; Srv: 'epmap' ),       { DCE endpoint resolution; NETBIOS RPC }
    ( Prt: 137; Srv: 'netbios-ns' ),  { NETBIOS Name Service }
    ( Prt: 138; Srv: 'netbios-dgm' ), { NETBIOS Datagram Service }
    ( Prt: 139; Srv: 'netbios-ssn' ), { NETBIOS Session Service        }
    ( Prt: 143; Srv: 'imap' ),        { Internet Message Access Protocol }
    ( Prt: 161; Srv: 'snmp' ),        { SNMP }
    ( Prt: 169; Srv: 'send' ),        { SEND }
    ( Prt: 179; Srv: 'bgp' ),         { Border Gateway Protocol }
    ( Prt: 515; Srv: 'printer' ),     { spooler }
    ( Prt: 4000; Srv: 'terabase' ),   { Terabase; also used by ICQ}
    ( Prt: 8080; Srv: 'http-alt' )    { HTTP Alternate (see port 80) }
    );


//-----------conversion of ICMP error codes to strings--------------------------
             {taken from www.sockets.com/ms_icmp.c }

const
  { offset of ICMP error (@link(IcmpErr))}
  ICMP_ERROR_BASE = 11000;
  { ICMP error strings array }
  IcmpErr : array[1..22] of string =
  ('IP_BUFFER_TOO_SMALL','IP_DEST_NET_UNREACHABLE', 'IP_DEST_HOST_UNREACHABLE',
   'IP_PROTOCOL_UNREACHABLE', 'IP_DEST_PORT_UNREACHABLE', 'IP_NO_RESOURCES',
   'IP_BAD_OPTION','IP_HARDWARE_ERROR', 'IP_PACKET_TOO_BIG', 'IP_REQUEST_TIMED_OUT',
   'IP_BAD_REQUEST','IP_BAD_ROUTE', 'IP_TTL_EXPIRED_TRANSIT',
   'IP_TTL_EXPIRED_REASSEM','IP_PARAMETER_PROBLEM', 'IP_SOURCE_QUENCH',
   'IP_OPTION_TOO_BIG', 'IP_BAD_DESTINATION','IP_ADDRESS_DELETED',
   'IP_SPEC_MTU_CHANGE', 'IP_MTU_CHANGE', 'IP_UNLOAD'
  );


type
  // for IpHlpNetworkParams
  TNetworkParams = record
    HostName: string ;
    DomainName: string ;
    CurrentDnsServer: string ;
    DnsServerTot: integer ;
    DnsServerNames: array [0..9] of string ;
    NodeType: UINT;
    ScopeID: string ;
    EnableRouting: UINT;
    EnableProxy: UINT;
    EnableDNS: UINT;
  end;

  // dynamic array of rows
  TIfRows = array of TMibIfRow ;

  // for IpHlpAdaptersInfo
  TAdaptorInfo = record
    AdapterName: string ;
    Description: string ;
    MacAddress: string ;
    Index: DWORD;
    aType: UINT;
    DHCPEnabled: UINT;
    CurrIPAddress: string ;
    CurrIPMask: string ;
    IPAddressTot: integer ;
    IPAddressList: array of string ;
    IPMaskList: array of string ;
    GatewayTot: integer ;
    GatewayList: array of string ;
    DHCPTot: integer ;
    DHCPServer: array of string ;
    HaveWINS: BOOL;
    PrimWINSTot: integer ;
    PrimWINSServer: array of string ;
    SecWINSTot: integer ;
    SecWINSServer: array of string ;
    LeaseObtained: LongInt ; // UNIX time, seconds since 1970
    LeaseExpires: LongInt;   // UNIX time, seconds since 1970
  end ;

  // dynamic array of records
  TAdaptorRows = array of TAdaptorInfo ;


//---------------exported stuff-----------------------------------------------

{ Info on installed adapters }
function IpHlpAdaptersInfo(var AdpTot: integer;var AdpRows: TAdaptorRows): integer ;

{}
procedure Get_AdaptersInfo( List: TStrings );

{}
function IpHlpNetworkParams (var NetworkParams: TNetworkParams): integer ;

{}
procedure Get_NetworkParams( List: TStrings );

{}
procedure Get_ARPTable( List: TStrings );

{}
procedure Get_TCPTable( List: TStrings );

{}
procedure Get_TCPStatistics( List: TStrings );

{}
function IpHlpTCPStatistics (var TCPStats: TMibTCPStats): integer ;

{}
procedure Get_UDPTable( List: TStrings );

{}
procedure Get_UDPStatistics( List: TStrings );

{}
function IpHlpUdpStatistics (UdpStats: TMibUDPStats): integer ;

{}
procedure Get_IPAddrTable( List: TStrings );

{}
procedure Get_IPForwardTable( List: TStrings );

{}
procedure Get_IPStatistics( List: TStrings );

{}
function IpHlpIPStatistics (var IPStats: TMibIPStats): integer ;

{}
function Get_RTTAndHopCount( IPAddr: DWORD; MaxHops: Longint;
  var RTT: longint; var HopCount: longint ): integer;

{}
procedure Get_ICMPStats( ICMPIn, ICMPOut: TStrings );

{ include bytes in/out for each adaptor }
function IpHlpIfTable(var IfTot: integer; var IfRows: TIfRows): integer ;

{ get interface table to TStrings }
procedure Get_IfTable( List: TStrings );

{}
function IpHlpIfEntry(Index: integer; var IfRow: TMibIfRow): integer ;

{}
procedure Get_RecentDestIPs( List: TStrings );


// string grid interface

{}
procedure DoNetworkParams(sg : TStringGrid);

{}
procedure DoArpTable(sg : TStringGrid);

{}
procedure DoTcpTable(sg: TStringGrid);

{}
procedure DoUdpTable(sg : TStringGrid);

{}
procedure DoTCPStatistics(sg : TStringGrid);

{}
procedure DoICMPInputStatistics( sg : TStringGrid );

{}
procedure DoIcmpOutputStatistics(sg : TStringGrid);

{}
procedure DoUdpStatistics(sg : TStringGrid);

{}
procedure DoIpStatistics(sg : TStringGrid);

{}
procedure DoIPAddrTable(sg : TStringGrid);

{ fill ip forward string grid }
procedure DoIPForwardTable(sg : TStringGrid);

{ fill adapaters info string grid }
procedure DoAdaptersInfo(sg: TStringGrid);

{ fill interfaces table string grid }
procedure DoIfTable(sg: TStringGrid);


// conversion utils

{ converts numerical MAC-address to ww-xx-yy-zz string }
function MacAddr2Str( MacAddr: TMacAddress; size: integer ): string;

{ converts IP-address in network byte order DWORD to dotted decimal string}
function IpAddr2Str( IPAddr: DWORD ): string;

{ converts dotted decimal IP-address to network byte order DWORD}
function Str2IpAddr( IPStr: string ): DWORD;

{ converts port number in network byte order to string }
function Port2Str( nwoPort: DWORD ): string;

{ converts port number in network byte order to DWORD }
function Port2Wrd( nwoPort: DWORD ): DWORD;

{ converts well-known port numbers to service ID }
function Port2Svc( Port: DWORD ): string;

{ conversion of ICMP error codes to strings }
function ICMPErr2Str( ICMPErrCode: DWORD) : string;


implementation

//--------------General utilities-----------------------------------------------

{ extracts next "token" from string, then eats string }
function NextToken( var s: string; Separator: char ): string;
var
  Sep_Pos: integer;
begin
  Result := '';
  if length( s ) > 0 then begin
    Sep_Pos := pos( Separator, s );
    if Sep_Pos > 0 then begin
      Result := copy( s, 1, Pred( Sep_Pos ) );
      Delete( s, 1, Sep_Pos );
    end else begin
      Result := s;
      s := '';
    end;
  end;
end;

//------------------------------------------------------------------------------
{ concerts numerical MAC-address to ww-xx-yy-zz string }
function MacAddr2Str( MacAddr: TMacAddress; size: integer ): string;
var
  i             : integer;
begin
  if Size = 0 then begin
    Result := '00-00-00-00-00-00';
    EXIT;
  end else
    Result := '';
  //
  for i := 1 to Size do
    Result := Result + IntToHex( MacAddr[i], 2 ) + '-';
  Delete( Result, Length( Result ), 1 );
end;

//------------------------------------------------------------------------------
{ converts IP-address in network byte order DWORD to dotted decimal string}
function IpAddr2Str( IPAddr: DWORD ): string;
var
  i             : integer;
begin
  Result := '';
  for i := 1 to 4 do begin
    Result := Result + Format( '%d.', [IPAddr and $FF] );
    IPAddr := IPAddr shr 8;
  end;
  Delete( Result, Length( Result ), 1 );
end;

//------------------------------------------------------------------------------
{ converts dotted decimal IP-address to network byte order DWORD}
function Str2IpAddr( IPStr: string ): DWORD;
var
  i             : integer;
  Num           : DWORD;
begin
  Result := 0;
  for i := 1 to 4 do
  try
    Num := ( StrToInt( NextToken( IPStr, '.' ) ) ) shl 24;
    Result := ( Result shr 8 ) or Num;
  except
    Result := 0;
  end;

end;

//------------------------------------------------------------------------------
{ converts port number in network byte order to DWORD }
function Port2Wrd( nwoPort: DWORD ): DWORD;
begin
  Result := Swap( WORD( nwoPort ) );
end;

//------------------------------------------------------------------------------
{ converts port number in network byte order to string }
function Port2Str( nwoPort: DWORD ): string;
begin
  Result := IntToStr( Port2Wrd( nwoPort ) );
end;

//------------------------------------------------------------------------------
{ converts well-known port numbers to service ID }
function Port2Svc( Port: DWORD ): string;
var
  i             : integer;
begin
//  Result := Format( '%4d', [Port] ); // in case port not found
  Result := IntToStr(Port); // svk
  for i := Low( WellKnownPorts ) to High( WellKnownPorts ) do
    if Port = WellKnownPorts[i].Prt then begin      { svk }
      Result := Result +': ' + WellKnownPorts[i].Srv;
      BREAK;
    end;
end;

//-----------------------------------------------------------------------------
{ general,  fixed network parameters }
procedure Get_NetworkParams( List: TStrings );
var
    NetworkParams: TNetworkParams ;
    I, ErrorCode: integer ;
begin
    if not Assigned( List ) then EXIT;
    List.Clear;
    ErrorCode := IpHlpNetworkParams (NetworkParams) ;
    if ErrorCode <> 0 then begin
      List.Add (SysErrorMessage (ErrorCode));
      exit;
    end;
    with NetworkParams do begin
        List.Add( 'HOSTNAME          : ' + HostName );
        List.Add( 'DOMAIN            : ' + DomainName );
        List.Add( 'NETBIOS NODE TYPE : ' + NETBIOSTypes[NodeType] );
        List.Add( 'DHCP SCOPE        : ' + ScopeID );
        List.Add( 'ROUTING ENABLED   : ' + IntToStr( EnableRouting ) );
        List.Add( 'PROXY   ENABLED   : ' + IntToStr( EnableProxy ) );
        List.Add( 'DNS     ENABLED   : ' + IntToStr( EnableDNS ) );
        if DnsServerTot <> 0 then begin
          for I := 0 to Pred (DnsServerTot) do
            List.Add( 'DNS SERVER ADDR   : ' + DnsServerNames [I] ) ;
        end; // if
    end; // with
end ;

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
function IpHlpNetworkParams (var NetworkParams: TNetworkParams): integer ;
var
  FixedInfo     : PTFixedInfo;         // Angus
  InfoSize      : Longint;
  PDnsServer    : PTIP_ADDR_STRING ;   // Angus
begin
    InfoSize := 0 ;   // Angus
    result := ERROR_NOT_SUPPORTED ;
    if NOT LoadIpHlp then
      exit ;
    result := GetNetworkParams( Nil, @InfoSize );  // Angus
    if result <> ERROR_BUFFER_OVERFLOW then
      exit ; // Angus
    GetMem (FixedInfo, InfoSize) ;                    // Angus
    try
      result := GetNetworkParams( FixedInfo, @InfoSize );   // Angus
      if result <> ERROR_SUCCESS then
        exit ;
      NetworkParams.DnsServerTot := 0 ;
      with FixedInfo^ do begin
        NetworkParams.HostName := trim (HostName) ;
        NetworkParams.DomainName := trim (DomainName) ;
        NetworkParams.ScopeId := trim (ScopeID) ;
        NetworkParams.NodeType := NodeType ;
        NetworkParams.EnableRouting := EnableRouting ;
        NetworkParams.EnableProxy := EnableProxy ;
        NetworkParams.EnableDNS := EnableDNS ;
        NetworkParams.DnsServerNames [0] := DNSServerList.IPAddress ;  // Angus
        if NetworkParams.DnsServerNames [0] <> '' then
          NetworkParams.DnsServerTot := 1 ;
        PDnsServer := DnsServerList.Next;
        while PDnsServer <> Nil do begin
          NetworkParams.DnsServerNames [NetworkParams.DnsServerTot] :=
                                        PDnsServer^.IPAddress ;  // Angus
          inc (NetworkParams.DnsServerTot) ;
          if NetworkParams.DnsServerTot >=
                   Length (NetworkParams.DnsServerNames) then
          exit ;
          PDnsServer := PDnsServer.Next ;
        end;
      end ;
    finally
       FreeMem (FixedInfo) ;                     // Angus
    end ;
end;

//------------------------------------------------------------------------------

function ICMPErr2Str( ICMPErrCode: DWORD) : string;
begin
   Result := 'Unknown Error : ' + IntToStr( ICMPErrCode );
   dec( ICMPErrCode, ICMP_ERROR_BASE );
   if ICMPErrCode in [Low(ICMpErr)..High(ICMPErr)] then
     Result := ICMPErr[ ICMPErrCode];
end;


//------------------------------------------------------------------------------

// include bytes in/out for each adaptor
function IpHlpIfTable(var IfTot: integer; var IfRows: TIfRows): integer ;
var
  I,
  TableSize   : integer;
  pBuf, pNext : PChar;
begin
  result := ERROR_NOT_SUPPORTED ;
  if NOT LoadIpHlp then exit ;
  SetLength (IfRows, 0) ;
  IfTot := 0 ; // Angus
  TableSize := 0;
   // first call: get memsize needed
  result := GetIfTable (Nil, @TableSize, false) ;  // Angus
  if result <> ERROR_INSUFFICIENT_BUFFER then exit ;
  GetMem( pBuf, TableSize );
  try
      FillChar (pBuf^, TableSize, #0);  // clear buffer, since W98 does not

   // get table pointer
      result := GetIfTable (PTMibIfTable (pBuf), @TableSize, false) ;
      if result <> NO_ERROR then exit ;
      IfTot := PTMibIfTable (pBuf)^.dwNumEntries ;
      if IfTot = 0 then exit ;
      SetLength (IfRows, IfTot) ;
      pNext := pBuf + SizeOf(IfTot) ;
      for i := 0 to Pred (IfTot) do
      begin
         IfRows [i] := PTMibIfRow (pNext )^ ;
         inc (pNext, SizeOf (TMibIfRow)) ;
      end;
  finally
      FreeMem (pBuf) ;
  end ;
end;

procedure Get_IfTable( List: TStrings );
var
  IfRows        : TIfRows ;
  Error, I      : integer;
  NumEntries    : integer;
  sDescr, sIfName: string ;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  SetLength (IfRows, 0) ;
  Error := IpHlpIfTable (NumEntries, IfRows) ;
  if (Error <> 0) then
      List.Add( SysErrorMessage( GetLastError ) )
  else if NumEntries = 0 then
      List.Add( 'no entries.' )
  else
  begin
      for I := 0 to Pred (NumEntries) do
      begin
          with IfRows [I] do
          begin
             if wszName [1] = #0 then
                 sIfName := ''
             else
                 sIfName := WideCharToString (@wszName) ;  // convert Unicode to string
             sIfName := trim (sIfName) ;
             sDescr := bDescr ;
             sDescr := trim (sDescr);
             List.Add (Format (
               '%0.8x |%3d | %16s |%8d |%12d |%2d |%2d |%10d |%10d | %-s| %-s',
               [dwIndex, dwType, MacAddr2Str( TMacAddress( bPhysAddr ),
               dwPhysAddrLen ), dwMTU, dwSpeed, dwAdminStatus,
               dwOPerStatus, Int64 (dwInOctets), Int64 (dwOutOctets),  // counters are 32-bit
               sIfName, sDescr] )  // Angus, added in/out
               );
          end;
      end ;
  end ;
  SetLength (IfRows, 0) ;  // free memory
end ;

function IpHlpIfEntry(Index: integer; var IfRow: TMibIfRow): integer ;
begin
  result := ERROR_NOT_SUPPORTED ;
  if NOT LoadIpHlp then exit ;
  FillChar (IfRow, SizeOf (TMibIfRow), #0);  // clear buffer, since W98 does not
  IfRow.dwIndex := Index ;
  result := GetIfEntry (@IfRow) ;
end ;

//-----------------------------------------------------------------------------
{ Info on installed adapters }
function IpHlpAdaptersInfo(var AdpTot: integer; var AdpRows: TAdaptorRows): integer ;
var
  BufLen        : DWORD;
  AdapterInfo   : PTIP_ADAPTER_INFO;
  PIpAddr       : PTIP_ADDR_STRING;
  PBuf          : PCHAR ;
  I             : integer ;
begin
  SetLength (AdpRows, 4) ;
  AdpTot := 0 ;
  BufLen := 0 ;
  result := GetAdaptersInfo( Nil, @BufLen );
  if (result <> ERROR_INSUFFICIENT_BUFFER) and (result = NO_ERROR) then exit ;
  GetMem( pBuf, BufLen );
  try
      FillChar (pBuf^, BufLen, #0);  // clear buffer
      result := GetAdaptersInfo( PTIP_ADAPTER_INFO (PBuf), @BufLen );
      if result = NO_ERROR then
      begin
         AdapterInfo := PTIP_ADAPTER_INFO (PBuf) ;
         while ( AdapterInfo <> nil ) do
         begin
            AdpRows [AdpTot].IPAddressTot := 0 ;
            SetLength (AdpRows [AdpTot].IPAddressList, 2) ;
            SetLength (AdpRows [AdpTot].IPMaskList, 2) ;
            AdpRows [AdpTot].GatewayTot := 0 ;
            SetLength (AdpRows [AdpTot].GatewayList, 2) ;
            AdpRows [AdpTot].DHCPTot := 0 ;
            SetLength (AdpRows [AdpTot].DHCPServer, 2) ;
            AdpRows [AdpTot].PrimWINSTot := 0 ;
            SetLength (AdpRows [AdpTot].PrimWINSServer, 2) ;
            AdpRows [AdpTot].SecWINSTot := 0 ;
            SetLength (AdpRows [AdpTot].SecWINSServer, 2) ;
            AdpRows [AdpTot].CurrIPAddress := NULL_IP;
            AdpRows [AdpTot].CurrIPMask := NULL_IP;
            AdpRows [AdpTot].AdapterName := Trim( string( AdapterInfo^.AdapterName ) );
            AdpRows [AdpTot].Description := Trim( string( AdapterInfo^.Description ) );
            AdpRows [AdpTot].MacAddress := MacAddr2Str( TMacAddress(
                                 AdapterInfo^.Address ), AdapterInfo^.AddressLength ) ;
            AdpRows [AdpTot].Index := AdapterInfo^.Index ;
            AdpRows [AdpTot].aType := AdapterInfo^.aType ;
            AdpRows [AdpTot].DHCPEnabled := AdapterInfo^.DHCPEnabled ;
            if AdapterInfo^.CurrentIPAddress <> Nil then
            begin
                AdpRows [AdpTot].CurrIPAddress := AdapterInfo^.CurrentIPAddress.IpAddress ;
                AdpRows [AdpTot].CurrIPMask := AdapterInfo^.CurrentIPAddress.IpMask ;
            end ;

        // get list of IP addresses and masks for IPAddressList
            I := 0 ;
            PIpAddr := @AdapterInfo^.IPAddressList ;
            while (PIpAddr <> Nil) do
            begin
                AdpRows [AdpTot].IPAddressList [I] := PIpAddr.IpAddress ;
                AdpRows [AdpTot].IPMaskList [I] := PIpAddr.IpMask ;
                PIpAddr := PIpAddr.Next ;
                inc (I) ;
                if Length (AdpRows [AdpTot].IPAddressList) <= I then
                begin
                     SetLength (AdpRows [AdpTot].IPAddressList, I * 2) ;
                     SetLength (AdpRows [AdpTot].IPMaskList, I * 2) ;
                end ;
            end ;
            AdpRows [AdpTot].IPAddressTot := I ;

        // get list of IP addresses for GatewayList
            I := 0 ;
            PIpAddr := @AdapterInfo^.GatewayList ;
            while (PIpAddr <> Nil) do
            begin
                AdpRows [AdpTot].GatewayList [I] := PIpAddr.IpAddress ;
                PIpAddr := PIpAddr.Next ;
                inc (I) ;
                if Length (AdpRows [AdpTot].GatewayList) <= I then
                             SetLength (AdpRows [AdpTot].GatewayList, I * 2) ;
            end ;
            AdpRows [AdpTot].GatewayTot := I ;

        // get list of IP addresses for GatewayList
            I := 0 ;
            PIpAddr := @AdapterInfo^.DHCPServer ;
            while (PIpAddr <> Nil) do
            begin
                AdpRows [AdpTot].DHCPServer [I] := PIpAddr.IpAddress ;
                PIpAddr := PIpAddr.Next ;
                inc (I) ;
                if Length (AdpRows [AdpTot].DHCPServer) <= I then
                             SetLength (AdpRows [AdpTot].DHCPServer, I * 2) ;
            end ;
            AdpRows [AdpTot].DHCPTot := I ;

        // get list of IP addresses for PrimaryWINSServer
            I := 0 ;
            PIpAddr := @AdapterInfo^.PrimaryWINSServer ;
            while (PIpAddr <> Nil) do
            begin
                AdpRows [AdpTot].PrimWINSServer [I] := PIpAddr.IpAddress ;
                PIpAddr := PIpAddr.Next ;
                inc (I) ;
                if Length (AdpRows [AdpTot].PrimWINSServer) <= I then
                             SetLength (AdpRows [AdpTot].PrimWINSServer, I * 2) ;
            end ;
            AdpRows [AdpTot].PrimWINSTot := I ;

       // get list of IP addresses for SecondaryWINSServer
            I := 0 ;
            PIpAddr := @AdapterInfo^.SecondaryWINSServer ;
            while (PIpAddr <> Nil) do
            begin
                AdpRows [AdpTot].SecWINSServer [I] := PIpAddr.IpAddress ;
                PIpAddr := PIpAddr.Next ;
                inc (I) ;
                if Length (AdpRows [AdpTot].SecWINSServer) <= I then
                             SetLength (AdpRows [AdpTot].SecWINSServer, I * 2) ;
            end ;
            AdpRows [AdpTot].SecWINSTot := I ;

            AdpRows [AdpTot].LeaseObtained := AdapterInfo^.LeaseObtained ;
            AdpRows [AdpTot].LeaseExpires := AdapterInfo^.LeaseExpires ;

            inc (AdpTot) ;
            if Length (AdpRows) <= AdpTot then
                            SetLength (AdpRows, AdpTot * 2) ;  // more memory
            AdapterInfo := AdapterInfo^.Next;
         end ;
         SetLength (AdpRows, AdpTot) ;
      end ;
  finally
      FreeMem( pBuf );
  end ;
end ;

procedure Get_AdaptersInfo( List: TStrings );
var
  AdpTot: integer;
  AdpRows: TAdaptorRows ;
  Error: DWORD ;
  I: integer ;
  //J: integer ;  jpt - see below
  //S: string ;        id.
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  SetLength (AdpRows, 0) ;
  AdpTot := 0 ;
  Error := IpHlpAdaptersInfo(AdpTot, AdpRows) ;
  if (Error <> 0) then
      List.Add( SysErrorMessage( GetLastError ) )
  else if AdpTot = 0 then
      List.Add( 'no entries.' )
  else
  begin
      for I := 0 to Pred (AdpTot) do
      begin
        with AdpRows [I] do
        begin
            //List.Add(AdapterName + '|' + Description ); // jpt : not useful
            List.Add( Format('%8.8x | %6s | %16s | %2d | %16s | %16s | %16s',
                [Index, ifTypeStr[aType], MacAddress, DHCPEnabled,
                GatewayList [0], DHCPServer [0], PrimWINSServer [0]] ) );
            {if IPAddressTot <> 0 then    // jpt : not useful
            begin
                S := '' ;
                for J := 0 to Pred (IPAddressTot) do
                        S := S + IPAddressList [J] + '/' + IPMaskList [J] + ' | ' ;
                List.Add(IntToStr (IPAddressTot) + ' IP Addresse(s): ' + S);
            end ;
            List.Add( '  ' ); }
        end ;
      end ;
  end ;
  SetLength (AdpRows, 0) ;
end ;

//-----------------------------------------------------------------------------
{ get round trip time and hopcount to indicated IP }
function Get_RTTAndHopCount( IPAddr: DWORD; MaxHops: Longint; var RTT: Longint;
  var HopCount: Longint ): integer;
begin
  if not GetRTTAndHopCount( IPAddr, @HopCount, MaxHops, @RTT ) then
  begin
    Result := GetLastError;
    RTT := -1; // Destination unreachable, BAD_HOST_NAME,etc...
    HopCount := -1;
  end
  else
    Result := NO_ERROR;
end;

//-----------------------------------------------------------------------------
{ ARP-table lists relations between remote IP and remote MAC-address.
 NOTE: these are cached entries ;when there is no more network traffic to a
 node, entry is deleted after a few minutes.
}
procedure Get_ARPTable( List: TStrings );
var
  IPNetRow      : TMibIPNetRow;
  TableSize     : DWORD;
  NumEntries    : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  // first call: get table length
  TableSize := 0;
  ErrorCode := GetIPNetTable( Nil, @TableSize, false );   // Angus
  //
  if ErrorCode = ERROR_NO_DATA then
  begin
    List.Add( ' ARP-cache empty.' );
    EXIT;
  end;
  // get table
  GetMem( pBuf, TableSize );
  NumEntries := 0 ;
  try
  ErrorCode := GetIpNetTable( PTMIBIPNetTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then
  begin
    NumEntries := PTMIBIPNetTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then // paranoia striking, but you never know...
    begin
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do
      begin
        IPNetRow := PTMIBIPNetRow( PBuf )^;
        with IPNetRow do
          List.Add( Format( '%8x | %12s | %16s | %10s',
                           [dwIndex, MacAddr2Str( bPhysAddr, dwPhysAddrLen ),
                           IPAddr2Str( dwAddr ), sipNetToMediaTypeString[dwType]
                           ]));
        inc( pBuf, SizeOf( IPNetRow ) );
      end;
    end
    else
      List.Add( ' ARP-cache empty.' );
  end
  else
    List.Add( SysErrorMessage( ErrorCode ) );

  // we _must_ restore pointer!
  finally
      dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( IPNetRow ) );
      FreeMem( pBuf );
  end ;
end;


//------------------------------------------------------------------------------
procedure Get_TCPTable( List: TStrings );
var
  TCPRow        : TMIBTCPRow;
  i,
    NumEntries  : integer;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  DestIP        : string;
  pBuf          : PChar;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  RecentIPs.Clear;
  // first call : get size of table
  TableSize := 0;
  NumEntries := 0 ;
  ErrorCode := GetTCPTable(Nil, @TableSize, false );  // Angus
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    EXIT;

  // get required memory size, call again
  GetMem( pBuf, TableSize );
  // get table
  ErrorCode := GetTCPTable( PTMIBTCPTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then
  begin

    NumEntries := PTMIBTCPTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then
    begin
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do
      begin
        TCPRow := PTMIBTCPRow( pBuf )^; // get next record
        with TCPRow do
        begin
          if dwRemoteAddr = 0 then
            dwRemotePort := 0;
          DestIP := IPAddr2Str( dwRemoteAddr );
          List.Add(
            Format( '%15s : %-7s | %15s : %-7s | %-16s',
            [IpAddr2Str( dwLocalAddr ),
            Port2Svc( Port2Wrd( dwLocalPort ) ),
              DestIP,
              Port2Svc( Port2Wrd( dwRemotePort ) ),
              stcpConnStateString[dwState]
              ] ) );
         //
            if (not ( dwRemoteAddr = 0 ))
            and ( RecentIps.IndexOf(DestIP) = -1 ) then
               RecentIPs.Add( DestIP );
        end;
        inc( pBuf, SizeOf( TMIBTCPRow ) );
      end;
    end;
  end
  else
    List.Add( SyserrorMessage( ErrorCode ) );
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibTCPRow ) );
  FreeMem( pBuf );
end;

//------------------------------------------------------------------------------
procedure Get_TCPStatistics( List: TStrings );
var
  TCPStats      : TMibTCPStats;
  ErrorCode     : DWORD;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  if NOT LoadIpHlp then exit ;
  ErrorCode := GetTCPStatistics( @TCPStats );
  if ErrorCode = NO_ERROR then
    with TCPStats do
    begin
      List.Add( 'Retransmission algorithm : ' + sTcpRtoAlgorithmString[dwRTOAlgorithm] );
      List.Add( 'Minimum Timeout         : ' + IntToStr( dwRTOMin ) + ' ms' );
      List.Add( 'Maximum Timeout         : ' + IntToStr( dwRTOMax ) + ' ms' );
      List.Add( 'Maximum Pend.Connections : ' + IntToStr( dwRTOAlgorithm ) );
      List.Add( 'Active Opens             : ' + IntToStr( dwActiveOpens ) );
      List.Add( 'Passive Opens            : ' + IntToStr( dwPassiveOpens ) );
      List.Add( 'Failed Open Attempts     : ' + IntToStr( dwAttemptFails ) );
      List.Add( 'Established conn. Reset  : ' + IntToStr( dwEstabResets ) );
      List.Add( 'Current Established Conn.: ' + IntToStr( dwCurrEstab ) );
      List.Add( 'Segments Received        : ' + IntToStr( dwInSegs ) );
      List.Add( 'Segments Sent            : ' + IntToStr( dwOutSegs ) );
      List.Add( 'Segments Retransmitted   : ' + IntToStr( dwReTransSegs ) );
      List.Add( 'Incoming Errors          : ' + IntToStr( dwInErrs ) );
      List.Add( 'Outgoing Resets          : ' + IntToStr( dwOutRsts ) );
      List.Add( 'Cumulative Connections   : ' + IntToStr( dwNumConns ) );
    end
  else
    List.Add( SyserrorMessage( ErrorCode ) );
end;

function IpHlpTCPStatistics (var TCPStats: TMibTCPStats): integer ;
begin
    result := ERROR_NOT_SUPPORTED ;
    if NOT LoadIpHlp then exit ;
    result := GetTCPStatistics( @TCPStats );
end;

//------------------------------------------------------------------------------
procedure Get_UDPTable( List: TStrings );
var
  UDPRow        : TMIBUDPRow;
  i,
    NumEntries  : integer;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  pBuf          : PChar;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;

  // first call : get size of table
  TableSize := 0;
  NumEntries := 0 ;
  ErrorCode := GetUDPTable(Nil, @TableSize, false );
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    EXIT;

  // get required size of memory, call again
  GetMem( pBuf, TableSize );

  // get table
  ErrorCode := GetUDPTable( PTMIBUDPTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then
  begin
    NumEntries := PTMIBUDPTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then
    begin
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do
      begin
        UDPRow := PTMIBUDPRow( pBuf )^; // get next record
        with UDPRow do
          List.Add( Format( '%15s : %-6s',
            [IpAddr2Str( dwLocalAddr ),
            Port2Svc( Port2Wrd( dwLocalPort ) )
              ] ) );
        inc( pBuf, SizeOf( TMIBUDPRow ) );
      end;
    end
    else
      List.Add( 'no entries.' );
  end
  else
    List.Add( SyserrorMessage( ErrorCode ) );
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibUDPRow ) );
  FreeMem( pBuf );
end;

//------------------------------------------------------------------------------
procedure Get_IPAddrTable( List: TStrings );
var
  IPAddrRow     : TMibIPAddrRow;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
  NumEntries    : DWORD;
begin
  if not Assigned( List ) then EXIT;
  List.Clear;
  TableSize := 0; ;
  NumEntries := 0 ;
  // first call: get table length
  ErrorCode := GetIpAddrTable(Nil, @TableSize, true );  // Angus
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    EXIT;

  GetMem( pBuf, TableSize );
  // get table
  ErrorCode := GetIpAddrTable( PTMibIPAddrTable( pBuf ), @TableSize, true );
  if ErrorCode = NO_ERROR then
  begin
    NumEntries := PTMibIPAddrTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then
    begin
      inc( pBuf, SizeOf( DWORD ) );
      for i := 1 to NumEntries do
      begin
        IPAddrRow := PTMIBIPAddrRow( pBuf )^;
        with IPAddrRow do
          List.Add( Format( '%8.8x | %15s | %15s | %15s | %8.8d',
            [dwIndex,
            IPAddr2Str( dwAddr ),
              IPAddr2Str( dwMask ),
              IPAddr2Str( dwBCastAddr ),
              dwReasmSize
              ] ) );
        inc( pBuf, SizeOf( TMIBIPAddrRow ) );
      end;
    end
    else
      List.Add( 'no entries.' );
  end
  else
    List.Add( SysErrorMessage( ErrorCode ) );

  // we must restore pointer!
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( IPAddrRow ) );
  FreeMem( pBuf );
end;

//-----------------------------------------------------------------------------
{ gets entries in routing table; equivalent to "Route Print" }
procedure Get_IPForwardTable( List: TStrings );
var
  IPForwRow     : TMibIPForwardRow;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
  NumEntries    : DWORD;
begin

  if not Assigned( List ) then EXIT;
  List.Clear;
  TableSize := 0;

  // first call: get table length
  NumEntries := 0 ;
  ErrorCode := GetIpForwardTable(Nil, @TableSize, true);
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    EXIT;

  // get table
  GetMem( pBuf, TableSize );
  ErrorCode := GetIpForwardTable( PTMibIPForwardTable( pBuf ), @TableSize, true);
  if ErrorCode = NO_ERROR then
  begin
    NumEntries := PTMibIPForwardTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then
    begin
      inc( pBuf, SizeOf( DWORD ) );
      for i := 1 to NumEntries do
      begin
        IPForwRow := PTMibIPForwardRow( pBuf )^;
        with IPForwRow do
        begin
          if (dwForwardType < 1)
          or (dwForwardType > 4) then
                   dwForwardType := 1 ;   // Angus, allow for bad value
          List.Add( Format(
            '%15s | %15s | %15s | %8.8x | %7s |   %5.5d |  %7s |   %2.2d',
            [IPAddr2Str( dwForwardDest ),
            IPAddr2Str( dwForwardMask ),
              IPAddr2Str( dwForwardNextHop ),
              dwForwardIFIndex,
              sIpRouteTypeString[dwForwardType],
              dwForwardNextHopAS,
              sIpRouteProtoString[dwForwardProto],
              dwForwardMetric1
              ] ) );
        end ;
        inc( pBuf, SizeOf( TMibIPForwardRow ) );
      end;
    end
    else
      List.Add( 'no entries.' );
  end
  else
    List.Add( SysErrorMessage( ErrorCode ) );
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibIPForwardRow ) );
  FreeMem( pBuf );
end;

//------------------------------------------------------------------------------
procedure Get_IPStatistics( List: TStrings );
var
  IPStats       : TMibIPStats;
  ErrorCode     : integer;
begin
  if not Assigned( List ) then EXIT;
  if NOT LoadIpHlp then exit ;
  ErrorCode := GetIPStatistics( @IPStats );
  if ErrorCode = NO_ERROR then
  begin
    List.Clear;
    with IPStats do
    begin
      if dwForwarding = 1 then
        List.add( 'Forwarding Enabled      : ' + 'Yes' )
      else
        List.add( 'Forwarding Enabled      : ' + 'No' );
      List.add( 'Default TTL             : ' + inttostr( dwDefaultTTL ) );
      List.add( 'Datagrams Received      : ' + inttostr( dwInReceives ) );
      List.add( 'Header Errors     (In)  : ' + inttostr( dwInHdrErrors ) );
      List.add( 'Address Errors    (In)  : ' + inttostr( dwInAddrErrors ) );
      List.add( 'Datagrams Forwarded     : ' + inttostr( dwForwDatagrams ) );   // Angus
      List.add( 'Unknown Protocols (In)  : ' + inttostr( dwInUnknownProtos ) );
      List.add( 'Datagrams Discarded     : ' + inttostr( dwInDiscards ) );
      List.add( 'Datagrams Delivered     : ' + inttostr( dwInDelivers ) );
      List.add( 'Requests Out            : ' + inttostr( dwOutRequests ) );
      List.add( 'Routings Discarded      : ' + inttostr( dwRoutingDiscards ) );
      List.add( 'No Routes        (Out)  : ' + inttostr( dwOutNoRoutes ) );
      List.add( 'Reassemble TimeOuts     : ' + inttostr( dwReasmTimeOut ) );
      List.add( 'Reassemble Requests     : ' + inttostr( dwReasmReqds ) );
      List.add( 'Succesfull Reassemblies : ' + inttostr( dwReasmOKs ) );
      List.add( 'Failed Reassemblies     : ' + inttostr( dwReasmFails ) );
      List.add( 'Succesful Fragmentations: ' + inttostr( dwFragOKs ) );
      List.add( 'Failed Fragmentations   : ' + inttostr( dwFragFails ) );
      List.add( 'Datagrams Fragmented    : ' + inttostr( dwFRagCreates ) );
      List.add( 'Number of Interfaces    : ' + inttostr( dwNumIf ) );
      List.add( 'Number of IP-addresses  : ' + inttostr( dwNumAddr ) );
      List.add( 'Routes in RoutingTable  : ' + inttostr( dwNumRoutes ) );
    end;
  end
  else
    List.Add( SysErrorMessage( ErrorCode ) );
end;

function IpHlpIPStatistics (var IPStats: TMibIPStats): integer ;      // Angus
begin
    result := ERROR_NOT_SUPPORTED ;
    if NOT LoadIpHlp then exit ;
    result := GetIPStatistics( @IPStats );
end ;

//------------------------------------------------------------------------------
procedure Get_UdpStatistics( List: TStrings );
var
  UdpStats      : TMibUDPStats;
  ErrorCode     : integer;
begin
  if not Assigned( List ) then EXIT;
  ErrorCode := GetUDPStatistics( @UdpStats );
  if ErrorCode = NO_ERROR then
  begin
    List.Clear;
    with UDPStats do
    begin
      List.add( 'Datagrams (In)    : ' + inttostr( dwInDatagrams ) );
      List.add( 'Datagrams (Out)   : ' + inttostr( dwOutDatagrams ) );
      List.add( 'No Ports          : ' + inttostr( dwNoPorts ) );
      List.add( 'Errors    (In)    : ' + inttostr( dwInErrors ) );
      List.add( 'UDP Listen Ports  : ' + inttostr( dwNumAddrs ) );
    end;
  end
  else
    List.Add( SysErrorMessage( ErrorCode ) );
end;

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
function IpHlpUdpStatistics (UdpStats: TMibUDPStats): integer ;     // Angus
begin
    result := ERROR_NOT_SUPPORTED ;
    if NOT LoadIpHlp then exit ;
    result := GetUDPStatistics (@UdpStats) ;
end ;

//------------------------------------------------------------------------------
procedure Get_ICMPStats( ICMPIn, ICMPOut: TStrings );
var
  ErrorCode     : DWORD;
  ICMPStats     : PTMibICMPInfo;
begin
  if ( ICMPIn = nil ) or ( ICMPOut = nil ) then EXIT;
  ICMPIn.Clear;
  ICMPOut.Clear;
  New( ICMPStats );
  ErrorCode := GetICMPStatistics( ICMPStats );
  if ErrorCode = NO_ERROR then
  begin
    with ICMPStats.InStats do begin
      ICMPIn.Add( 'Messages received    : ' + IntToStr( dwMsgs ) );
      ICMPIn.Add( 'Errors               : ' + IntToStr( dwErrors ) );
      ICMPIn.Add( 'Dest. Unreachable    : ' + IntToStr( dwDestUnreachs ) );
      ICMPIn.Add( 'Time Exceeded        : ' + IntToStr( dwTimeEcxcds ) );
      ICMPIn.Add( 'Param. Problems      : ' + IntToStr( dwParmProbs ) );
      ICMPIn.Add( 'Source Quench        : ' + IntToStr( dwSrcQuenchs ) );
      ICMPIn.Add( 'Redirects            : ' + IntToStr( dwRedirects ) );
      ICMPIn.Add( 'Echo Requests        : ' + IntToStr( dwEchos ) );
      ICMPIn.Add( 'Echo Replies         : ' + IntToStr( dwEchoReps ) );
      ICMPIn.Add( 'Timestamp Requests   : ' + IntToStr( dwTimeStamps ) );
      ICMPIn.Add( 'Timestamp Replies    : ' + IntToStr( dwTimeStampReps ) );
      ICMPIn.Add( 'Addr. Masks Requests : ' + IntToStr( dwAddrMasks ) );
      ICMPIn.Add( 'Addr. Mask Replies   : ' + IntToStr( dwAddrReps ) );
    end;
     //
    with ICMPStats.OutStats do
    begin
      ICMPOut.Add( 'Messages sent        : ' + IntToStr( dwMsgs ) );
      ICMPOut.Add( 'Errors               : ' + IntToStr( dwErrors ) );
      ICMPOut.Add( 'Dest. Unreachable    : ' + IntToStr( dwDestUnreachs ) );
      ICMPOut.Add( 'Time Exceeded        : ' + IntToStr( dwTimeEcxcds ) );
      ICMPOut.Add( 'Param. Problems      : ' + IntToStr( dwParmProbs ) );
      ICMPOut.Add( 'Source Quench        : ' + IntToStr( dwSrcQuenchs ) );
      ICMPOut.Add( 'Redirects            : ' + IntToStr( dwRedirects ) );
      ICMPOut.Add( 'Echo Requests        : ' + IntToStr( dwEchos ) );
      ICMPOut.Add( 'Echo Replies         : ' + IntToStr( dwEchoReps ) );
      ICMPOut.Add( 'Timestamp Requests   : ' + IntToStr( dwTimeStamps ) );
      ICMPOut.Add( 'Timestamp Replies    : ' + IntToStr( dwTimeStampReps ) );
      ICMPOut.Add( 'Addr. Masks Requests : ' + IntToStr( dwAddrMasks ) );
      ICMPOut.Add( 'Addr. Mask Replies   : ' + IntToStr( dwAddrReps ) );
    end;
  end
  else
    IcmpIn.Add( SysErrorMessage( ErrorCode ) );
  Dispose( ICMPStats );
end;

//------------------------------------------------------------------------------
procedure Get_RecentDestIPs( List: TStrings );
begin
  if Assigned( List ) then
    List.Assign( RecentIPs )
end;

//--------------------------------
procedure DoNetworkParams(sg : TStringGrid);
var
  NetworkParams : TNetworkParams;
  i, ErrorCode  : integer;
  //*******************************
  procedure AppendRow(const Parameter, Value : string);
  var
    RowIdx: integer;
  begin
    with sg do begin
      RowIdx := RowCount-1;
      Cells[0,RowIdx] := Parameter;
      Cells[1,RowIdx] := Value;
      
      RowCount := RowCount + 1;
    end;
  end;
  //*******************************
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  ErrorCode := IpHlpNetworkParams (NetworkParams) ;

  if ErrorCode <> 0 then begin
    AppendRow('Error', SysErrorMessage (ErrorCode));
    exit;
  end ;

  with NetworkParams do begin
    AppendRow('Host name',HostName);
    AppendRow('Domain name',DomainName);
    AppendRow('NETBIOS node type', NETBIOSTypes[NodeType]);
    AppendRow('DHCP scope', ScopeID);
    AppendRow('Routing enabled', IntToStr(EnableRouting));
    AppendRow('Proxy enabled', IntToStr(EnableProxy));
    AppendRow('DNS enabled', IntToStr(EnableDNS));
    if DnsServerTot <> 0 then begin
      for i:= 0 to Pred (DnsServerTot) do begin
        AppendRow('DNS server address', DnsServerNames[I]);
      end;
    end; // if DnsServerTot <> 0
  end;
end;


//-----------------
procedure DoArpTable(sg : TStringGrid);
var
  IPNetRow      : TMibIPNetRow;
  TableSize     : DWORD;
  NumEntries    : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
  //*************************************
  procedure AppendRow(AdapterIndex, RemoteMAC, RemoteIp, ArpType : string);
  var
    RowIdx: integer;
  begin
    with sg do begin
      RowIdx := RowCount-1;
      Cells[0,RowIdx] := AdapterIndex;
      Cells[1,RowIdx] := RemoteMAC;
      Cells[2,RowIdx] := RemoteIp;
      Cells[3,RowIdx] := ArpType;
    
      RowCount := RowCount + 1;
    end;
  end;
  //*************************************
begin
  if not Assigned(sg) then
    exit;
    
  sg.RowCount := 2;

  // first call: get table length
  TableSize := 0;
  ErrorCode := GetIPNetTable( Nil, @TableSize, false );   // Angus
  //
  if ErrorCode = ERROR_NO_DATA then begin
    AppendRow('ARP-cache empty.','','','' );
    exit;
  end;

  // get table
  GetMem( pBuf, TableSize );
  NumEntries := 0 ;
  try
  ErrorCode := GetIpNetTable( PTMIBIPNetTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then begin
    NumEntries := PTMIBIPNetTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then begin // paranoia striking, but you never know...
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do begin
        IPNetRow := PTMIBIPNetRow( PBuf )^;
        with IPNetRow do
          AppendRow(HexLS(dwIndex),
                    MacAddr2Str( bPhysAddr, dwPhysAddrLen ),
                    IPAddr2Str( dwAddr ),
                    sipNetToMediaTypeString[dwType]);
        inc( pBuf, SizeOf( IPNetRow ) );
      end; // for
    end else // if NumEntries > 0
      AppendRow('ARP-cache empty.','','','' );
  end else //   if ErrorCode = NO_ERROR
    AppendRow('Error', SysErrorMessage( ErrorCode ), '','');

  // we _must_ restore pointer!
  finally
      dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( IPNetRow ) );
      FreeMem( pBuf );
  end ;

end;

//------------------------
procedure DoTcpTable(sg: TStringGrid);
var
  TCPRow        : TMIBTCPRow;
  i,NumEntries  : integer;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  DestIP        : string;
  pBuf          : PChar;
  //************************************************
  procedure AppendRow(LocalIP, LocalPort, RemoteIP, RemotePort, State : string);
  begin
    sg.Cells[0,sg.RowCount-1] := LocalIp;
    sg.Cells[1,sg.RowCount-1] := LocalPort;
    sg.Cells[2,sg.RowCount-1] := RemoteIp;
    sg.Cells[3,sg.RowCount-1] := RemotePort;
    sg.Cells[4,sg.RowCount-1] := State;
    sg.RowCount := sg.RowCount + 1;
  end;
  //************************************************
begin
  if not Assigned(sg) then
    exit;
    
  sg.RowCount := 2;

  RecentIPs.Clear;

  // first call : get size of table
  TableSize := 0;
  NumEntries := 0 ;
  ErrorCode := GetTCPTable(Nil, @TableSize, false );  // Angus
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    exit;

  // get required memory size, call again
  GetMem( pBuf, TableSize );
  // get table
  ErrorCode := GetTCPTable( PTMIBTCPTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then begin
    NumEntries := PTMIBTCPTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then begin
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do begin
        TCPRow := PTMIBTCPRow( pBuf )^; // get next record
        with TCPRow do begin
          if dwRemoteAddr = 0 then
            dwRemotePort := 0;
          DestIP := IPAddr2Str( dwRemoteAddr );
          AppendRow( IpAddr2Str( dwLocalAddr ),
                     Port2Svc( Port2Wrd( dwLocalPort ) ),
                     DestIP,
                     Port2Svc( Port2Wrd( dwRemotePort ) ),
                     stcpConnStateString[dwState] );
         //
            if (not ( dwRemoteAddr = 0 ))
            and ( RecentIps.IndexOf(DestIP) = -1 ) then
               RecentIPs.Add( DestIP );
        end;  // with TCPRow
        inc( pBuf, SizeOf( TMIBTCPRow ) );
      end;
    end;
  end
  else
    AppendRow('Error', SyserrorMessage( ErrorCode ), '','','' );
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibTCPRow ) );
  FreeMem( pBuf );
end;

//----------------------------
procedure DoUdpTable(sg : TStringGrid);
var
  UDPRow        : TMIBUDPRow;
  i,NumEntries  : integer;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  pBuf          : PChar;
  //************************************************
  procedure AppendRow(LocalIp, Port : string);
  begin
    sg.Cells[0,sg.RowCount-1] := LocalIp;
    sg.Cells[1,sg.RowCount-1] := Port;
    sg.RowCount := sg.RowCount + 1;
  end;
  //************************************************
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  // first call : get size of table
  TableSize := 0;
  NumEntries := 0 ;
  ErrorCode := GetUDPTable(Nil, @TableSize, false );
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    exit;

  // get required size of memory, call again
  GetMem( pBuf, TableSize );

  // get table
  ErrorCode := GetUDPTable( PTMIBUDPTable( pBuf ), @TableSize, false );
  if ErrorCode = NO_ERROR then begin
    NumEntries := PTMIBUDPTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then begin
      inc( pBuf, SizeOf( DWORD ) ); // get past table size
      for i := 1 to NumEntries do begin
        UDPRow := PTMIBUDPRow( pBuf )^; // get next record
        with UDPRow do
          AppendRow(IpAddr2Str( dwLocalAddr ), Port2Svc( Port2Wrd( dwLocalPort ) ));
        inc( pBuf, SizeOf( TMIBUDPRow ) );
      end;
    end
    else
      AppendRow('no entries.', '' );
  end else
    AppendRow('Error', SyserrorMessage( ErrorCode ));
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibUDPRow ) );
  FreeMem( pBuf );
end;

//-------------------------------------
procedure DoTCPStatistics(sg : TStringGrid);
var
  TCPStats      : TMibTCPStats;
  ErrorCode     : DWORD;
  //=================
  procedure AppendRow(Parameter, Value: string);
  begin
    sg.Cells[0,sg.RowCount-1] := Parameter;
    sg.Cells[1,sg.RowCount-1] := Value;
    sg.RowCount := sg.RowCount + 1;
  end;
  //=================
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;
  
  if NOT LoadIpHlp then
    exit;
  ErrorCode := GetTCPStatistics( @TCPStats );
  if ErrorCode = NO_ERROR then with TCPStats do begin
    AppendRow('Retransmission algorithm', sTcpRtoAlgorithmString[dwRTOAlgorithm] );
    AppendRow('Minimum Timeout', IntToStr( dwRTOMin ) + ' ms' );
    AppendRow('Maximum Timeout', IntToStr( dwRTOMax ) + ' ms' );
    AppendRow('Maximum Pending Connections', IntToStr( dwRTOAlgorithm ) );
    AppendRow('Active Opens', IntToStr( dwActiveOpens ) );
    AppendRow('Passive Opens', IntToStr( dwPassiveOpens ) );
    AppendRow('Failed Open Attempts', IntToStr( dwAttemptFails ) );
    AppendRow('Established connections Reset', IntToStr( dwEstabResets ) );
    AppendRow('Current Established Connections', IntToStr( dwCurrEstab ) );
    AppendRow('Segments Received', IntToStr( dwInSegs ) );
    AppendRow('Segments Sent', IntToStr( dwOutSegs ) );
    AppendRow('Segments Retransmitted', IntToStr( dwReTransSegs ) );
    AppendRow('Incoming Errors', IntToStr( dwInErrs ) );
    AppendRow('Outgoing Resets', IntToStr( dwOutRsts ) );
    AppendRow('Cumulative Connections', IntToStr( dwNumConns ) );
  end else
    AppendRow('Error', SyserrorMessage( ErrorCode ));
end;

//---------------------------------------
procedure DoICMPInputStatistics( sg : TStringGrid );
var
  ErrorCode     : DWORD;
  ICMPStats     : PTMibICMPInfo;
  //=================
  procedure AppendRow(Parameter, Value: string);
  begin
    sg.Cells[0,sg.RowCount-1] := Parameter;
    sg.Cells[1,sg.RowCount-1] := Value;
    
    sg.RowCount := sg.RowCount + 1;
  end;
  //=================
begin
  if not Assigned(sg) then
    exit;
    
  sg.RowCount := 2;

  New( ICMPStats );
  ErrorCode := GetICMPStatistics( ICMPStats );
  if ErrorCode = NO_ERROR then begin
    with ICMPStats.InStats do begin
      AppendRow('Messages received', IntToStr( dwMsgs ) );
      AppendRow('Errors', IntToStr( dwErrors ) );
      AppendRow('Destination Unreachable', IntToStr( dwDestUnreachs ) );
      AppendRow('Time Exceeded', IntToStr( dwTimeEcxcds ) );
      AppendRow('Parameter Problems', IntToStr( dwParmProbs ) );
      AppendRow('Source Quench', IntToStr( dwSrcQuenchs ) );
      AppendRow('Redirects', IntToStr( dwRedirects ) );
      AppendRow('Echo Requests', IntToStr( dwEchos ) );
      AppendRow('Echo Replies', IntToStr( dwEchoReps ) );
      AppendRow('Timestamp Requests', IntToStr( dwTimeStamps ) );
      AppendRow('Timestamp Replies', IntToStr( dwTimeStampReps ) );
      AppendRow('Address Masks Requests', IntToStr( dwAddrMasks ) );
      AppendRow('Address Mask Replies', IntToStr( dwAddrReps ) );
    end;
  end else
    AppendRow('Error', SysErrorMessage( ErrorCode ));
  Dispose( ICMPStats );
end;

//-------------------------------------------------
procedure DoIcmpOutputStatistics(sg : TStringGrid);
var
  ErrorCode     : DWORD;
  ICMPStats     : PTMibICMPInfo;
  //=================
  procedure AppendRow(Parameter, Value: string);
  begin
    sg.Cells[0,sg.RowCount-1] := Parameter;
    sg.Cells[1,sg.RowCount-1] := Value;
    sg.RowCount := sg.RowCount + 1;
  end;
  //=================
  begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  New( ICMPStats );
  ErrorCode := GetICMPStatistics( ICMPStats );
  if ErrorCode = NO_ERROR then begin
    with ICMPStats.OutStats do begin
      AppendRow('Messages sent', IntToStr( dwMsgs ) );
      AppendRow('Errors', IntToStr( dwErrors ) );
      AppendRow('Destination Unreachable', IntToStr( dwDestUnreachs ) );
      AppendRow('Time Exceeded', IntToStr( dwTimeEcxcds ) );
      AppendRow('Parameter Problems', IntToStr( dwParmProbs ) );
      AppendRow('Source Quench', IntToStr( dwSrcQuenchs ) );
      AppendRow('Redirects', IntToStr( dwRedirects ) );
      AppendRow('Echo Requests', IntToStr( dwEchos ) );
      AppendRow('Echo Replies', IntToStr( dwEchoReps ) );
      AppendRow('Timestamp Requests', IntToStr( dwTimeStamps ) );
      AppendRow('Timestamp Replies', IntToStr( dwTimeStampReps ) );
      AppendRow('Address Masks Requests', IntToStr( dwAddrMasks ) );
      AppendRow('Address Mask Replies', IntToStr( dwAddrReps ) );
    end;
  end else
    AppendRow('Error', SysErrorMessage( ErrorCode ));
  Dispose( ICMPStats );
end; {-- procedure DoIcmpOutput}

//------------------------------------------------------------------------------
procedure DoUdpStatistics(sg : TStringGrid);
var
  UdpStats      : TMibUDPStats;
  ErrorCode     : integer;
  //=================
  procedure AppendRow(Parameter, Value : string);
  begin
    sg.Cells[0,sg.RowCount-1] := Parameter;
    sg.Cells[1,sg.RowCount-1] := Value;
    sg.RowCount := sg.RowCount + 1;
  end;
  //=================
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  ErrorCode := GetUDPStatistics( @UdpStats );
  if ErrorCode = NO_ERROR then begin
    with UDPStats do begin
      AppendRow('Datagrams (In)', inttostr( dwInDatagrams ) );
      AppendRow('Datagrams (Out)', inttostr( dwOutDatagrams ) );
      AppendRow('No Ports', inttostr( dwNoPorts ) );
      AppendRow('Errors (In)', inttostr( dwInErrors ) );
      AppendRow('UDP Listen Ports', inttostr( dwNumAddrs ) );
    end;
  end else
    AppendRow('Error', SysErrorMessage( ErrorCode ));
end;

//---------------------------------------------------
procedure DoIpStatistics(sg : TStringGrid);
var
  IPStats       : TMibIPStats;
  ErrorCode     : integer;
  //=================
  procedure AppendRow(Parameter, Value : string);
  begin
    sg.Cells[0,sg.RowCount-1] := Parameter;
    sg.Cells[1,sg.RowCount-1] := Value;
    sg.RowCount := sg.RowCount + 1;
  end;
  //=================
begin
  if not Assigned(sg) then
    exit;
  if NOT LoadIpHlp then
    exit;
    
  sg.RowCount := 2;

  ErrorCode := GetIPStatistics( @IPStats );
  if ErrorCode = NO_ERROR then begin
    with IPStats do begin
      if dwForwarding = 1 then
        AppendRow('Forwarding Enabled', 'Yes' )
      else
        AppendRow('Forwarding Enabled', 'No' );

      AppendRow('Default TTL', inttostr( dwDefaultTTL ) );
      AppendRow('Datagrams Received', inttostr( dwInReceives ) );
      AppendRow('Header Errors (In)', inttostr( dwInHdrErrors ) );
      AppendRow('Address Errors (In)', inttostr( dwInAddrErrors ) );
      AppendRow('Datagrams Forwarded', inttostr( dwForwDatagrams ) );   // Angus
      AppendRow('Unknown Protocols (In)', inttostr( dwInUnknownProtos ) );
      AppendRow('Datagrams Discarded', inttostr( dwInDiscards ) );
      AppendRow('Datagrams Delivered', inttostr( dwInDelivers ) );
      AppendRow('Requests Out', inttostr( dwOutRequests ) );
      AppendRow('Routings Discarded', inttostr( dwRoutingDiscards ) );
      AppendRow('No Routes (Out)', inttostr( dwOutNoRoutes ) );
      AppendRow('Reassemble TimeOuts', inttostr( dwReasmTimeOut ) );
      AppendRow('Reassemble Requests', inttostr( dwReasmReqds ) );
      AppendRow('Successfull Reassemblies', inttostr( dwReasmOKs ) );
      AppendRow('Failed Reassemblies', inttostr( dwReasmFails ) );
      AppendRow('Successful Fragmentations', inttostr( dwFragOKs ) );
      AppendRow('Failed Fragmentations', inttostr( dwFragFails ) );
      AppendRow('Datagrams Fragmented', inttostr( dwFRagCreates ) );
      AppendRow('Number of Interfaces', inttostr( dwNumIf ) );
      AppendRow('Number of IP-addresses', inttostr( dwNumAddr ) );
      AppendRow('Routes in Routing Table', inttostr( dwNumRoutes ) );
    end;
  end else
    AppendRow('Error', SysErrorMessage( ErrorCode ));
end;

//------------------------------------------------------------------------------
procedure DoIPAddrTable(sg : TStringGrid);
var
  IPAddrRow     : TMibIPAddrRow;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
  NumEntries    : DWORD;
  //***********************************
  procedure AppendRow(const index,ip,subnet,broadcast,reasm: string);
  begin
    sg.Cells[0,sg.RowCount-1] := index;
    sg.Cells[1,sg.RowCount-1] := ip;
    sg.Cells[2,sg.RowCount-1] := subnet;
    sg.Cells[3,sg.RowCount-1] := broadcast;
    sg.Cells[4,sg.RowCount-1] := reasm;
    sg.RowCount := sg.RowCount + 1;
  end;
  //***********************************
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  TableSize := 0; ;
  NumEntries := 0 ;
  // first call: get table length
  ErrorCode := GetIpAddrTable(Nil, @TableSize, true );  // Angus
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    exit;

  GetMem( pBuf, TableSize );
  // get table
  ErrorCode := GetIpAddrTable( PTMibIPAddrTable( pBuf ), @TableSize, true );
  if ErrorCode = NO_ERROR then begin
    NumEntries := PTMibIPAddrTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then begin
      inc( pBuf, SizeOf( DWORD ) );
      for i := 1 to NumEntries do begin
        IPAddrRow := PTMIBIPAddrRow( pBuf )^;
        with IPAddrRow do
          AppendRow(  HexLS(dwIndex),
                      IPAddr2Str( dwAddr ),
                      IPAddr2Str( dwMask ),
                      IPAddr2Str( dwBCastAddr ),
                      IntToStr(dwReasmSize));
        inc( pBuf, SizeOf( TMIBIPAddrRow ) );
      end;
    end else
      AppendRow('no entries.','','','','' );
  end else
    AppendRow('Error', SysErrorMessage( ErrorCode ),'','','');

  // we must restore pointer!
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( IPAddrRow ) );
  FreeMem( pBuf );
end;

//-----------------------------------------------------------------------------
{ gets entries in routing table; equivalent to "Route Print" }
procedure DoIPForwardTable(sg : TStringGrid);
var
  IPForwRow     : TMibIPForwardRow;
  TableSize     : DWORD;
  ErrorCode     : DWORD;
  i             : integer;
  pBuf          : PChar;
  NumEntries    : DWORD;
  //***********************************
  procedure AppendRow(const fw_dest_ip,fw_mask,ip_next_hop,if_index,
                   fw_type,next_as_nr,fw_proto,fw_metric : string);
  begin
    sg.Cells[0,sg.RowCount-1] := fw_dest_ip;
    sg.Cells[1,sg.RowCount-1] := fw_mask;
    sg.Cells[2,sg.RowCount-1] := ip_next_hop;
    sg.Cells[3,sg.RowCount-1] := if_index;
    sg.Cells[4,sg.RowCount-1] := fw_type;
    sg.Cells[5,sg.RowCount-1] := next_as_nr;
    sg.Cells[6,sg.RowCount-1] := fw_proto;
    sg.Cells[7,sg.RowCount-1] := fw_metric;
    sg.RowCount := sg.RowCount + 1;
  end;
  //***********************************
begin
  if not Assigned(sg) then
    exit;

  sg.RowCount := 2;

  TableSize := 0;

  // first call: get table length
  NumEntries := 0 ;
  ErrorCode := GetIpForwardTable(Nil, @TableSize, true);
  if Errorcode <> ERROR_INSUFFICIENT_BUFFER then
    exit;

  // get table
  GetMem( pBuf, TableSize );
  ErrorCode := GetIpForwardTable( PTMibIPForwardTable( pBuf ), @TableSize, true);
  if ErrorCode = NO_ERROR then begin
    NumEntries := PTMibIPForwardTable( pBuf )^.dwNumEntries;
    if NumEntries > 0 then begin
      inc( pBuf, SizeOf( DWORD ) );
      for i := 1 to NumEntries do begin
        IPForwRow := PTMibIPForwardRow( pBuf )^;
        with IPForwRow do begin
          if (dwForwardType < 1)
          or (dwForwardType > 4) then
                   dwForwardType := 1 ;   // Angus, allow for bad value
          AppendRow( IPAddr2Str( dwForwardDest ),
                     IPAddr2Str( dwForwardMask ),
                     IPAddr2Str( dwForwardNextHop ),
                     HexLS(dwForwardIFIndex),
                     sIpRouteTypeString[dwForwardType],
                     IntToStr(dwForwardNextHopAS),
                     sIpRouteProtoString[dwForwardProto],
                     IntToStr(dwForwardMetric1) );
        end ;
        inc( pBuf, SizeOf( TMibIPForwardRow ) );
      end;
    end
    else
      AppendRow('no entries.','','','','','','','' );
  end
  else
    AppendRow('Error', SysErrorMessage( ErrorCode ),'','','','','','');
  dec( pBuf, SizeOf( DWORD ) + NumEntries * SizeOf( TMibIPForwardRow ) );
  FreeMem( pBuf );
end;

//------------------------------------------------
procedure DoAdaptersInfo(sg: TStringGrid);
var
  AdpTot: integer;
  AdpRows: TAdaptorRows ;
  Error: DWORD ;
  I: integer ;
  //J: integer ;  jpt - see below
  //S: string ;        id.
  //****************************************
  procedure AppendRow(const adaptIdx,Typ,MAC,DHCP,DefGateway,DHCPsrv,PrimaryWinsSrv:string);
  begin
    with sg do begin
      Cells[0,RowCount-1] := adaptIdx;
      Cells[1,RowCount-1] := Typ;
      Cells[2,RowCount-1] := MAC;
      Cells[3,RowCount-1] := DHCP;
      Cells[4,RowCount-1] := DefGateway;
      Cells[5,RowCount-1] := DHCPsrv;
      Cells[6,RowCount-1] := PrimaryWinsSrv;
      
      RowCount := RowCount + 1;
    end;
  end;
  //****************************************
begin
  if not Assigned(sg) then
    exit;
    
  sg.RowCount := 2;
  
  SetLength (AdpRows, 0) ;
  AdpTot := 0 ;
  Error := IpHlpAdaptersInfo(AdpTot, AdpRows) ;
  if (Error <> 0) then
    AppendRow('Error', SysErrorMessage( GetLastError ),'','','','','' )
  else
    if AdpTot = 0 then
      AppendRow('no entries.','','','','','','' )
    else begin
      for i := 0 to Pred (AdpTot) do begin
        with AdpRows [i] do begin
            AppendRow( HexLS(Index),
                       ifTypeStr[aType],
                       MacAddress,
                       IntToStr(DHCPEnabled),
                       GatewayList [0],
                       DHCPServer [0],
                       PrimWINSServer [0]);
        end ; // with
      end ;  // for
  end ;  // if else
  SetLength (AdpRows, 0) ;
end ;

//---------------------------------------
procedure DoIfTable(sg: TStringGrid);
var
  IfRows        : TIfRows ;
  Error, I      : integer;
  NumEntries    : integer;
  sDescr, sIfName: string;
  //***************************************
  procedure AppendRow(const index,typ,MAC,MTU,speed,adminstatus,operstatus,inp,outp,name,descr:string);
  var
    RowIdx: integer;
  begin
    with sg do begin
      RowIdx := RowCount-1;
      Cells[0,RowIdx] := index;
      Cells[1,RowIdx] := typ;
      Cells[2,RowIdx] := MAC;
      Cells[3,RowIdx] := MTU;
      Cells[4,RowIdx] := speed;
      Cells[5,RowIdx] := AdminStatus;
      Cells[6,RowIdx] := OperStatus;
      Cells[7,RowIdx] := inp;
      Cells[8,RowIdx] := outp;
      Cells[9,RowIdx] := name;
      Cells[10,RowIdx] := descr;
    
      RowCount := RowCount +1;
    end;
  end;
  //***************************************
begin
  if not Assigned(sg) then
    exit;
  sg.RowCount := 2;
  
  SetLength (IfRows, 0) ;
  Error := IpHlpIfTable(NumEntries, IfRows);
  if (Error <> 0) then
    AppendRow('Error', SysErrorMessage(GetLastError),'','','','','','','','','')
  else
    if NumEntries = 0 then
      AppendRow('no entries.','','','','','','','','','','' )
    else begin
      for I := 0 to Pred (NumEntries) do begin
          with IfRows [I] do begin
             if wszName [1] = #0 then
                 sIfName := ''
             else
                 sIfName := WideCharToString (@wszName) ;  // convert Unicode to string
             sIfName := trim (sIfName) ;
             sDescr := bDescr ;
             sDescr := trim (sDescr);
             AppendRow(
               HexLS(dwIndex),
               HexLS(dwType),
               MacAddr2Str( TMacAddress( bPhysAddr ), dwPhysAddrLen ),
               IntToStr(dwMTU),
               IntToStr(dwSpeed),
               IntToStr(dwAdminStatus),
               IntToStr(dwOPerStatus),
               IntToStr(Int64 (dwInOctets)),
               IntToStr(Int64 (dwOutOctets)),  // counters are 32-bit
               sIfName,
               sDescr );  // Angus, added in/out
          end;
      end ;
  end ;
  SetLength (IfRows, 0) ;  // free memory
end ;



initialization

  RecentIPs := TStringList.Create;

finalization

  RecentIPs.Free;

end.

--
_______________________________________________
Lazarus mailing list
Lazarus@lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply via email to