[Back to NETWORK SWAG index] [Back to Main SWAG index] [Original]

    {
    From: greg.miller@shivasys.com

    >Could you tell me where to get the ipx units?

    I'll post the IPX source here again.  (Perhaps this should go into
    the FAQ? :)  There seems to be a big demand for this unit.

    { ipx - IPX communication protocol primitives.          }
    unit ipx;

    interface uses DOS;

    type
         MessageStr          = String;
         IPX_REGS            = Registers;
         Byte4               = array[0..3] of byte;
         NetworkNumber       = Byte4;
         NetworkNode         = array[0..5] of byte;

         ECB                 = record
                                link_address          : Pointer;
                                event_service_routine : Pointer;
                                in_use                : byte;
                                completion_code       : byte;
                                socket_number         : word;
                                ipx_workspace         : Byte4;
                                driver_workspace      : array[0..11] of
    byte;
                                immediate_address     : NetworkNode;
                                fragment_count          : word;
                                fragment                : array [0..1] of
    record
                                                              address :
    pointer;
                                                              length  :
    word;
                                                        end;
                               end;

         IPXHEADER           = record
                                checksum              : word;
                                length                : word;
                                transport_control     : byte;
                                packet_type           : byte;
                                dest_network_number   : NetworkNumber;
                                dest_network_node     : NetworkNode;
                                dest_network_socket   : word;
                                source_network_number : NetworkNumber;
                                source_network_node   : NetworkNode;
                                source_network_socket : word;
                               end;

    { ZeroEcb - store zeros in all ecb fields.
     Pre: e is an ECB.
            Post: e is fully zeroed. }
    procedure ZeroEcb( var e : ECB );

    { ZeroHeader - Store zeros in all header fields.
     Pre: h is an IPXHEADER.
            Post: h is fulled zeroed. }
    procedure ZeroHeader( var h : IPXHEADER );

    { Get1stConnectionNumber - Return first connection number for user name
     Pre: username is valid Novell user name
            Post: Returns first connection number username is logged on or
             0 if not logged on. }
    function Get1stConnectionNumber( username : string ) : word;

    { GetInternetAddress - Get the network:node address for a connection.
     Pre: connection_number is valid for a logged on user.
            Post: network_number is valid number of network.
             physical_node is valid station node.
     }
    function GetInternetAddress(    connection_number : byte;
                                var network_number : NetworkNumber; {hi:lo}
                                var physical_node : NetworkNode ) : integer;

    { IPXSPXNotLoaded - Executed when ipxspx called but not loaded.
     Pre: IPX not loaded.
            Post: Execution aborted. }
    procedure IPXSPXNotLoaded(var NovRegs : Registers);

    { IPXInstalled - Determine if IPX is installed on workstation.
     Pre: Either IPX is or is not installed.
            Post:   If IPX installed initialize global IPXLocation to IPX
    entry
             point and return TRUE.
                    Otherwise initialize global IPXLocation to
    IPXSPXNotLoaded
                    entry point and return FALSE.  }
    function IPXInstalled : Boolean;

    { IPXSPX - Call ipxspx at address in IPXLocation.
     Pre: IPXInstalled has been called.
             IPX is installed and NovRegs assigned IPX or SPX function
             and parameter values. Not checking is done.
            Post:  IPX or SPX function is called.
             NovRegs assigned by call. }
    procedure IPXSPX(var NovRegs:Registers);

    { IPXRelinquishControl - Give ipx momentary control of CPU.
     Pre: IPX loaded.
            Post: IPX execution done. }
    procedure IPXRelinquishControl;

    { IPXCancelEvent - Cancels pending event associated with ECB.
                Pre:  e is valid ECB.
                       Post: 00 - Success.
                         F9 - ECB cannot be canceled.
                             FF - ECB not in use. }
    function IPXCancelEvent( var e : ECB ) : byte;

    { IPXDisconnectFromTarget - Notify listening node that communications
    woth
           specified socket are being terminated.
     Pre: number:node:socket are valid.
            Post: Node notified.   }
    procedure IPXDisconnectFromTarget( network_number : NetWorkNumber;
                                       network_node   : NetWorkNode;
                                       network_socket : word );

    { IPXScheduleEvent - Schedule processing of ECB after timer ticks.
     Pre: ticks is number of 18.2 per second ticks.
                    e is a valid ECB at the time processing occurs.
            Post: e is processed after timer ticks. }
    procedure IPXScheduleEvent( ticks : word; var e : ECB );

    { IPXOpenSocket - Open an application socket.
     Pre: socket to use (BBA-7FFF). All assumed short-lived.
            Post: 00 - Success.
             FE - Socket table full.
                    FF - Socket already open.  }
    function IPXOpenSocket( socket : word ) : byte;

    { IPXCloseSocket - Close socket. No harm if already closed.
     Pre: socket to close.
            Post: socket is closed. }
    procedure IPXCloseSocket( socket : word );

    { IPXListenForPacket - Submit an ECB for use when packet received. Must
                           have ECB available when packet received by IPX.
     Pre: e storage is available when ECB processed by IPX.
             e.socket_number opened.
                    e.event_svc-routine valid routine or NULL.
                    e.fragment_count normally 2.
                    e.fragment[0].address to IPX Header buffer.
                    e.fragment[0].length = 30.
                    e.fragment[1].address to data area <=546 bytes long.
                    e.fragment[1].length = length of data area.
            Post: If socket opened, e is added to pool and return TRUE.
             Otherwise return FALSE.    }
    function IPXListenForPacket( var e : ECB ) : Boolean;

    { IPXSendPacket - Send packet using given ECB.
     Pre: e storage is available when ECB processed by IPX.
             e.socket_number opened.
                    e.event_svc-routine valid routine or NULL.
                    e.immediate_address is address of destination
    workstation.
                    e.fragment_count normally 2.
                    e.fragment[0].address to IPX Header buffer.
                    e.fragment[0].length = 30.
                    e.fragment[1].address to data area <=546 bytes long.
                    e.fragment[1].length = length of data area.
            Post: e.completion_code of: 00 - Message sent.
                FC - Event canceled.
                                            FD - Bad packet.   }

    { IPXGetLocalTarget - Get the bridge address (or node if not bridged)
    for
            network:node address.
      Pre: dest_network - network number of workstation.
             dest_node    - network node of workstation.
                    dest_socket  - network socket of workstation.
            Post: bridge_address is routing information used by
    IPXSendPacket.
             Return 00 - Success.
                           FA - No path to destination. }
    function IPXGetLocalTarget( var dest_network   : NetworkNumber;
                                var dest_node      : NetworkNode;
                                    dest_socket    : word;
                                var bridge_address : NetworkNode ) : byte;

    { IPXGetIntervalMarker - Return time marker measured in 18.2/sec ticks.
     Pre: None.
            Post: Return time marker. }
    function IPXGetIntervalMarker : word;

    { IPXSend -  Send a packet to network:node:socket using send_ecb and
                 send_header. send_ecb/send_header should be defined outside of
                 IPXSend as both may be in use by ipx after IPXSend completes,
                 releasing any local variables.
        Pre: dest_network - network number of destination.
                    dest_node    - network node of destination.
                    dest_socket  - socket of destination.
                    packet_ptr   - pointer to send packet.
      packet_len   - length of send packet
      send_ecb     - ECB to use for sending.
                    send_header  - IPXHEADER to use for sending.
                    send_socket  - socket to use for sending.
            Post:   If destination reachable, packet is sent. }
    procedure IPXSend(  var dest_network   : NetworkNumber;
                        var dest_node      : NetworkNode;
                            dest_socket    : word; { hi:lo }
                            packet_ptr     : Pointer;
                            packet_len     : integer;
                        var send_ecb       : ECB;
                        var send_header    : IPXHEADER;
                         send_socket    : word );

    { IPXReceive - Submit an ECB/header and storage buffer for a received
             message.
        Pre:    receive_ecb    - ECB allocated for recieving.
      receive_header - IPXHEADER allocated for receiving.
                    receive_socket - socket to receive on.
     Post: message        - area allocated for received message
                holds data.
                    message_size   - size of message area in bytes.
      }
    procedure IPXReceive(  var receive_ecb    : ECB;
                           var receive_header : IPXHEADER;
                               receive_socket : word;
                               message        : Pointer;
                               message_size   : word );
    { IPXReceivedFrame - Returns TRUE if message frame received in ECB.
        Pre:    receive_ecb    - ECB allocated for recieving.
     Post: Returns TRUE if message frame received in ECB.
    }
    function IPXReceivedFrame( receive_ecb : ECB ) : Boolean;

    {_________________________________________________________________________}

    implementation
       type
         REQUESTBUFFER       = record
                                dest_network_number   : NetWorkNumber;
                                dest_network_node     : NetworkNode;
                                dest_network_socket   : word;
                               end;
         REPLYBUFFER         = record
                                node_address          : NetworkNode;
                               end;
       var IPXLocation : Pointer;              { Address of ipx }

    { abort - Display message and halt.
       Pre:  message is a string. }
    procedure abort( message : string );
    begin
         writeln( message );
         Halt(1);
    end;

    {$F+}
    { Get1stConnectionNumber - Return first connection number for user name
     Pre: username is valid Novell user name
            Post: Returns first connection number username is logged on or
             0 if not logged on. }
    function Get1stConnectionNumber( username : string ) : word;
    var
      NovRegs          : Registers;
      Request          : record
                           len            : Word;
                           buffer_type    : Byte;
                           object_type    : Word;
                           name           : string[47];
                         end;
      Reply            : record
                           len                : Word;
                           number_connections : byte;
                           connection_num     : array[0..99] of byte;
                         end;
    begin
      with Request do begin
        len  := 51;
        buffer_type := $15;
        object_type := $0100;
        name := username;
      end;

      Reply.len := 101;     { Maximum number of user connections }

      with NovRegs do begin
        AH := $E3;
        DS := Seg(Request);  {DS:SI points to request}
        SI := Ofs(Request);
        ES := Seg(Reply);    {ES:DI points to reply}
        DI := Ofs(Reply);
        MsDos(NovRegs);

        if (Al <> 0) or (Reply.number_connections = 0)
           then Get1stConnectionNumber := 0
           else Get1stConnectionNumber := Reply.connection_num[0];
      end;
    end;

    { GetInternetAddress - Get the network:node address for a connection.
     Pre: connection_number is valid for a logged on user.
            Post: network_number is valid number of network.
             physical_node is valid station node.
     }
    function GetInternetAddress(    connection_number : byte;
                                var network_number : NetworkNumber; {hi:lo}
                                var physical_node : NetworkNode ) : integer;
    var
      NovRegs          : Registers;
      Request          : record
                           len               : word;
                           buffer_type       : byte;
                           connection_number : byte;
                         end;
      Reply            : record
                           len            : word;
                           network_number : NetworkNumber;
                           physical_node  : NetworkNode;
                           server_socket  : word;
                         end;
    begin
      with Request do begin
        len  := 2;
        buffer_type := $13;
      end;
      Request.connection_number := connection_number;
      Reply.len := 12;
      with NovRegs do begin
        AH := $E3;
        DS := Seg(Request);  {DS:SI points to request}
        SI := Ofs(Request);
        ES := Seg(Reply);    {ES:DI points to reply}
        DI := Ofs(Reply);
        MsDos(NovRegs);
        Ah := 0;
        GetInternetAddress := Ax;
      end;
      network_number := Reply.network_number;
      physical_node := Reply.physical_node;
    end;

    { IPXSPXNotLoaded - Executed when ipxspx called but not loaded.
     Pre: IPX not loaded.
            Post: Execution aborted. }
    procedure IPXSPXNotLoaded(var NovRegs : Registers);
    begin
         abort('IPX not loaded');
    end;

     { ZeroEcb - store zeros in all ecb fields.
     Pre: e is an ECB.
            Post: e is fully zeroed. }
    procedure ZeroEcb( var e : ECB );
    var i : byte;
    begin
         with e do begin
              link_address := Ptr(0,0);
              event_service_routine := Ptr(0,0);
              in_use := 0;
              completion_code := 0;
              socket_number   := 0;
              for i := 0 to 3 do
                  ipx_workspace[i] := 0;
              for i := 0 to 11 do
                  driver_workspace[i] := 0;
              for i := 0 to 5 do
                  immediate_address[i] := 0;
              fragment_count := 0;
              for i := 0 to 1 do begin
                  fragment[i].address := Ptr(0,0);
                  fragment[i].length  := 0;
              end;
         end;
    end;

    { ZeroHeader - Store zeros in all header fields.
     Pre: h is an IPXHEADER.
            Post: h is fulled zeroed. }
    procedure ZeroHeader( var h : IPXHEADER );
    var i : byte;
    begin
       with h do begin
         checksum              := 0;
         length                := 0;
         transport_control     := 0;
         packet_type           := 0;
         for i := 0 to 3 do
             dest_network_number[i] := 0;
         for i := 0 to 5 do
             dest_network_node[i] := 0;
         dest_network_socket   := 0;
         for i := 0 to 3 do
             source_network_number[i] := 0;
         for i := 0 to 5 do
             source_network_node[i] := 0;
         source_network_socket := 0;
      end;
    end;

     { IPXInstalled - Determine if IPX is installed on workstation.
     Pre: Either IPX is or is not installed.
            Post:   If IPX installed initialize global IPXLocation to IPX
    entry
             point and return TRUE.
                    Otherwise initialize global IPXLocation to
    IPXSPXNotLoaded
                    entry point and return FALSE.  }
    function IPXInstalled : Boolean;
    var NovRegs          : IPX_REGS;
    begin
      with NovRegs do begin
        AX := $7A00;             {func 7Ah of int 2Fh is used to detect IPX}
        Intr($2F,NovRegs);
        if AL = $FF then begin   {if AL is FFh then IPX is loaded and
    available}
          IPXInstalled := TRUE;
          IPXLocation := Ptr(ES,DI); {pointer to IPX entry point in ES:DI}
        end
        else begin
          IPXInstalled := FALSE; {no IPX installed}
          IPXLocation := @IPXSPXNotLoaded;
        end;
      end;
    end;

    { IPXSPX - Call ipxspx at address in IPXLocation.
     Pre: IPXInstalled has been called.
             IPX is installed and NovRegs assigned IPX or SPX
    function
             and parameter values. Not checking is done.
            Post:  IPX or SPX function is called.
             NovRegs assigned by call. }
    procedure IPXSPX(var NovRegs:Registers);
    var   Ax_, Bx_, Dx_, Di_, Si_, Es_ : word;
    begin
         with NovRegs do begin  { Assign simple variables record field
    values }
              Ax_ := Ax;
              Bx_ := Bx;
              Dx_ := Dx;
              Di_ := Di;
              Si_ := Si;
              Es_ := Es;
         end;

         asm                            { Assembler instructions. }
            mov   Ax, Ax_               { Initialize CPU registers.}
            mov   Bx, Bx_
            mov   Dx, Dx_
            mov   Di, Di_
            mov   Si, Si_
            mov   Es, Es_

            push  Bp
            call  dword ptr IPXLocation { Call IPX via address at
    IPXLocation. }
            pop   Bp
            mov   Ax_, Ax
            mov   Dx_, Dx
         end;

         NovRegs.Ax := Ax_;             { Return register values to caller }
         NovRegs.Dx := Dx_;
    end;

    { IPXRelinquishControl - Give ipx momentary control of CPU.
     Pre: IPX loaded.
            Post: IPX execution done. }
    procedure IPXRelinquishControl;
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              Bx := $0a;
              IPXSPX(NovRegs);
         end
    end;

    { IPXCancelEvent - Cancels pending event associated with ECB.
                Pre:  e is valid ECB.
                       Post: 00 - Success.
                         F9 - ECB cannot be canceled.
                             FF - ECB not in use. }
    function IPXCancelEvent( var e : ECB ) : byte;
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              Bx := $06;
              ES := Seg(e);    {ES:SI points to ecb}
              SI := Ofs(e);
              IPXSPX(NovRegs);
              IPXCancelEvent := AL;
         end
    end;

    { IPXDisconnectFromTarget - Notify listening node that communications
    woth
           specified socket are being terminated.
     Pre: number:node:socket are valid.
            Post: Node notified.   }
    procedure IPXDisconnectFromTarget( network_number : NetWorkNumber;
                                       network_node   : NetWorkNode;
                                       network_socket : word );
    var NovRegs : IPX_REGS;
        request_buffer : REQUESTBUFFER;
    begin
         with request_buffer do begin
              dest_network_number := network_number;
              dest_network_node   := network_node;
       dest_network_socket := network_socket;
         end;

         with NovRegs do begin
              Bx := $0B;
              ES := Seg(request_buffer);    {ES:SI points to ecb}
              SI := Ofs(request_buffer);
              IPXSPX(NovRegs);
         end
    end;

    { IPXScheduleEvent - Schedule processing of ECB after timer ticks.
     Pre: ticks is number of 18.2 per second ticks.
                    e is a valid ECB at the time processing occurs.
            Post: e is processed after timer ticks. }
    procedure IPXScheduleEvent( ticks : word; var e : ECB );
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              Bx := $05;
              Ax := ticks;
              ES := Seg(e);
              SI := Ofs(e);
              IPXSPX(NovRegs);
         end;
    end;

    { IPXOpenSocket - Open an application socket.
     Pre: socket to use (BBA-7FFF). All assumed short-lived.
            Post: 00 - Success.
             FE - Socket table full.
                    FF - Socket already open.  }
    function IPXOpenSocket( socket : word ) : byte;
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              Dx := socket;
              Bx := 0;
              Al := 0;
              IPXSPX(NovRegs);
              Ah := 0;
              IPXOpenSocket := Ax;
         end
    end;

    { IPXCloseSocket - Close socket. No harm if already closed.
     Pre: socket to close.
            Post: socket is closed. }
    procedure IPXCloseSocket( socket : word );
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              Dx := socket;
              Bx := $0001;
              IPXSPX(NovRegs);
         end
    end;

     { IPXListenForPacket - Submit an ECB for use when packet received. Must
                           have ECB available when packet received by IPX.
     Pre: e storage is available when ECB processed by IPX.
              e.socket_number opened.
                    e.event_svc-routine valid routine or NULL.
                    e.fragment_count normally 2.
                    e.fragment[0].address to IPX Header buffer.
                    e.fragment[0].length = 30.
                    e.fragment[1].address to data area <=546 bytes long.
                    e.fragment[1].length = length of data area.
            Post: If socket opened, e is added to pool and return TRUE.
             Otherwise return FALSE.    }
    function IPXListenForPacket( var e : ECB ) : Boolean;
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              BX := $0004;
              ES := Seg(e);    {ES:SI points to ecb}
              SI := Ofs(e);
              IPXSPX(NovRegs);
              IPXListenForPacket := Al = 00;
         end
    end;

    { IPXSendPacket - Send packet using given ECB.
     Pre: e storage is available when ECB processed by IPX.
             e.socket_number opened.
                    e.event_svc-routine valid routine or NULL.
                    e.immediate_address is address of destination
    workstation.
                    e.fragment_count normally 2.
                    e.fragment[0].address to IPX Header buffer.
                    e.fragment[0].length = 30.
                    e.fragment[1].address to data area <=546 bytes long.
                    e.fragment[1].length = length of data area.
            Post: e.completion_code of: 00 - Message sent.
                FC - Event canceled.
                                            FD - Bad packet.   }
    procedure IPXSendPacket( var e: ECB );
    var NovRegs : IPX_REGS;
    begin
         with NovRegs do begin
              ES := Seg(e);    {ES:SI points to ecb}
              SI := Ofs(e);
              BX := $0003;
              IPXSPX(NovRegs);
         end
    end;

     { IPXGetLocalTarget - Get the bridge address (or node if not bridged)
    for
            network:node address.
      Pre: dest_network - network number of workstation.
             dest_node    - network node of workstation.
                    dest_socket  - network socket of workstation.
            Post: bridge_address is routing information used by
    IPXSendPacket.
             Return 00 - Success.
                           FA - No path to destination. }
    function IPXGetLocalTarget( var dest_network   : NetworkNumber;
                                var dest_node      : NetworkNode;
                                    dest_socket    : word;
                                var bridge_address : NetworkNode ) : byte;
    var
      NovRegs          : Registers;
      Request          : record
                           network_number    : NetworkNumber;
                           physical_node     : NetworkNode;
                           socket            : word;
                         end;
      Reply            : record
                           local_target      : NetworkNode;
                         end;
    begin
         with Request do begin
              network_number := dest_network;
              physical_node := dest_node;
              socket := dest_socket;
         end;
         with NovRegs do begin
              Es := Seg(Request);
              Si := Ofs(Request);
              Di := Ofs(Reply);
              Bx := $0002;
              IPXSPX(NovRegs);
              Ah := 0;
              IPXGetLocalTarget := Ax;
              bridge_address := Reply.local_target;
         end
    end;

    { IPXGetIntervalMarker - Return time marker measured in 18.2/sec ticks.
     Pre: None.
            Post: Return time marker. }
    function IPXGetIntervalMarker : word;
    var
      NovRegs          : Registers;
    begin

         with NovRegs do begin
              Bx := $0008;
              IPXSPX(NovRegs);
              IPXGetIntervalMarker := Ax;
         end
    end;

     { IPXSend - Send a packet to network:node:socket using send_ecb and
                 send_header. send_ecb/send_header should be defined outside
    of
                 IPXSend as both may be in use by ipx after IPXSend
    completes,
                 releasing any local variables.
        Pre: dest_network - network number of destination.
                    dest_node    - network node of destination.
                    dest_socket  - socket of destination.
                    packet_ptr   - pointer to send packet.
      packet_len   - length of send packet
      send_ecb     - ECB to use for sending.
                    send_header  - IPXHEADER to use for sending.
                    send_socket  - socket to use for sending.
            Post:   If destination reachable, packet is sent. }
    procedure IPXSend(  var dest_network   : NetworkNumber;
                        var dest_node      : NetworkNode;
                            dest_socket    : word; { hi:lo }
                            packet_ptr     : Pointer;
                            packet_len     : integer;
                        var send_ecb       : ECB;
                        var send_header    : IPXHEADER;
                         send_socket    : word );
    begin
         ZeroEcb(send_ecb);
         ZeroHeader(send_header);
         send_ecb.socket_number := send_socket;  { Socket used for sending }
         if IPXGetLocalTarget( dest_network,
               dest_node,
                               dest_socket,
                               send_ecb.immediate_address ) = 0
            then begin
                 with send_ecb do begin
                      fragment_count := 2;
                      fragment[0].address := @send_header;
                      fragment[0].length  := sizeof(IPXHEADER);
                      fragment[1].address := packet_ptr;
                      fragment[1].length  := packet_len;
                 end;
                 with send_header do begin
                      packet_type         := 4;
                      dest_network_number := dest_network;
                      dest_network_node   := dest_node;
                      dest_network_socket := dest_socket;
                 end;
                 IPXSendPacket( send_ecb );
            end;
    end;

     { IPXReceive - Submit an ECB/header and storage buffer for a received
             message.
        Pre:    receive_ecb    - ECB allocated for recieving.
      receive_header - IPXHEADER allocated for receiving.
                    receive_socket - socket to receive on.
     Post: message        - area allocated for received message
                holds data.
                    message_size   - size of message area in bytes.
      }
    procedure IPXReceive(  var receive_ecb    : ECB;
                           var receive_header : IPXHEADER;
                               receive_socket : word;
                               message        : Pointer;
                               message_size   : word );
    begin
       ZeroEcb(receive_ecb);
       ZeroHeader(receive_header);
       with receive_ecb do begin
            socket_number := receive_socket; { Socket used for receiving }
            fragment_count := 2;
            fragment[0].address := @receive_header;
            fragment[0].length  := sizeof(IPXHEADER);
            fragment[1].address := message;
            fragment[1].length  := message_size;
       end;
        if not IPXListenForPacket( receive_ecb ) then
         abort('IPX Error - Failure initializing.');
       IPXRelinquishControl;              { Give ipx opportunity to process
    }
    end;

    { IPXReceivedFrame - Returns TRUE if message frame received in ECB.
        Pre:    receive_ecb    - ECB allocated for recieving.
     Post: Returns TRUE if message frame received in ECB.
    }
    function IPXReceivedFrame( receive_ecb : ECB ) : Boolean;
    begin
     IPXReceivedFrame := (receive_ecb.completion_code = 0) and
                                (receive_ecb.in_use = 0);

    end;

    begin
    end.

[Back to NETWORK SWAG index] [Back to Main SWAG index] [Original]