UNIT IPX; (****************************************************************************) (* *) (* PROJEKT : PASCAL Treiber fuer Novell-NetWare *) (* MODULE : IPX.PAS *) (* VERSION : 1.10C *) (* COMPILER : Turbo Pascal V 6.0 *) (* DATUM : 13.06.91 *) (* AUTOR : R. Gilomen *) (* GEPRUEFT : R. Gilomen *) (* *) (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Bibliothek mit den IPX-Grunfunktionen. Dieses Modul *) (* wurde mit IPX Version 2.12 getestet. *) (* *) (*--------------------------------------------------------------------------*) (* *) (* MODIFIKATIONEN : *) (* *) (* Version 1.00A 20.02.91 R. Gilomen Initial Version *) (* Version 1.10A 28.02.91 R. Gilomen Neue Funktionen *) (* IPX_To_Addr *) (* IPX_From_Addr *) (* IPX_Internetwork_Address *) (* Version 1.10B 07.03.91 R. Gilomen Fehler in Funktion IPX_Done *) (* behoben. Bei SEND wurde *) (* Source.Socket veraendert. *) (* Version 1.10C 13.06.91 R. Gilomen Defaultwert fuer Parameter *) (* STAY_OPEN auf $FF gesetzt. *) (* *) (****************************************************************************) (*//////////////////////////////////////////////////////////////////////////*) INTERFACE (*//////////////////////////////////////////////////////////////////////////*) (*==========================================================================*) (* DEKLARATIONEN / DEFINITIONEN *) (*==========================================================================*) CONST (* Allgemeine Deklarationen *) MAX_SOCKETS = 20; (* Maximale Anzahl konfigurierte *) (* Kommunikationssockel. *) MAX_DATA_SIZE = 546; (* Maximale Datenlaenge *) NET_LENGTH = 4; (* Laenge Netzwerkadresse *) NODE_LENGTH = 6; (* Laenge Knotenadresse *) (* Code Deklarationen *) SEND = $10; RECEIVE = $20; (* Deklaration der Rueckgabewerte *) SUCCESS = $00; NOT_ENDED = $10; PARAMETER_ERROR = $20; NO_DESTINATION = $21; DEVICE_SW_ERROR = $30; SOCKET_TABLE_FULL = $31; PACKET_BAD = $32; PACKET_UNDELIVERIABLE = $33; PACKET_OVERFLOW = $34; DEVICE_HW_ERROR = $40; TYPE S4Byte = ARRAY [1..4] OF BYTE; (* Datentyp fuer Network *) S6Byte = ARRAY [1..6] OF BYTE; (* Datentyp fuer Node *) (* Datentyp fuer Daten *) Data_Packet = ARRAY [1..MAX_DATA_SIZE] OF CHAR; SData = RECORD (* Daten und Laenge *) Data : Data_Packet; Length : WORD; END; Network_Address = RECORD (* Datentyp fuer NW-Adr. *) Network : S4Byte; Node : S6Byte; Socket : WORD; END; (*==========================================================================*) (* PROZEDUREN / FUNKTIONEN *) (*==========================================================================*) FUNCTION IPX_Setup : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine initialisiert die IPX-Software und deren *) (* Funktion. *) (* *) (* *) (* PARAMETER : IN : - *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Open_Socket ( VAR Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine eroeffnet einen Kommunikationssockel. *) (* *) (* *) (* PARAMETER : IN : Socket = Nummer des Sockels, der eroeffnet *) (* werden soll. *) (* *) (* OUT: Socket = Nummer des Sockels, der effektiv *) (* geoeffnet wurde. *) (* *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Close_Socket ( Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine schliesst einen Kommunikationssockel. *) (* *) (* *) (* PARAMETER : IN : Socket = Nummer des Sockels, der geschlos- *) (* sen werden soll. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Send ( Socket : WORD; Dest_Addr : Network_Address; Buffer : SData ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine dient zum senden von Daten an eine oder *) (* mehrere Gegenstationen. *) (* *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der gesendet *) (* werden soll. *) (* Dest_Addr = Vollstaendige Netwerkadresse der *) (* Gegenstation(en). *) (* Buffer = Daten die gesendet werden und *) (* dessen Laenge. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Receive ( Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine dient zum Empfangen von Daten einer Gegen- *) (* station. Die Daten koennen, wenn das Kommando beendet *) (* ist, mit der Funktion IPX_Done vom Netzwerk abgeholt *) (* werden. *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der empfangen *) (* werden soll. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Done ( Socket : WORD; Code : BYTE; VAR Source_Addr : Network_Address; VAR Buffer : SData ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Funktion liefert den Status einer vorher abgesetz- *) (* ten Routine. Zurueckgegeben wird, ob die Routine schon *) (* beendet ist oder nicht sowie eventuelle Daten. *) (* *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der die Funktion *) (* ausgefuehrt werden soll. *) (* Code = Routine, deren Status ueberprueft *) (* werden soll. *) (* *) (* OUT: Source_Addr = Vollstaendige Netzwerkadresse der *) (* Gegenstation, von der Daten einge- *) (* troffen sind. *) (* Buffer = Buffer, in dem eventuelle Daten *) (* abgelegt werden koennen. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_Internetwork_Address ( VAR Network : S4Byte; VAR Node : S6Byte ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Funktion liefert die Internetzwerkadresse der *) (* jeweiligen Station. *) (* *) (* *) (* PARAMETER : OUT: Network = Netzwerkadresse *) (* Node = Knotenadresse *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_To_Addr ( Network : String; Node : String; Socket : String; VAR Addr : Network_Address ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine konvertiert die Eingabestrings in die Daten- *) (* struktur Network_Address. *) (* *) (* *) (* PARAMETER : IN : Network = Netzwerkadresse die konvertiert *) (* werden soll. *) (* Node = Knotenadresse die konvertiert *) (* werden soll. *) (* Socket = Sockelnummer die konvertiert *) (* werden soll. *) (* *) (* OUT: Addr = Konvertierte vollsaendige Netz- *) (* werkadresse. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) FUNCTION IPX_From_Addr ( Addr : Network_Address; VAR Network : String; VAR Node : String; VAR Socket : String ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine konvertiert die vollstaendige Netzwerk- *) (* adresse in String's. *) (* *) (* *) (* PARAMETER : IN : Addr = Vollstaendige Netzwerkadresse *) (* *) (* OUT: Network = Netzwerkadresse die konvertiert *) (* wurde. *) (* Node = Knotenadresse die konvertiert *) (* wurde. *) (* Socket = Sockelnummer die konvertiert *) (* wurde. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) (*//////////////////////////////////////////////////////////////////////////*) IMPLEMENTATION (*//////////////////////////////////////////////////////////////////////////*) (*==========================================================================*) (* UNITS IMPORT *) (*==========================================================================*) USES Dos; (*==========================================================================*) (* DEKLARATIONEN / DEFINITIONEN *) (*==========================================================================*) CONST (* Allgemeine Definitionen *) HEADER = 30; (* Groesse IPX-Header *) PACKET_SIZE = 576; (* IPX-Paket groesse *) (* Definitionen der IPX-Funktionen *) IPX_TST = $7A00; (* Vorbereiten fuer IPX Test *) MUX_INTR = $2F; (* Multiplex Interrupt *) OPEN_SOCKET = $0000; (* Oeffnet einen Sockel *) CLOSE_SOCKET = $0001; (* Schliesst einen Sockel *) GET_TARGET = $0002; (* Pruefe Gegenstation *) DO_SEND = $0003; (* Sendet ein Paket *) DO_RECEIVE = $0004; (* Empfaengt Pakete *) GET_ADDR = $0009; (* Bestimmt Internetzwerkadresse *) (* Definitionen der IPX-Parameter *) STAY_OPEN = $FF; (* $00 : Sockel bleibt geoeffnet, *) (* bis er explizit geschlossen wird *) (* oder das Programm terminiert. *) (* $FF : Sockel bleibt geoeffnet, *) (* bis er explizit geschlossen wird. *) (* Wird benoetigt fuer TSR-Programme.*) (* Definitionen der IPX-Rueckgabewerte *) IPX_LOADED = $FF; (* IPX ist geladen *) OPENED = $00; (* Sockel erfolgreich geoeffnet *) ALREADY_OPEN = $FF; (* Sockel ist bereits goeffnet *) TABLE_FULL = $FE; (* Sockel Tabelle ist voll *) EXIST = $00; (* Weg zu Gegenstation existiert *) NO_SOCKET = $FF; (* Sockel existiert nicht *) SEND_OK = $00; (* Senden war erfolgreich *) SOCKET_ERROR = $FC; (* Sockel existiert nicht mehr *) SIZE_ERROR = $FD; (* Paketgroesse nicht korrekt *) UNDELIV = $FE; (* Paket nicht ausgeliefert *) OVERFLOW = $FD; (* Buffer zu klein *) HW_ERROR = $FF; (* Hardware defekt *) REC_OK = $00; (* Paket erfolgreich empfangen *) (* Definition der ECB-Parameter *) FINISHED = $00; (* Routine beendet *) FRAG_COUNT = 1; (* Anzahl Fragmente *) UNKNOWN = 0; (* Unbekannter Paket Typ *) (* Deklarationen *) TYPE S12Byte = ARRAY [1..12] OF BYTE; (* Interner Datentyp *) IPX_Packet = RECORD (* IPX-Paket Struktur *) CheckSum : WORD; Length : WORD; TransportControl : BYTE; PacketType : BYTE; Destination : Network_Address; Source : Network_Address; IPX_Data : Data_Packet; END; ECB_Fragment = RECORD (* Fragment der ECB Struktur *) Address : ^IPX_Packet; Size : WORD; END; ECB = RECORD (* ECB Datenstruktur *) Link_Adress : S4Byte; ESR_Address : ^BYTE; InUseFlag : BYTE; CompletionCode : BYTE; SocketNumber : WORD; IPX_Workspace : S4Byte; DriverWorkspace : S12Byte; ImmediateAddress : S6Byte; FragmentCount : WORD; FragDescr : ECB_Fragment; END; Int_Addr = RECORD (* Datenstruktur Internetzwerkadr. *) Network : S4Byte; Node : S6Byte; END; VAR IPX_Location : ARRAY [1..2] OF WORD; (* Adresse von IPX *) (* Array in dem die ECB's *) (* verwaltet werden. *) ECB_Table : ARRAY [1..MAX_SOCKETS] OF ^ECB; (*==========================================================================*) (* PROZEDUREN / FUNKTIONEN *) (*==========================================================================*) PROCEDURE IPX_Call ( VAR Regs : Registers ); (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Diese Prozedur setzt die in Regs spezifizierten *) (* Register des Prozessors. Anschliessend wird ein IPX- *) (* Call ausgefuehrt und die Register wieder ausgelesen. *) (* Es werden nicht alle Register der Datenstruktur *) (* Regs uebernommen! *) (* *) (* PARAMETER : IN : Regs = Register, die gesetzt werden *) (* sollen. *) (* *) (* OUT: Regs = Register, die vom IPX gesetzt *) (* wurden (Return values). *) (* *) (*--------------------------------------------------------------------------*) VAR Temp_AX, Temp_BX, Temp_CX, Temp_DX, Temp_ES, Temp_SI, Temp_DI : WORD; BEGIN Temp_AX := Regs.AX; Temp_BX := Regs.BX; Temp_CX := Regs.CX; Temp_DX := Regs.DX; Temp_SI := Regs.SI; Temp_ES := Regs.ES; Temp_DI := Regs.DI; ASM PUSH BP (* Register sichern *) PUSH SP PUSH SS PUSH DS PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH ES PUSH DI MOV AX, Temp_AX (* Register setzen *) MOV BX, Temp_BX MOV CX, Temp_CX MOV DX, Temp_DX MOV SI, Temp_SI MOV ES, Temp_ES MOV DI, Temp_DI CALL DWORD PTR IPX_Location (* IPX aufrufen *) MOV Temp_AX, AX (* Register auslesen *) MOV Temp_BX, BX MOV Temp_CX, CX MOV Temp_DX, DX MOV Temp_SI, SI MOV Temp_ES, ES MOV Temp_DI, DI POP DI POP ES (* Gesicherte Register wieder *) POP SI (* zuruecksetzen. *) POP DX POP CX POP BX POP AX POP DS POP SS POP SP POP BP END; Regs.AX := Temp_AX; Regs.BX := Temp_BX; Regs.CX := Temp_CX; Regs.DX := Temp_DX; Regs.SI := Temp_SI; Regs.ES := Temp_ES; Regs.DI := Temp_DI; END; FUNCTION IPX_Setup : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine initialisiert die IPX-Software und deren *) (* Funktion. *) (* *) (* *) (* PARAMETER : IN : - *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i : INTEGER; (* Laufvariable *) Temp_Reg : Registers; (* Temporaere Register fuer Int. *) BEGIN Temp_Reg.AX := IPX_TST; (* Test ob IPX geladen. *) Intr (MUX_INTR,Temp_Reg); IF (Temp_Reg.AL <> IPX_LOADED) THEN BEGIN IPX_Setup := DEVICE_SW_ERROR; (* IPX nicht geladen *) EXIT; END; Temp_Reg.AX := Temp_Reg.ES; IPX_Location[1] := Temp_Reg.DI; (* Adresse von IPX sichern *) IPX_Location[2] := Temp_Reg.AX; FOR i := 1 TO MAX_SOCKETS DO (* Array fuer ECB init. *) ECB_Table[i] := NIL; IPX_Setup := SUCCESS; (* Initialisierung erfolgreich *) END; FUNCTION IPX_Open_Socket ( VAR Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine eroeffnet einen Kommunikationssockel. *) (* *) (* *) (* PARAMETER : IN : Socket = Nummer des Sockels, der eroeffnet *) (* werden soll. *) (* *) (* OUT: Socket = Nummer des Sockels, der effektiv *) (* geoeffnet wurde. *) (* *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i : INTEGER; (* Laufvariable *) Index : INTEGER; (* Index auf ECB_Table *) Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) BEGIN Socket := Swap(Socket); (* In Motorola Format konvertieren *) FOR i := 1 TO MAX_SOCKETS DO (* Pruefen, ob Sockel existiert *) IF ECB_Table[i] <> NIL THEN IF Socket = ECB_Table[i]^.SocketNumber THEN BEGIN IPX_Open_Socket := PARAMETER_ERROR; EXIT; END; Index := 1; WHILE (ECB_Table[Index] <> NIL) DO (* Pruefen, ob alle Sockel belegt *) BEGIN (* falls es noch freie ECB hat, *) IF Index >= MAX_SOCKETS THEN (* steht Index auf einem solchen. *) BEGIN IPX_Open_Socket := SOCKET_TABLE_FULL; EXIT; END; Index := Index + 1; END; Temp_Reg.BX := OPEN_SOCKET; (* Register fuer Call vorbereiten *) Temp_Reg.AL := STAY_OPEN; Temp_Reg.DX := Socket; IPX_Call (Temp_Reg); Socket := Temp_Reg.DX; (* Register auslesen *) IF Temp_Reg.AL <> OPENED THEN (* IPX nicht i.O. *) BEGIN IPX_Open_Socket := DEVICE_SW_ERROR; EXIT; END; NEW (ECB_Table[Index]); (* Vollstaendiger ECB erzeugen *) NEW (ECB_Table[Index]^.FragDescr.Address); ECB_Table[Index]^.SocketNumber := Socket; Socket := Swap(Socket); (* Zurueck in INTEL Format konv. *) IPX_Open_Socket := SUCCESS; END; FUNCTION IPX_Close_Socket ( Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine schliesset einen Kommunikationssockel. *) (* *) (* *) (* PARAMETER : IN : Socket = Nummer des Sockels, der geschlos- *) (* sen werden soll. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR Index : INTEGER; (* Index auf ECB_Table *) Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) BEGIN Socket := Swap(Socket); (* In Motorola Format konvertieren *) Index := 1; (* Sockel suchen *) WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DO BEGIN IF Index >= MAX_SOCKETS THEN BEGIN IPX_Close_Socket := PARAMETER_ERROR; (* Sockel existiert nicht *) EXIT; END; Index := Index + 1; END; Temp_Reg.BX := CLOSE_SOCKET; (* Register fuer Call vorbereiten *) Temp_Reg.DX := Socket; IPX_Call (Temp_Reg); (* Allozierter Speicher freigeben *) DISPOSE (ECB_Table[Index]^.FragDescr.Address); ECB_Table[Index]^.FragDescr.Address := NIL; DISPOSE (ECB_Table[Index]); ECB_Table[Index] := NIL; IPX_Close_Socket := SUCCESS; END; FUNCTION IPX_Send ( Socket : WORD; Dest_Addr : Network_Address; Buffer : SData ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine dient zum senden von Daten an eine oder *) (* mehrere Gegenstation(en). *) (* *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der gesendet *) (* werden soll. *) (* Dest_Addr = Vollstaendige Netwerkadresse der *) (* Gegenstation(en). *) (* Buffer = Daten die gesendet werden und *) (* dessen Laenge. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i : INTEGER; (* Laufvariable *) Index : INTEGER; (* Index auf ECB_Table *) Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) Temp_Imm_Addr : S6Byte; (* Temporaere ImmdediateAddress *) Temp_Addr : S12Byte; (* Temporaere Internetworkadresse *) BEGIN Socket := Swap(Socket); (* In Motorola Format konvertieren *) Dest_Addr.Socket := Swap(Dest_Addr.Socket); Index := 1; (* Sockel suchen *) WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DO BEGIN IF Index >= MAX_SOCKETS THEN BEGIN IPX_Send := PARAMETER_ERROR; (* Sockel existiert nicht *) EXIT; END; Index := Index + 1; END; IF Buffer.Length > MAX_DATA_SIZE THEN (* Laenge der Daten pruefen *) BEGIN IPX_Send := PARAMETER_ERROR; EXIT; END; WITH Dest_Addr DO (* Pruefe ob Gegenstation erreichbar *) BEGIN FOR i := 1 TO NET_LENGTH DO (* Internetzwerkadresse zusammenst. *) Temp_Addr[i] := Network[i]; FOR i := 1 TO NODE_LENGTH DO Temp_Addr[i + NET_LENGTH] := Node[i]; Temp_Addr[11] := Lo(Socket); (* Low-Byte *) Temp_Addr[12] := HI(Socket); (* High-Byte *) END; Temp_Reg.ES := Seg(Temp_Addr); (* Register fuer Call vorbereiten *) Temp_Reg.SI := Ofs(Temp_Addr); Temp_Reg.DI := Ofs(Temp_Imm_Addr); Temp_Reg.BX := GET_TARGET; IPX_Call (Temp_Reg); ECB_Table[Index]^.ImmediateAddress := Temp_Imm_Addr; IF Temp_Reg.AL <> EXIST THEN BEGIN IPX_Send := NO_DESTINATION; (* Weg nicht verfuegbar *) EXIT; END; WITH ECB_Table[Index]^ DO (* ECB mit Parametern fuellen *) BEGIN ESR_Address := NIL; SocketNumber := Socket; InUseFlag := FINISHED; FragmentCount := FRAG_COUNT; WITH FragDescr.Address^ DO (* IPX-Header vorbereiten *) BEGIN PacketType := UNKNOWN; WITH Destination DO BEGIN Network := Dest_Addr.Network; Node := Dest_Addr.Node; Socket := Dest_Addr.Socket; END; IPX_Data := Buffer.Data; END; FragDescr.Size := Buffer.Length + 30; END; Temp_Reg.ES := Seg(ECB_Table[Index]^); (* Register fuer Call vorbereiten *) Temp_Reg.SI := Ofs(ECB_Table[Index]^); Temp_Reg.BX := DO_SEND; IPX_Call (Temp_Reg); IPX_Send := SUCCESS; END; FUNCTION IPX_Receive ( Socket : WORD ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine dient zum Empfangen von Daten einer Gegen- *) (* station. Die Daten koennen, wenn das Kommando beendet *) (* ist, mit der Funktion IPX_Done vom Netzwerk abgeholt *) (* werden. *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der empfangen *) (* werden soll. *) (* *) (* OUT: Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR Index : INTEGER; (* Index auf ECB *) i : INTEGER; (* Laufvariable *) Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) BEGIN Socket := Swap(Socket); (* In Motorola Format konvertieren *) Index := 1; (* Sockel suchen *) WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DO BEGIN IF Index >= MAX_SOCKETS THEN BEGIN IPX_Receive := PARAMETER_ERROR; (* Sockel existiert nicht *) EXIT; END; Index := Index + 1; END; WITH ECB_Table[Index]^ DO (* ECB mit Parametern fuellen *) BEGIN ESR_Address := NIL; FragmentCount := FRAG_COUNT; FragDescr.Size := PACKET_SIZE; InUseFlag := FINISHED; END; Temp_Reg.ES := Seg(ECB_Table[Index]^); (* Register vorbereiten *) Temp_Reg.SI := Ofs(ECB_Table[Index]^); Temp_Reg.BX := DO_RECEIVE; IPX_Call (Temp_Reg); IF Temp_Reg.AL = NO_SOCKET THEN BEGIN IPX_Receive := DEVICE_SW_ERROR; EXIT; END; IPX_Receive := SUCCESS; END; FUNCTION IPX_Done ( Socket : WORD; Code : BYTE; VAR Source_Addr : Network_Address; VAR Buffer : SData ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Funktion liefert den Status einer vorher abgesetz- *) (* ten Routine. Zurueckgegeben wird, ob die Routine schon *) (* beendet ist oder nicht sowie eventuelle Daten. *) (* *) (* *) (* PARAMETER : IN : Socket = Sockelnummer, auf der die Funktion *) (* ausgefuehrt werden soll. *) (* Code = Routine, deren Status ueberprueft *) (* werden soll. *) (* *) (* OUT: Source_Addr = Vollstaendige Netzwerkadresse der *) (* Gegenstation, von der Daten einge- *) (* troffen sind. *) (* Buffer = Buffer, in dem eventuelle Daten *) (* abgelegt werden koennen. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i : INTEGER; (* Laufvariable *) Index : INTEGER; (* Index auf ECB_Table *) Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) BEGIN Socket := Swap(Socket); (* In Motorola Format konvertieren *) Index := 1; (* Sockel suchen *) WHILE (ECB_Table[Index]^.SocketNumber <> Socket) DO BEGIN IF Index >= MAX_SOCKETS THEN BEGIN IPX_Done := PARAMETER_ERROR; (* Sockel existiert nicht *) EXIT; END; Index := Index + 1; END; (* Test ob Funktion beendet *) IF ECB_Table[Index]^.InUseFlag <> FINISHED THEN BEGIN IPX_Done := NOT_ENDED; EXIT; END; CASE Code OF SEND : BEGIN (* Send Completion Code auswerten *) CASE ECB_Table[Index]^.CompletionCode OF SEND_OK : ; SOCKET_ERROR : BEGIN IPX_Done := DEVICE_SW_ERROR; EXIT; END; SIZE_ERROR : BEGIN IPX_Done := PACKET_BAD; EXIT; END; UNDELIV : BEGIN IPX_Done := PACKET_UNDELIVERIABLE; EXIT; END; HW_ERROR : BEGIN IPX_Done := DEVICE_HW_ERROR; EXIT; END ELSE BEGIN IPX_Done := DEVICE_SW_ERROR; EXIT; END; END; END; RECEIVE : BEGIN (* Receive Completion Code auswerten *) CASE ECB_Table[Index]^.CompletionCode OF REC_OK : BEGIN (* Daten in Benutzerbuffer kopieren *) WITH ECB_Table[Index]^.FragDescr DO BEGIN Buffer.Data := Address^.IPX_Data; Buffer.Length := Swap(Address^.Length) - HEADER; END; (* Netzwerkadresse umkopieren *) WITH ECB_Table[Index]^.FragDescr.Address^.Source DO BEGIN Source_Addr.Network := Network; Source_Addr.Node := Node; Source_Addr.Socket := Swap(Socket); END; END; SOCKET_ERROR : BEGIN IPX_Done := DEVICE_SW_ERROR; EXIT; END; OVERFLOW : BEGIN IPX_Done := PACKET_OVERFLOW; EXIT; END; NO_SOCKET : BEGIN IPX_Done := DEVICE_SW_ERROR; EXIT; END ELSE BEGIN IPX_Done := DEVICE_SW_ERROR; EXIT; END; END; END ELSE BEGIN IPX_Done := PARAMETER_ERROR; EXIT; END; END; IPX_Done := SUCCESS; END; FUNCTION IPX_Internetwork_Address ( VAR Network : S4Byte; VAR Node : S6Byte ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Funktion liefert die Internetzwerkadresse der *) (* jeweiligen Station. *) (* *) (* *) (* PARAMETER : OUT: Network = Netzwerkadresse *) (* Node = Knotenadresse *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR Temp_Reg : Registers; (* Temporaere Register fuer IPX-Call *) Reply_Buffer : Int_Addr; (* Temporaerer Buffer fuer Adressen *) BEGIN Temp_Reg.ES := Seg(Reply_Buffer); (* Register vorbereiten *) Temp_Reg.SI := Ofs(Reply_Buffer); Temp_Reg.BX := GET_ADDR; IPX_Call (Temp_Reg); Network := Reply_Buffer.Network; (* Daten umkopieren *) Node := Reply_Buffer.Node; IPX_Internetwork_Address := SUCCESS; END; FUNCTION IPX_To_Addr ( Network : String; Node : String; Socket : String; VAR Addr : Network_Address ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine konvertiert die Eingabestrings in die Daten- *) (* struktur Network_Address. *) (* *) (* *) (* PARAMETER : IN : Network = Netzwerkadresse die konvertiert *) (* werden soll. *) (* Node = Knotenadresse die konvertiert *) (* werden soll. *) (* Socket = Sockelnummer die konvertiert *) (* werden soll. *) (* *) (* OUT: Addr = Konvertierte vollsaendige Netz- *) (* werkadresse. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i,n,Code : INTEGER; c : CHAR; Temp : BYTE; BEGIN (* Pruefe Netzwerk und Node Laenge *) IF (ORD(Network[0]) <> (2 * NET_LENGTH)) OR (ORD(Node[0]) <> (2 * NODE_LENGTH)) THEN BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; (* Netzwerkadresse konvertieren *) i := 1; n := 1; WHILE ( i <= (2 * NET_LENGTH)) DO BEGIN c := UPCASE(Network[i]); CASE c OF 'A'..'F': Addr.Network[n] := ORD(c) - 55; '0'..'9': Addr.Network[n] := ORD(c) - 48 ELSE BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; END; Addr.Network[n] := Addr.Network[n] SHL 4; c := UPCASE(Network[i + 1]); CASE c OF 'A'..'F': Temp := ORD(c) - 55; '0'..'9': Temp := ORD(c) - 48; ELSE BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; END; Addr.Network[n] := Addr.Network[n] + Temp; i := i + 2; n := n + 1; END; (* Node-Adresse konvertieren *) i := 1; n := 1; WHILE ( i <= (2 * NODE_LENGTH)) DO BEGIN c := UPCASE(Node[i]); CASE c OF 'A'..'F': Addr.Node[n] := ORD(c) - 55; '0'..'9': Addr.Node[n] := ORD(c) - 48; ELSE BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; END; Addr.Node[n] := Addr.Node[n] SHL 4; c := UPCASE(Node[i + 1]); CASE c OF 'A'..'F': Temp := ORD(c) - 55; '0'..'9': Temp := ORD(c) - 48; ELSE BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; END; Addr.Node[n] := Addr.Node[n] + Temp; i := i + 2; n := n + 1; END; (* Sockelnummer konvertieren *) VAL (Socket,Addr.Socket,Code); IF Code <> 0 THEN BEGIN IPX_To_Addr := PARAMETER_ERROR; EXIT; END; IPX_To_Addr := SUCCESS; END; FUNCTION IPX_From_Addr ( Addr : Network_Address; VAR Network : String; VAR Node : String; VAR Socket : String ) : BYTE; (*--------------------------------------------------------------------------*) (* *) (* BESCHREIBUNG : Die Routine konvertiert die vollstaendige Netzwerk- *) (* adresse in String's. *) (* *) (* *) (* PARAMETER : IN : Addr = Vollstaendige Netzwerkadresse *) (* *) (* OUT: Network = Netzwerkadresse die konvertiert *) (* wurde. *) (* Node = Knotenadresse die konvertiert *) (* wurde. *) (* Socket = Sockelnummer die konvertiert *) (* wurde. *) (* Rueckgabewert = Fehlercode *) (* *) (*--------------------------------------------------------------------------*) VAR i,n,Code : INTEGER; c : CHAR; TempHi,TempLo : BYTE; BEGIN (* Netzwerkadresse konvertieren *) i := 1; n := 1; WHILE ( i <= (2 * NET_LENGTH)) DO BEGIN TempHi := Addr.Network[n] DIV 16; (* Hi-Nibble *) CASE TempHi OF 10..15 : Network[i] := CHR(TempHi + 55); 0..9 : Network[i] := CHR(TempHi + 48) ELSE BEGIN IPX_From_Addr := PARAMETER_ERROR; EXIT; END; END; i := i + 1; TempLo := Addr.Network[n] MOD 16; (* Lo-Nibble *) CASE TempLo OF 10..15 : Network[i] := CHR(TempLo + 55); 0..9 : Network[i] := CHR(TempLo + 48) ELSE BEGIN IPX_From_Addr := PARAMETER_ERROR; EXIT; END; END; i := i + 1; n := n + 1; END; Network[0] := CHR(i); (* Laenge Netzwerkadresse fuer String *) (* Node-Adresse konvertieren *) i := 1; n := 1; WHILE ( i <= (2 * NODE_LENGTH)) DO BEGIN TempHi := Addr.Node[n] DIV 16; (* Hi-Nibble *) CASE TempHi OF 10..15 : Node[i] := CHR(TempHi + 55); 0..9 : Node[i] := CHR(TempHi + 48) ELSE BEGIN IPX_From_Addr := PARAMETER_ERROR; EXIT; END; END; i := i + 1; TempLo := Addr.Node[n] MOD 16; (* Lo-Nibble *) CASE TempLo OF 10..15 : Node[i] := CHR(TempLo + 55); 0..9 : Node[i] := CHR(TempLo + 48) ELSE BEGIN IPX_From_Addr := PARAMETER_ERROR; EXIT; END; END; i := i + 1; n := n + 1; END; Node[0] := CHR(i - 1); (* Laenge Knotenadr. fuer String *) (* Sockelnummer konvertieren *) STR (Addr.Socket,Socket); IPX_From_Addr := SUCCESS; END; END.