فهرست منبع

Combined IP modules

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@8189 8c9fc860-2736-0410-a75d-ab315db34111
negelef 7 سال پیش
والد
کامیت
74078b26a1
4فایلهای تغییر یافته به همراه148 افزوده شده و 3267 حذف شده
  1. 0 1618
      source/AMD64.IP.Mod
  2. 0 1620
      source/I386.IP.Mod
  3. 147 25
      source/IP.Mod
  4. 1 4
      source/Release.Tool

+ 0 - 1618
source/AMD64.IP.Mod

@@ -1,1618 +0,0 @@
-(* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
-
-MODULE IP; (** AUTHOR "pjm, mvt, eb"; PURPOSE "IP (v4 and v6)"; *)
-
-IMPORT SYSTEM, KernelLog, Commands, Strings, Network;
-
-CONST
-	(* DEBUG *)
-	DEBUG = TRUE;
-
-	(** Error codes *)
-	Ok* = 0;
-	DeviceAlreadyUsed* = 3901;
-	DuplicateInterfaceName* = 3902;
-	NoInterfaceName* = 3903;
-	GatewayNotInSubnet* = 3904;
-	IPv6AdrUsedOnIPv4Interface* = 4001;
-	IPv4AdrUsedOnIPv6Interface* = 4002;
-	DublicatedAddresses* = 4003;
-	MixedIpProtocols* = 4003;
-	LocalAdrSetIntv6* = 4004;   (* local address must be NIL when calling SetAdrs on a IPv6 interface *)
-	PrefixNotSet* = 4005; (* prefix on ipv6 interface must be set with local address *)
-
-	MaxNofDNS* = 10; (** maximum number of DNS servers per interface *)
-	MaxTTL* = 255; (** maximum time-to-live on outgoing datagrams *)
-
-	NbrOfReceivers = 255; (* Number of possible receivers, i.e. possible layer 3 protocols *)
-
-	(** IP address constants *)
-	NilAdrIPv4 = 0;
-
-	(* Comparators for Adr.usedProtocols *)
-	IPv4* = 4;
-	IPv6* = 6;
-	NilAdrIdent = -1;	(* usedProtocol of NilAdrs *)
-
-	(* ICMP *)
-	ICMPHdrLen* = 4;
-	ICMPSrcLLAdrOptionType* = 1;
-	ICMPTargetLLAdrOptionType* = 2;
-	ICMPPrefixInfoOptionType* = 3;
-	ICMPRedirectHdrOptionType* = 4;
-	ICMPMTUOptionType* = 5;
-	ICMPAdvIntOptionType* = 7;
-	ICMPHomeAgOptionType* = 8;
-	ICMPRouteOption* = 9;
-
-
-TYPE
-	Adr* = RECORD
-		ipv4Adr*: LONGINT;
-		ipv6Adr*: ARRAY 16 OF CHAR;
-		usedProtocol*: LONGINT;
-		data*: LONGINT;
-	END; (** An IP Address.	usedProtocol = 0: No protocol yet used
-							usedProtocol = IPv4: IPv4 address stored in field ipv4Adr
-							usedProtocol = IPv6: IPv6 address stored in field ipv6Adr
-							data can be used to store additional informations. I.e. in IPv6 the
-							prefix length is stored in the data field *)
-
-TYPE
-	Packet* = POINTER TO ARRAY OF CHAR;
-
-	Name* = ARRAY 128 OF CHAR; (** Name type for interface name *)
-
-	Interface* = OBJECT
-	VAR
-		(** IP addresses of this interface. *)
-		localAdr*, maskAdr*, gatewayAdr*, subnetAdr*, broadAdr*: Adr;
-
-		(** name of the interface *)
-		name*: Name;
-
-		(** Device that the interface belongs to *)
-		dev*: Network.LinkDevice;
-
-		(** DNS server list - can be used by DNS, not used in IP itself *)
-		DNS-: ARRAY MaxNofDNS OF Adr; (* DNS server list *)
-		DNScount*: LONGINT; (* number of DNS servers in list *)
-
-		(* interface *)
-		next*: Interface; (* next pointer for interface list *)
-		closed*: BOOLEAN; (* is interface already closed? *)
-		protocol*: LONGINT; (* Interface for IPv4 or IPv6?. Only used by IP otherwise use dynamic type checking! *)
-
-
-		(** Set addresses. Is normally called just after instanciation, but can also be called later, e.g. by DHCP.
-			If "gatewayAdr" is "NilAdr", the subnet is considered to have no gateway, else it must be in the same
-			subnet as the "localAdr".
-			"domain" can be an empty string. It is normally used by a DNS implementation. It is not used in IP directly.
-			In IPv6 maskAdr is the prefix of the currently IP address *)
-		PROCEDURE SetAdrs*(localAdr, maskOrPrefixAdr, gatewayAdr: Adr; VAR res: WORD);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END SetAdrs;
-
-
-		(** Remove all domain name servers from the interface. *)
-		PROCEDURE DNSRemoveAll*;
-		BEGIN {EXCLUSIVE}
-			DNScount := 0;
-		END DNSRemoveAll;
-
-
-		(** Add a domain name server to the interface. *)
-		PROCEDURE DNSAdd*(adr: Adr);
-		VAR
-			i: LONGINT;
-
-		BEGIN {EXCLUSIVE}
-			(* concurrent lookup is consistent *)
-			ASSERT(DNScount < MaxNofDNS);
-
-			i := 0;
-			WHILE i < DNScount DO
-				IF AdrsEqual (DNS[i],adr) THEN RETURN END;
-				INC(i)
-			END;
-			DNS[DNScount] := adr;
-			INC(DNScount);
-		END DNSAdd;
-
-
-		(** Remove a domain name server from the interface. *)
-		PROCEDURE DNSRemove*(adr: Adr);
-		VAR i: LONGINT;
-		BEGIN {EXCLUSIVE}
-			(* concurrent lookup could result in a duplicate address in worst-case *)
-			(* this happends hardly ever and is harmless for DNS anyway *)
-			i := 0;
-			WHILE (i < DNScount) & (~ AdrsEqual(DNS[i],adr)) DO
-				INC(i)
-			END;
-			IF i < DNScount THEN
-				INC(i);
-				WHILE i < DNScount DO
-					DNS[i-1] := DNS[i];
-					INC(i);
-				END;
-				DEC(DNScount);
-			END;
-		END DNSRemove;
-
-
-		(** Send an IP packet on this interface. *)
-		PROCEDURE Send*(type: LONGINT; destAdr: Adr; CONST l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, TTL: LONGINT);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END Send;
-
-
-		(* Internal procedure to perform the rest of the send operation. Used by "Send" and for IP forwarding. *)
-		PROCEDURE DoSend*(destAdr: Adr; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT) ;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END DoSend;
-
-
-		(** Enumerate all ARP table entries. *)
-		PROCEDURE ARPEnumerate*(handle: ARPHandler);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ARPEnumerate;
-
-
-		(** Close and deactivate the interface, i.e. remove it from the configuration. *)
-		PROCEDURE Close*;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END Close;
-
-
-		(** Check if adr is a broadcast address *)
-		PROCEDURE IsBroadcast*(adr: Adr) : BOOLEAN;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IsBroadcast;
-
-
-		(** Check if adr is a multicast address *)
-		PROCEDURE IsMulticast*(adr: Adr) : BOOLEAN;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IsMulticast;
-
-
-		(** Receive an IP packet *)
-		PROCEDURE IPInput*(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IPInput;
-
-
-		(** Reads the source address of a IP packet buffer *)
-		PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): Adr;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ReadSrcAdr;
-
-
-		(** Reads the destination address of a IP packet buffer *)
-		PROCEDURE ReadDestAdr* (buffer: Network.Buffer): Adr;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ReadDestAdr;
-
-
-		(** Creates a pseudo-header for checksum calculation (TCP/UDP) and returns the length of this header *)
-		PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR;  src, dst: Adr; protocol, pktLengthUpperLayer: LONGINT): LONGINT;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END WritePseudoHeader;
-
-
-		(** Writes the configuration of this interface *)
-		PROCEDURE OutInterface*;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END OutInterface;
-
-	END Interface;
-
-
-TYPE
-	(* List of interfaces *)
-	InterfaceList* = POINTER TO RECORD
-		interface*: Interface;
-		next*: InterfaceList;
-	END;
-
-	Receiver* = PROCEDURE {DELEGATE} (int: Interface; type: LONGINT; fip, lip: Adr; buffer: Network.Buffer);
-	V6InterfaceByDstIP* = PROCEDURE {DELEGATE} (dstAdr: Adr): Interface;
-
-	(** Handler for ARPPool.Enumerate. *)
-	ARPHandler* = PROCEDURE {DELEGATE} (ip: Adr; complete: BOOLEAN; link: Network.LinkAdr; size, sendTime, updateTime, updateDate, hash: LONGINT);
-
-	InterfaceHandler* = PROCEDURE {DELEGATE} (int: Interface);
-
-
-VAR
-	(* receiver *)
-	receivers*: ARRAY 256 OF Receiver; (* registered receivers - array position is IPv4 protocol field or IPv6 next header field *)
-
-	(* Interface by dst for IPv6 *)
-	v6InterfaceByDstIP*: V6InterfaceByDstIP;
-
-	(* IP *)
-	NilAdr*: Adr; (* To check if an IP address is NIL use IsNilAdr instead *)
-	preferredProtocol*: LONGINT;	(* Preferred IP protocol *)
-
-	(* IP counters *)
-	NIPSentToSubnet*, NIPSentToGateway*, NIPSentBroadcast*, NIPCantFragment*,
-	NIPRcvTotal*, NIPTooSmall*, NIPBadVersion*, NIPOptions*, NIPBadChecksum*,
-	NIPBadLength*, NIPTrim*, NIPBadHdrLen*, NIPNotForUs*, NIPCantReassemble*, NIPSrcIsBroadcast*,
-	NIPDelivered*, NIPNoReceiver*, NIPForwarded*, NIPSentLocalLoopback*, NIPSentPointToPoint*: LONGINT;
-
-	(* turn on/off IP forwarding, echo replay *)
-	IPForwarding*: BOOLEAN;
-	EchoReply*: BOOLEAN;
-
-	(* Interface *)
-	interfaces*: Interface; (* list of all installed interfaces *)
-
-	counter: LONGINT; (* Use it only in the module body! *)
-
-
-(** Is address not yet specified *)
-PROCEDURE IsNilAdr* (adr: Adr): BOOLEAN;
-VAR
-	isNil: BOOLEAN;
-	i: LONGINT;
-
-BEGIN
-	CASE adr.usedProtocol OF
-		IPv4:
-			RETURN (adr.ipv4Adr = NilAdrIPv4)
-
-		|IPv6:
-			isNil := TRUE;
-			i := 0;
-			WHILE ((i<16) & isNil) DO
-				IF adr.ipv6Adr[i] # 0X THEN
-					isNil := FALSE;
-				END;
-				INC(i);
-			END;
-			RETURN isNil;
-
-		|NilAdrIdent:
-			RETURN TRUE;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN TRUE;
-	END;
-END IsNilAdr;
-
-
-(* Checks if two addresses are equal *)
-PROCEDURE AdrsEqual* (adr1, adr2: Adr): BOOLEAN;
-VAR
-	equal: BOOLEAN;
-	i: LONGINT;
-
-BEGIN
-	IF adr1.usedProtocol # adr2.usedProtocol THEN
-		RETURN FALSE;
-	END;
-
-	CASE adr1.usedProtocol OF
-		IPv4:
-			IF adr1.ipv4Adr = adr2.ipv4Adr THEN
-				RETURN TRUE;
-			END;
-
-		|IPv6:
-			equal := TRUE;
-			i := 0;
-			WHILE ((i < 16) & equal) DO
-				IF adr1.ipv6Adr[i] # adr2.ipv6Adr[i] THEN
-					equal := FALSE;
-				END;
-				INC(i);
-			END;
-
-			IF adr1.data # adr2.data THEN
-				equal := FALSE;
-			END;
-
-			RETURN equal;
-
-		|NilAdrIdent:
-			(* both addresses NIL therefore equal *)
-			IF adr2.usedProtocol = NilAdrIdent THEN
-				RETURN TRUE;
-			ELSE
-				RETURN FALSE;
-			END;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN FALSE;
-	END;
-	RETURN FALSE;
-END AdrsEqual;
-
-
-(** Convert a dotted-decimal string to an ip address. Return NilAdr on failure. *)
-PROCEDURE StrToAdr*(ipString: ARRAY OF CHAR): Adr;
-VAR
-	retAdr: Adr;
-	i, j, x: LONGINT;
-	adr: ARRAY 4 OF CHAR;
-	ok: BOOLEAN;
-	charCount: LONGINT;				(* ipv6: number of character between two : *)
-	ipv6AdrPart: ARRAY 6 OF CHAR;		(* two bytes of an IPv6 address *)
-	ipv6AdrRight: ARRAY 16 OF CHAR;	(* right part of an IPv6 address; after :: *)
-	hexToChar: ARRAY 3 OF CHAR;
-	leftParts: LONGINT;					(* number of bytes before :: *)
-	rightParts: LONGINT;				(* number of bytes after :: *)
-	val, res: LONGINT;
-	state: LONGINT;						(* state of the FSM look at the eof for more info *)
-	dPointOcc: BOOLEAN;				(* double point occured *)
-	prefixVal: LONGINT;
-
-
-	(* compute a subpart (two bytes) of a IPv6 address; subpart:=between two : *)
-	PROCEDURE ComputeIPv6Part():BOOLEAN;
-	BEGIN
-		CASE charCount OF
-			0:
-				RETURN TRUE;
-
-			|1,2:
-				IF dPointOcc THEN
-					ipv6AdrRight[rightParts] := 0X;
-					INC(rightParts);
-				ELSE
-					retAdr.ipv6Adr[leftParts] := 0X;
-					INC(leftParts);
-				END;
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			|3:
-				hexToChar[0] := ipv6AdrPart[0];
-				hexToChar[1] := 0X;
-				Strings.HexStrToInt(hexToChar, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-				ipv6AdrPart[0] := "0";
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			|4:
-				hexToChar[0] := ipv6AdrPart[0];
-				hexToChar[1] := ipv6AdrPart[1];
-				hexToChar[2] := 0X;
-				Strings.HexStrToInt(hexToChar, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-				ipv6AdrPart[0] := "0";
-				ipv6AdrPart[1] := "0";
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			ELSE
-				IF DEBUG THEN
-					ASSERT(TRUE);
-				END;
-				RETURN FALSE;
-		END;
-		charCount := 0;
-		RETURN TRUE;
-	END ComputeIPv6Part;
-
-
-BEGIN
-	retAdr := NilAdr;
-
-	IF IsValidIPv4Str(ipString) THEN
-		(* Return an ipv4 address *)
-		i := 0;
-		j := 0;
-		x := -1;
-		ok := FALSE;
-
-		LOOP
-			IF (ipString[i] = ".") OR (ipString[i] = 0X) THEN
-				IF (x < 0) OR (x > 255) OR (j = 4) THEN EXIT END;
-				adr[j] := CHR(x);
-				IF ipString[i] = 0X THEN ok := (j = 3); EXIT END;
-				x := -1; INC(i); INC(j)
-			ELSIF (ipString[i] >= "0") & (ipString[i] <= "9") THEN
-				IF x = -1 THEN x := 0 END;
-				x := x*10 + (ORD(ipString[i])-ORD("0"));
-				INC(i)
-			ELSE
-				EXIT
-			END
-		END;
-
-		IF ok THEN
-			retAdr.ipv4Adr := SYSTEM.VAL (LONGINT, adr);
-			retAdr.usedProtocol := IPv4;
-			RETURN retAdr;
-		ELSE
-			RETURN NilAdr;
-		END
-
-
-	(* IPv6 *)
-	ELSIF IsValidIPv6Str(ipString) THEN
-		i := 0;
-		state := 1;
-		charCount := 0;
-		dPointOcc := FALSE;
-		retAdr.usedProtocol := 6;
-		retAdr.ipv4Adr := NilAdrIPv4;
-		i := 0;
-		j := 0;
-		charCount := 0;
-		leftParts := 0;
-		rightParts := 0;
-		prefixVal := 0;
-
-		Strings.UpperCase(ipString);
-
-		WHILE (i < (LEN(ipString) - 1)) & (ipString[i] # 0X) DO
-
-			CASE state OF  (* Using the same FSM as IsValidIPv6Str *)
-				-1:	(* Error state
-					    Should never happen, is checked by IsValidIPv6Str() *)
-					RETURN NilAdr;
-
-				|1:	(* reading two blocks of two bytes of 0-9\A-F *)
-					IF ipString[i] = ":" THEN
-						ipv6AdrPart[charCount] := 0X;
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-						state := 2;
-
-					ELSIF ipString[i] = "/" THEN
-						ipv6AdrPart[charCount] := 0X;
-
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-						state := 3;
-
-					ELSE
-						(* 0-9, A-F *)
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-
-				|2:	(* a : occured *)
-					IF ipString[i] = ":" THEN
-						dPointOcc := TRUE;
-						state := 4;
-					ELSE
-						(* 0-9, A-F *)
-						state := 1;
-						charCount := 0;
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-
-				|3:	(* prefix will follow *)
-					prefixVal := (prefixVal * 10) + (ORD(ipString[i]) - ORD("0"));
-
-				|4:	(* A :: occured *)
-					IF ipString[i] = "/" THEN
-						state := 3;
-					ELSE
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-
-						(* 0-9, A-F *)
-						state := 1;
-						charCount := 0;
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-				ELSE
-					IF DEBUG THEN
-						ASSERT(TRUE);
-					END;
-			END;
-			INC(i);
-		END;
-
-		ipv6AdrPart[charCount] := 0X;
-		IF charCount # 0 THEN
-			IF ~ComputeIPv6Part() THEN
-				RETURN NilAdr;
-			END;
-		END;
-
-		IF dPointOcc THEN
-			(* fill 0X for :: *)
-			FOR i:= leftParts TO ((LEN(retAdr.ipv6Adr) -1) - rightParts) DO
-				retAdr.ipv6Adr[i] := 0X;
-			END;
-
-			(* fill part behind :: *)
-			FOR i := 0 TO (rightParts - 1) DO
-				retAdr.ipv6Adr[(LEN(retAdr.ipv6Adr) - rightParts) + i] := ipv6AdrRight[i];
-			END;
-		END;
-
-		IF prefixVal > 64 THEN
-			RETURN NilAdr;
-		END;
-		retAdr.data := prefixVal;
-		RETURN retAdr;
-	END;
-	RETURN NilAdr;
-END StrToAdr;
-
-
-(** Convert an IP address to a dotted-decimal string. *)
-PROCEDURE AdrToStr*(adr: Adr; VAR string: ARRAY OF CHAR);
-VAR
-	i, j, x: LONGINT;
-	a: ARRAY 4 OF CHAR;
-	val: LONGINT;
-	hexToStr: ARRAY 5 OF CHAR;
-	prefixLenStr: ARRAY 64 OF CHAR;
-	maxZeroRow: LONGINT;
-	currentZeroRow: LONGINT;
-	maxZeroStart: LONGINT;
-	currentZeroStart: LONGINT;
-	lastZero: BOOLEAN;
-	lastDPoint: BOOLEAN;
-	countEnded: BOOLEAN;
-
-BEGIN
-	CASE adr.usedProtocol OF
-		IPv4:
-			ASSERT(LEN(string) >= 16);	(* enough space for largest result *)
-			Network.Put4(a, 0, adr.ipv4Adr);
-			i := 0;
-			FOR j := 0 TO 3 DO
-				x := ORD(a[j]);
-				IF x >= 100 THEN string[i] := CHR(ORD("0")+x DIV 100); INC(i) END;
-				IF x >= 10 THEN string[i] := CHR(ORD("0")+x DIV 10 MOD 10); INC(i) END;
-				string[i] := CHR(ORD("0")+x MOD 10); INC(i);
-				IF j = 3 THEN string[i] := 0X ELSE string[i] := "." END;
-				INC(i)
-			END
-
-		|IPv6:
-			FOR i := 0 TO (LEN(adr.ipv6Adr) -1) BY 2 DO
-				(* simple version *)
-				val :=  ORD(adr.ipv6Adr[i]) * 256;
-				val := val + ORD(adr.ipv6Adr[i+1]);
-				Strings.IntToHexStr (val, 3, hexToStr);
-
-				(* Delete leading zeros *)
-				WHILE (hexToStr[0] = "0") & (hexToStr[1] # 0X) DO
-					Strings.Delete(hexToStr, 0, 1);
-				END;
-				Strings.Append (string, hexToStr);
-
-				IF i # (LEN(adr.ipv6Adr) - 2) THEN
-					Strings.Append (string, ":");
-				END;
-			END;
-
-			(* replace longest row of zeros with :: *)
-			maxZeroRow := 0;
-			currentZeroRow := 0;
-			maxZeroStart := 0;
-			currentZeroStart := 0;
-			i := 0;
-			lastZero := FALSE;
-			lastDPoint := TRUE;
-			countEnded :=TRUE;
-
-			WHILE string[i] # 0X DO
-				IF string[i] = "0" THEN
-					IF lastDPoint THEN
-						INC(currentZeroRow);
-						lastZero := TRUE;
-						lastDPoint := FALSE;
-						IF countEnded THEN
-							currentZeroStart := i;
-							countEnded := FALSE;
-						END;
-					END;
-				ELSIF string[i] = ":" THEN
-					lastDPoint := TRUE;
-					IF lastZero THEN
-						lastZero := FALSE;
-					END;
-				ELSE
-					IF lastDPoint THEN
-						lastDPoint := FALSE;
-						countEnded := TRUE;
-						IF currentZeroRow > maxZeroRow THEN
-							maxZeroRow := currentZeroRow;
-							maxZeroStart := currentZeroStart;
-						END;
-					END;
-				END;
-
-				INC(i);
-			END;
-
-			IF ~countEnded THEN
-				IF currentZeroRow > maxZeroRow THEN
-					maxZeroRow := currentZeroRow;
-					maxZeroStart := currentZeroStart;
-				END;
-			END;
-			IF maxZeroRow # 0 THEN
-				(* write a :: *)
-				IF maxZeroStart = 0 THEN
-					string[0] := ":";
-					i := 1;
-					WHILE ((string[i] # 0X) & ~((string[i] # "0") & (string[i] # ":"))) DO INC(i); END;
-					IF string[i] = 0X THEN
-						string := "::";
-					ELSE
-						Strings.Delete(string, 1, i-2);
-					END;
-				ELSE
-					i := maxZeroStart;
-					WHILE ((string[i] = "0") OR (string[i] = ":")) DO INC(i); END;
-					IF string[i] = 0X THEN
-						string[maxZeroStart] := ":";
-						string[maxZeroStart+1] := 0X;
-					ELSE
-						Strings.Delete(string, maxZeroStart, i - maxZeroStart - 1);
-					END;
-				END;
-			END;
-
-			IF adr.data # 0 THEN
-				(* write prefix *)
-				Strings.IntToStr(adr.data, prefixLenStr);
-				Strings.Append (string, "/");
-				Strings.Append (string, prefixLenStr);
-			END;
-
-		ELSE
-			IF IsNilAdr (adr) THEN
-				string := "";
-			END;
-	END;
-END AdrToStr;
-
-
-(** Convert a IP address from an array [ofs..ofs+x] to an
-	Adr-type variable.
-	Example for IPv4:
-	If the LSB (least significant byte) is stored the the beginning [ofs],
-	LSBfirst must be set to TRUE.
-		(address "a.b.c.d" is stored as [d,c,b,a])
-	If the LSB is stored at the end [ofs+3], LSBfirst must be set to FALSE.
-		(address "a.b.c.d" is stored as [a,b,c,d])
-*)
-PROCEDURE ArrayToAdr*(CONST array: ARRAY OF CHAR; ofs, protocol: LONGINT; LSBfirst: BOOLEAN): Adr;
-VAR
-	adr: Adr;
-	i, swapTemp: LONGINT;
-BEGIN
-	ASSERT((protocol = 4) OR (protocol = 6));
-
-	IF protocol = IPv4 THEN  (* index check *)
-		IF ~(ofs + 4 <= LEN(array)) THEN
-			RETURN NilAdr;
-		END;
-
-		SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv4Adr), 4);
-		IF LSBfirst THEN
-			SwapEndian(adr.ipv4Adr);
-		END;
-		adr.usedProtocol := IPv4;
-
-	ELSIF protocol = IPv6 THEN
-		IF ~(ofs + 16 <= LEN(array)) THEN
-			RETURN NilAdr;
-		END;
-
-		SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv6Adr), 16);
-		IF LSBfirst THEN
-			FOR i := 0 TO 3 DO
-				SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
-				SwapEndian(swapTemp);
-				SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(adr.ipv6Adr[i*4]), 4);
-			END;
-		END;
-		adr.usedProtocol := IPv6;
-
-	ELSE
-		IF DEBUG THEN
-			ASSERT(TRUE);
-		END;
-		RETURN NilAdr;
-	END;
-	RETURN adr;
-END ArrayToAdr;
-
-
-(** Convert an Adr-type variable  into an array [ofs..ofs+x]
-	Example in IPv4:
-	If the LSB (least significant byte) should be stored the the
-	beginning [ofs], LSBfirst must be set to TRUE.
-		(address "a.b.c.d" is stored as [d,c,b,a])
-	If the LSB should be stored at the end [ofs+3], LSBfirst must be set to FALSE.
-		(address "a.b.c.d" is stored as [a,b,c,d])
-*)
-PROCEDURE AdrToArray*(adr: Adr; VAR array: ARRAY OF CHAR; ofs: LONGINT; LSBfirst: BOOLEAN);
-VAR
-	tempAdr: Adr;
-	i, swapTemp: LONGINT;
-
-BEGIN
-	tempAdr := adr;
-
-	CASE adr.usedProtocol OF
-		IPv4:
-			IF ~(ofs+4 <= LEN(array)) THEN
-				tempAdr := NilAdr;
-			END;
-
-			IF LSBfirst THEN
-				SwapEndian(tempAdr.ipv4Adr);
-			END;
-			SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv4Adr), ADDRESSOF(array[ofs]), 4);
-
-		| IPv6:
-			IF ~(ofs + 16 <= LEN(array)) THEN
-				tempAdr := NilAdr;
-			END;
-
-			IF LSBfirst THEN
-				FOR i := 0 TO 3 DO
-					SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
-					SwapEndian(swapTemp);
-					SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(tempAdr.ipv6Adr[i*4]), 4);
-				END;
-			END;
-			SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr), ADDRESSOF(array[ofs]), 16);
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-	END;
-END AdrToArray;
-
-
-(** Reads the IP source address from a buffer *)
-PROCEDURE SrcAdrFromBuffer* (buffer: Network.Buffer): Adr;
-VAR
-	i: LONGINT;
-	adr: Adr;
-
-BEGIN
-	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
-		IPv4:
-			adr.usedProtocol := IPv4;
-			adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+12]);
-			SetIPv6AdrNil(adr);
-			RETURN adr;
-
-		|IPv6:
-			adr.usedProtocol := IPv6;
-			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+8 + i];
-			END;
-			adr.ipv4Adr := NilAdrIPv4;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NilAdr;
-	END;
-	RETURN NilAdr;
-END SrcAdrFromBuffer;
-
-
-(** Reads the IP destination address from a buffer *)
-PROCEDURE DestAdrFromBuffer* (buffer: Network.Buffer): Adr;
-VAR
-	adr: Adr;
-	i: LONGINT;
-
-BEGIN
-	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
-		IPv4:
-			adr.usedProtocol := IPv4;
-			adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+16]);
-			SetIPv6AdrNil(adr);
-			RETURN adr;
-
-		|IPv6:
-			adr.usedProtocol := IPv6;
-			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+24 + i];
-			END;
-			adr.ipv4Adr := NilAdrIPv4;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NilAdr;
-	END;
-	RETURN NilAdr;
-END DestAdrFromBuffer;
-
-
-(* Swap internal representation of an IP address from big to little endian or vice versa. *)
-PROCEDURE -SwapEndian(VAR adr: LONGINT);
-CODE {SYSTEM.AMD64}
-	POP RAX
-	MOV ECX, [RAX]
-	BSWAP ECX
-	MOV [RAX], ECX
-END SwapEndian;
-
-
-(** Write an IP address. *)
-PROCEDURE OutAdr*(adr: Adr);
-VAR
-	s: ARRAY 64 OF CHAR;
-
-BEGIN
-	AdrToStr(adr, s); KernelLog.String(s);
-END OutAdr;
-
-
-(** Enumerate all installed interfaces *)
-PROCEDURE Enumerate*(handler: InterfaceHandler);
-VAR item: Interface;
-BEGIN
-	item := interfaces;
-	WHILE item # NIL DO
-		handler(item);
-		item := item.next;
-	END;
-END Enumerate;
-
-
-(** Output the configuration of the specified interface. Can be used as Handler in Enumerate(). *)
-PROCEDURE OutInterface*(interface: Interface);
-BEGIN
-	interface.OutInterface;
-END OutInterface;
-
-
-(** Aos command: Output statistics and configuration of all installed interfaces. *)
-PROCEDURE IPConfig*(context : Commands.Context);
-BEGIN
-	context.out.String("Interfaces:"); context.out.Ln;
-	context.out.String("----------------------"); context.out.Ln;
-	Enumerate(OutInterface);
-	context.out.Ln;
-	context.out.String("IP statistics:"); context.out.Ln;
-	context.out.String("----------------------"); context.out.Ln;
-	context.out.String("NIPSentToSubnet"); context.out.Int(NIPSentToSubnet,10);context.out.Ln;
-	context.out.String("NIPSentToGateway"); context.out.Int(NIPSentToGateway,10);context.out.Ln;
-	context.out.String("NIPSentBroadcast"); context.out.Int(NIPSentBroadcast,10);context.out.Ln;
-	context.out.String("NIPCantFragment"); context.out.Int(NIPCantFragment,10);context.out.Ln;
-	context.out.String("NIPRcvTotal"); context.out.Int(NIPRcvTotal,10);context.out.Ln;
-	context.out.String("NIPTooSmall"); context.out.Int(NIPTooSmall,10);context.out.Ln;
-	context.out.String("NIPBadVersion"); context.out.Int(NIPBadVersion,10);context.out.Ln;
-	context.out.String("NIPOptions"); context.out.Int(NIPOptions,10);context.out.Ln;
-	context.out.String("NIPBadChecksum"); context.out.Int(NIPBadChecksum,10);context.out.Ln;
-	context.out.String("NIPBadLength"); context.out.Int(NIPBadLength,10);context.out.Ln;
-	context.out.String("NIPTrim"); context.out.Int(NIPTrim, 10);context.out.Ln;
-	context.out.String("NIPBadHdrLen"); context.out.Int(NIPBadHdrLen,10);context.out.Ln;
-	context.out.String("NIPNotForUs"); context.out.Int(NIPNotForUs,10);context.out.Ln;
-	context.out.String("NIPCantReassemble"); context.out.Int(NIPCantReassemble,10);context.out.Ln;
-	context.out.String("NIPSrcIsBroadcast"); context.out.Int(NIPSrcIsBroadcast,10);context.out.Ln;
-	context.out.String("NIPDelivered"); context.out.Int(NIPDelivered,10);context.out.Ln;
-	context.out.String("NIPNoReceiver"); context.out.Int(NIPNoReceiver,10);context.out.Ln;
-	context.out.String("NIPForwarded"); context.out.Int(NIPForwarded,10);context.out.Ln;
-	context.out.String("NIPSentLocalLoopback"); context.out.Int(NIPSentLocalLoopback,10);context.out.Ln;
-	context.out.String("NIPSentPointToPoint"); context.out.Int(NIPSentPointToPoint,10);context.out.Ln; context.out.Ln;
-END IPConfig;
-
-
-(** 	First part of a split checksum operation. len must be non-zero and even. chk1 must be 0 at the
-	beginning. The result can be passed to a following call to Checksum1(). The last chk1 result must
-	be passed to Checksum2, which sums the data following sequentially on the data summed by this
-	operation. Carries from bit 15 are accumulated in the top 16 bits, so at most 65535 words can be
-	summed by Checksum1 and Checksum2 together. *)
-PROCEDURE Checksum1*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): LONGINT;
-CODE {SYSTEM.AMD64}
-	MOV EAX, [RBP + chk1]
-	MOV RBX, [RBP + data]
-	ADD EBX, [RBP + ofs]
-	MOV ECX, [RBP + len]
-	SHR ECX, 1
-	JNC sloop
-	PUSH 8	; ASSERT(~ODD(len))
-	INT 3
-sloop:
-	MOVZX EDX, WORD [RBX]
-	ADD EAX, EDX
-	ADD RBX, 2
-	DEC ECX
-	JNZ sloop
-END Checksum1;
-
-
-(** 	Continue a checksum operation. len can be zero or odd. chk1 can be the result of Checksum1 for
-	the immediately preceding data, or 0 for contiguous data. *)
-PROCEDURE Checksum2*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): INTEGER;
-	CODE {SYSTEM.AMD64}
-	MOV EAX, [RBP + chk1]
-	MOV RBX, [RBP + data]
-	ADD EBX, [RBP + ofs]
-	MOV ECX, [RBP + len]
-	SHR ECX, 1
-	JZ eloop
-sloop:
-	MOVZX EDX, WORD [RBX]
-	ADD EAX, EDX
-	ADD RBX, 2
-	DEC ECX
-	JNZ sloop
-eloop:
-	TEST [RBP + len], 1	; check for odd length
-	JZ even
-	MOVZX EDX, BYTE [RBX]	; add last byte
-	ADD EAX, EDX
-even:
-	MOV ECX, EAX	; now add in all the carries
-	SHR ECX, 16
-	AND EAX, 0FFFFH
-	ADD EAX, ECX
-	MOV ECX, EAX	; add in additional carry
-	SHR ECX, 16
-	ADD EAX, ECX	; result is in low 16 bits of EAX
-	NOT EAX
-END Checksum2;
-
-
-(* Return TRUE if "adr1" and "adr2" are in the same subnet defined by "mask". Only for IPv4 *)
-PROCEDURE SameSubnetv4(adr1, adr2, mask: LONGINT): BOOLEAN;
-CODE {SYSTEM.AMD64}
-	MOV EAX, [RBP + adr1]
-	MOV EBX, [RBP + adr2]
-	MOV ECX, [RBP + mask]
-	AND EAX, ECX
-	AND EBX, ECX
-	CMP EAX, EBX
-	SETZ AL
-END SameSubnetv4;
-
-
-(* Return TRUE if adr matches the prefix *)
-PROCEDURE MatchPrefix*(adr: Adr; prefix: Adr): BOOLEAN;
-VAR
-	bytesToCheck: LONGINT;
-	bitsToCheck: LONGINT;
-	i: LONGINT;
-	matches: BOOLEAN;
-	diffSet: SET;
-
-BEGIN
-	IF DEBUG THEN
-		ASSERT ((IsNilAdr(adr)) OR (adr.usedProtocol = IPv6));
-	END;
-
-	matches := TRUE;
-
-	bytesToCheck := prefix.data DIV 8;
-	bitsToCheck := prefix.data MOD 8;
-
-	FOR i := 0 TO bytesToCheck - 1 DO
-		IF adr.ipv6Adr[i] # prefix.ipv6Adr[i] THEN
-			matches := FALSE;
-		END;
-	END;
-
-	IF bitsToCheck # 0 THEN
-		diffSet := {};
-		FOR i := 0 TO 8 - bitsToCheck - 1 DO
-			diffSet := diffSet + {i};
-		END;
-
-		FOR i := 0 TO bitsToCheck - 1 DO
-			IF (SYSTEM.VAL(SET, adr.ipv6Adr[bytesToCheck]) - diffSet) # (SYSTEM.VAL(SET, prefix.ipv6Adr[bytesToCheck]) - diffSet) THEN
-				matches := FALSE;
-			END;
-		END;
-	END;
-	RETURN matches;
-END MatchPrefix;
-
-
-(** Return the interface on which packets with "dst" address should be sent. Return NIL if no interface matches. *)
-PROCEDURE InterfaceByDstIP*(dest: Adr): Interface;
-VAR
-	item, gw: Interface;
-
-BEGIN
-	CASE dest.usedProtocol OF
-		IPv4:
-			gw := NIL;
-			item := interfaces;
-			LOOP
-				IF item = NIL THEN EXIT END;
-				IF (item.protocol = IPv4) & (~IsNilAdr(item.localAdr)) & (item.dev.Linked() # Network.LinkNotLinked) THEN
-					IF SameSubnetv4(dest.ipv4Adr, item.subnetAdr.ipv4Adr, item.maskAdr.ipv4Adr) THEN
-						EXIT;
-					ELSIF (gw = NIL) & (~IsNilAdr(item.subnetAdr)) THEN
-						IF item.protocol # IPv4 THEN
-							gw := item;
-						ELSIF ~IsNilAdr(item.gatewayAdr) THEN
-							gw := item;
-						END;
-					END;
-				END;
-				item := item.next;
-			END;
-			IF item # NIL THEN
-				RETURN item;
-			ELSE
-				RETURN gw;
-			END;
-
-		|IPv6:
-			(* Requires special handling when multiple devices are present *)
-			RETURN v6InterfaceByDstIP(dest);
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NIL;
-	END;
-END InterfaceByDstIP;
-
-
-(** Return the reference to an installed interface by its name. NIL is returned if no interface with this name
-	was found. *)
-PROCEDURE InterfaceByName*(CONST name: ARRAY OF CHAR): Interface;
-VAR item: Interface;
-BEGIN
-	item := interfaces;
-	WHILE (item # NIL) & (item.name # name) DO
-		item := item.next;
-	END;
-	RETURN item;
-END InterfaceByName;
-
-
-(** Delivers first preferred (if possible) interface of an device.
-	Return the reference to an installed interface by its device. NIL is returned if no interface with this
-	device was found. *)
-PROCEDURE InterfaceByDevice*(dev: Network.LinkDevice): Interface;
-VAR
-	item: Interface;
-	unprefInt: Interface;
-BEGIN
-	unprefInt := NIL;
-	item := interfaces;
-	WHILE (item # NIL) DO
-		IF item.dev = dev THEN
-			IF item.protocol # preferredProtocol THEN
-				unprefInt := item;
-			ELSE
-				RETURN item;
-			END;
-		END;
-		item := item.next;
-	END;
-	(* return interface with unpreferred protocol or NIL *)
-	RETURN unprefInt;
-END InterfaceByDevice;
-
-
-(** Return a list of installed interfaces of a certain device. *)
-PROCEDURE InterfaceListByDevice* (dev: Network.LinkDevice):InterfaceList;
-VAR
-	item: Interface;
-	interfaceList: InterfaceList;
-	interfaceListItem: InterfaceList;
-
-BEGIN
-	item := interfaces;
-	interfaceList := NIL;
-
-	(* search for interfaces with matching device and put them in a list *)
-	WHILE item # NIL DO
-		IF item.dev = dev THEN
-			NEW(interfaceListItem);
-			interfaceListItem.interface := item;
-			interfaceListItem.next := interfaceList;
-			interfaceList := interfaceListItem;
-		END;
-		item := item.next;
-	END;
-	RETURN interfaceList;
-END InterfaceListByDevice;
-
-
-(** Install a receiver for a type. The type is stored in
-	IPv4: Protocol field
-	IPv6: Next header field *)
-PROCEDURE InstallReceiver*( type: LONGINT; r: Receiver);
-BEGIN {EXCLUSIVE}
-	IF DEBUG THEN
-		ASSERT(r # NIL);
-		ASSERT((type >=0) & (type <= 255));
-		ASSERT(receivers[type] = NIL);
-	END;
-
-	receivers[type] := r;
-END InstallReceiver;
-
-
-(** Remove the currently installed receiver for a type. The type is stored in
-	IPv4: Protocol field
-	IPv6: Next header field *)
-PROCEDURE RemoveReceiver*(type: LONGINT);
-BEGIN {EXCLUSIVE}
-	ASSERT((type >=0) & (type <= 255));
-	ASSERT(receivers[type] # NIL);
-
-	receivers[type] := NIL;
-END RemoveReceiver;
-
-
-(** Checks if a string is a valid IPv4 address *)
-PROCEDURE IsValidIPv4Str (CONST ipString: ARRAY OF CHAR): BOOLEAN;
-VAR
-	i,j: LONGINT;
-	ipNr: LONGINT;
-	digits: ARRAY 4 OF CHAR;
-	startClass: LONGINT;
-BEGIN
-	i := 0;
-
-	(* Class A *)
-	WHILE (i < Strings.Length(ipString)) & (ipString[i] #'.') & (i < 3) DO
-		digits[i] := ipString[i];
-		INC (i);
-	END;
-	digits[i] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only numbers *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class B *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length(ipString)) & (ipString[i] # '.') & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class C *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length (ipString)) & (ipString[i] # '.') & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class D *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length (ipString)) & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	RETURN TRUE;
-END IsValidIPv4Str;
-
-
-(** Checks if a string is a valid IPv6 address *)
-PROCEDURE IsValidIPv6Str (ipString: ARRAY OF CHAR): BOOLEAN;
-VAR
-	i: LONGINT;
-	state: LONGINT; (* -1: error *)
-	charCount: LONGINT;
-	ascD: LONGINT;
-	ascH: LONGINT;
-	dPointOcc: BOOLEAN;
-	prefixLenArr: ARRAY 3 OF LONGINT;
-	prefixLen: LONGINT;
-
-BEGIN
-	i := 0;
-	state := 1;
-	dPointOcc := FALSE;
-
-	Strings.UpperCase(ipString);
-
-	WHILE (i < (LEN(ipString) - 1)) & (ipString[i] # 0X) DO
-
-		CASE state OF
-			-1:
-				RETURN FALSE;
-
-			|1:
-				(* 0-9 & A-F *)
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-
-					(* more than 4 digits between two : *)
-					IF charCount > 4 THEN
-						state := -1;
-					END;
-
-				(* : *)
-				ELSIF ipString[i] = ":" THEN
-					charCount := 0;
-					state := 2;
-				ELSIF ipString[i] = "/" THEN
-					charCount := 0;
-					state := 3;
-				ELSE
-					state := -1;
-				END;
-
-			|2:
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ipString[i] = ":" THEN
-					IF dPointOcc THEN
-						state := -1;
-					ELSE
-						dPointOcc := TRUE;
-						state := 4;
-					END
-
-				ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-					state := 1;
-				ELSE
-					state := -1;
-				END;
-
-			|3:
-				ascD := ORD(ipString[i]) - ORD("0");
-
-				IF ~((ascD >= 0) & (ascD <= 9)) THEN
-					state := -1;
-				ELSE
-					IF charCount > 3 THEN
-						state := -1;
-					ELSE
-						prefixLenArr[charCount] := ascD;
-						INC(charCount);
-					END;
-				END;
-
-			|4:
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ipString[i] = "/" THEN
-					state := 3;
-				ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-					state := 1;
-				ELSE
-					state := -1;
-				END;
-
-			ELSE
-				IF DEBUG THEN
-					ASSERT(TRUE);
-				END;
-		END;
-		INC(i);
-	END;
-
-	CASE state OF
-		1:
-			RETURN TRUE;
-
-		|3:
-			IF charCount > 0 THEN
-				prefixLen := 0;
-				FOR i:= 0 TO charCount - 1 DO
-					prefixLen := prefixLen * 10;
-					INC(prefixLen, prefixLenArr[i]);
-				END;
-				IF prefixLen <= 64 THEN
-					RETURN TRUE;
-				ELSE
-					RETURN FALSE;
-				END;
-			ELSE
-				RETURN FALSE;
-			END;
-
-		|4:
-			RETURN TRUE;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN FALSE;
-	END;
-	RETURN FALSE;
-END IsValidIPv6Str;
-
-
-(** Set IPv6 address to zero *)
-PROCEDURE SetIPv6AdrNil (adr: Adr);
-VAR
-	i: LONGINT;
-
-BEGIN
-	FOR i := 0 TO 15 DO
-		adr.ipv6Adr[i] := 0X;
-	END;
-END SetIPv6AdrNil;
-
-
-(* Add the interface to the IP configuration. *)
-PROCEDURE AddInterface*(int: Interface; VAR res: WORD);
-VAR
-	item: Interface;
-BEGIN {EXCLUSIVE}
-	item := interfaces;
-	WHILE item # NIL DO
-		(* Check if interface name already exists *)
-		IF item.name = int.name THEN
-			res := DuplicateInterfaceName;
-			RETURN;
-		END;
-		item := item.next;
-	END;
-	(* Add interface *)
-	int.next := interfaces;
-	interfaces := int;
-	res := Ok;
-END AddInterface;
-
-
-(* Remove the interface from the IP configuration. *)
-PROCEDURE RemoveInterface*(int: Interface);
-VAR
-	item: Interface;
-
-BEGIN {EXCLUSIVE}
-	item := interfaces;
-	IF item = NIL THEN
-		(* empty list *)
-	ELSIF item = int THEN
-		(* remove first item *)
-		interfaces := interfaces.next;
-	ELSE
-		WHILE item.next # int DO
-			item := item.next;
-		END;
-		IF item.next # NIL THEN
-			item.next := item.next.next;
-		ELSE
-			(* not found *)
-		END;
-	END;
-END RemoveInterface;
-
-
-(* Prints out a packet *)
-PROCEDURE PacketOut*(CONST title, buffer: ARRAY OF CHAR; all: BOOLEAN);
-VAR
-	i: LONGINT;
-	length: LONGINT;
-
-BEGIN
-	KernelLog.Ln;KernelLog.String("********************");KernelLog.Ln;
-	KernelLog.String(title); KernelLog.Ln;
-
-	IF all THEN
-		length := LEN(buffer) -1;
-	ELSE
-		length := Strings.Min(LEN(buffer) - 1, 256);
-	END;
-
-	FOR i := 0 TO length DO
-		IF (i MOD 4) = 0 THEN
-			KernelLog.Ln;
-			KernelLog.Int(i, 2);KernelLog.String(":  ");
-		END;
-		KernelLog.Hex(ORD(buffer[i]), -1);
-		KernelLog.String(" ");
-	END;
-
-	KernelLog.Ln;KernelLog.String("********************");KernelLog.Ln;
-END PacketOut;
-
-
-BEGIN
-	(* IPFowarding default value is FALSE *)
-	IPForwarding := FALSE;
-
-	(* EchoReply default value is TRUE *)
-	EchoReply := TRUE;
-
-	(* Initializations *)
-	(* NilAdr *)
-	NilAdr.ipv4Adr := NilAdrIPv4;
-	SetIPv6AdrNil (NilAdr);
-	NilAdr.usedProtocol := NilAdrIdent;
-
-	(* Initialize receiver list *)
-	FOR counter:=0 TO NbrOfReceivers-1 DO
-		receivers[counter] := NIL;
-	END;
-
-	(* Initialize inteface list *)
-	interfaces := NIL;
-END IP.
-
-
-
-Free:
-System.Free TraceRoute VNC Ping WMFTPClient FTPClient WebFTPServer TCPServices TLS InitNetwork Ping DHCP TCP DNS UDP ICMP IPv4 IPv6 IP~
-
-Start:
-InitNetwork.Init
-
-Compile:
-PC.Compile \s IP.Mod IPv4.Mod IPv6.Mod ICMP.Mod UDP.Mod DNS.Mod TCP.Mod DHCP.Mod InitNetwork.Mod WebFTPServer.Mod FTPClient.Mod WMFTPClient.Mod Ping.Mod VNC.Mod TraceRoute.Mod~
-
-
-
-History:
-02.05.2005	eb	Supports IPv6 and fragmented IPv6 packets.
-
-
-
-
-IsValidIPv6Str:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
-
-FSM used in IsValidIPv6Str:
------------------------
-EOS: end of string
-	State 1: Initial state
-			0-9/A-F goto state 1
-			: goto state 2
-			/ goto state 3
-			EOS valid
-	State 2:	0-9/A-F goto state 1
-			: goto state 4
-			EOS invalid
-	State 3:	0-9 goto state 3
-			EOS valid
-	State 4:	/ goto state 3
-			0-9/A-F goto state 1
-			EOS valid
-
-			

+ 0 - 1620
source/I386.IP.Mod

@@ -1,1620 +0,0 @@
-(* Aos, Copyright 2001, Pieter Muller, ETH Zurich *)
-
-MODULE IP; (** AUTHOR "pjm, mvt, eb"; PURPOSE "IP (v4 and v6)"; *)
-
-IMPORT SYSTEM, KernelLog, Commands, Strings, Network;
-
-CONST
-	(* DEBUG *)
-	DEBUG = TRUE;
-
-	(** Error codes *)
-	Ok* = 0;
-	DeviceAlreadyUsed* = 3901;
-	DuplicateInterfaceName* = 3902;
-	NoInterfaceName* = 3903;
-	GatewayNotInSubnet* = 3904;
-	IPv6AdrUsedOnIPv4Interface* = 4001;
-	IPv4AdrUsedOnIPv6Interface* = 4002;
-	DublicatedAddresses* = 4003;
-	MixedIpProtocols* = 4003;
-	LocalAdrSetIntv6* = 4004;   (* local address must be NIL when calling SetAdrs on a IPv6 interface *)
-	PrefixNotSet* = 4005; (* prefix on ipv6 interface must be set with local address *)
-
-	MaxNofDNS* = 10; (** maximum number of DNS servers per interface *)
-	MaxTTL* = 255; (** maximum time-to-live on outgoing datagrams *)
-
-	NbrOfReceivers = 255; (* Number of possible receivers, i.e. possible layer 3 protocols *)
-
-	(** IP address constants *)
-	NilAdrIPv4 = 0;
-
-	(* Comparators for Adr.usedProtocols *)
-	IPv4* = 4;
-	IPv6* = 6;
-	NilAdrIdent = -1;	(* usedProtocol of NilAdrs *)
-
-	(* ICMP *)
-	ICMPHdrLen* = 4;
-	ICMPSrcLLAdrOptionType* = 1;
-	ICMPTargetLLAdrOptionType* = 2;
-	ICMPPrefixInfoOptionType* = 3;
-	ICMPRedirectHdrOptionType* = 4;
-	ICMPMTUOptionType* = 5;
-	ICMPAdvIntOptionType* = 7;
-	ICMPHomeAgOptionType* = 8;
-	ICMPRouteOption* = 9;
-
-
-TYPE
-	Adr* = RECORD
-		ipv4Adr*: LONGINT;
-		ipv6Adr*: ARRAY 16 OF CHAR;
-		usedProtocol*: LONGINT;
-		data*: LONGINT;
-	END; (** An IP Address.	usedProtocol = 0: No protocol yet used
-							usedProtocol = IPv4: IPv4 address stored in field ipv4Adr
-							usedProtocol = IPv6: IPv6 address stored in field ipv6Adr
-							data can be used to store additional informations. I.e. in IPv6 the
-							prefix length is stored in the data field *)
-
-TYPE
-	Packet* = POINTER TO ARRAY OF CHAR;
-
-	Name* = ARRAY 128 OF CHAR; (** Name type for interface name *)
-
-	Interface* = OBJECT
-	VAR
-		(** IP addresses of this interface. *)
-		localAdr*, maskAdr*, gatewayAdr*, subnetAdr*, broadAdr*: Adr;
-
-		(** name of the interface *)
-		name*: Name;
-
-		(** Device that the interface belongs to *)
-		dev*: Network.LinkDevice;
-
-		(** DNS server list - can be used by DNS, not used in IP itself *)
-		DNS-: ARRAY MaxNofDNS OF Adr; (* DNS server list *)
-		DNScount*: LONGINT; (* number of DNS servers in list *)
-
-		(* interface *)
-		next*: Interface; (* next pointer for interface list *)
-		closed*: BOOLEAN; (* is interface already closed? *)
-		protocol*: LONGINT; (* Interface for IPv4 or IPv6?. Only used by IP otherwise use dynamic type checking! *)
-
-
-		(** Set addresses. Is normally called just after instanciation, but can also be called later, e.g. by DHCP.
-			If "gatewayAdr" is "NilAdr", the subnet is considered to have no gateway, else it must be in the same
-			subnet as the "localAdr".
-			"domain" can be an empty string. It is normally used by a DNS implementation. It is not used in IP directly.
-			In IPv6 maskAdr is the prefix of the currently IP address *)
-		PROCEDURE SetAdrs*(localAdr, maskOrPrefixAdr, gatewayAdr: Adr; VAR res: WORD);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END SetAdrs;
-
-
-		(** Remove all domain name servers from the interface. *)
-		PROCEDURE DNSRemoveAll*;
-		BEGIN {EXCLUSIVE}
-			DNScount := 0;
-		END DNSRemoveAll;
-
-
-		(** Add a domain name server to the interface. *)
-		PROCEDURE DNSAdd*(adr: Adr);
-		VAR
-			i: LONGINT;
-
-		BEGIN {EXCLUSIVE}
-			(* concurrent lookup is consistent *)
-			ASSERT(DNScount < MaxNofDNS);
-
-			i := 0;
-			WHILE i < DNScount DO
-				IF AdrsEqual (DNS[i],adr) THEN RETURN END;
-				INC(i)
-			END;
-			DNS[DNScount] := adr;
-			INC(DNScount);
-		END DNSAdd;
-
-
-		(** Remove a domain name server from the interface. *)
-		PROCEDURE DNSRemove*(adr: Adr);
-		VAR i: LONGINT;
-		BEGIN {EXCLUSIVE}
-			(* concurrent lookup could result in a duplicate address in worst-case *)
-			(* this happends hardly ever and is harmless for DNS anyway *)
-			i := 0;
-			WHILE (i < DNScount) & (~ AdrsEqual(DNS[i],adr)) DO
-				INC(i)
-			END;
-			IF i < DNScount THEN
-				INC(i);
-				WHILE i < DNScount DO
-					DNS[i-1] := DNS[i];
-					INC(i);
-				END;
-				DEC(DNScount);
-			END;
-		END DNSRemove;
-
-
-		(** Send an IP packet on this interface. *)
-		PROCEDURE Send*(type: LONGINT; destAdr: Adr; CONST l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, TTL: LONGINT);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END Send;
-
-
-		(* Internal procedure to perform the rest of the send operation. Used by "Send" and for IP forwarding. *)
-		PROCEDURE DoSend*(destAdr: Adr; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT) ;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END DoSend;
-
-
-		(** Enumerate all ARP table entries. *)
-		PROCEDURE ARPEnumerate*(handle: ARPHandler);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ARPEnumerate;
-
-
-		(** Close and deactivate the interface, i.e. remove it from the configuration. *)
-		PROCEDURE Close*;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END Close;
-
-
-		(** Check if adr is a broadcast address *)
-		PROCEDURE IsBroadcast*(adr: Adr) : BOOLEAN;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IsBroadcast;
-
-
-		(** Check if adr is a multicast address *)
-		PROCEDURE IsMulticast*(adr: Adr) : BOOLEAN;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IsMulticast;
-
-
-		(** Receive an IP packet *)
-		PROCEDURE IPInput*(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END IPInput;
-
-
-		(** Reads the source address of a IP packet buffer *)
-		PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): Adr;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ReadSrcAdr;
-
-
-		(** Reads the destination address of a IP packet buffer *)
-		PROCEDURE ReadDestAdr* (buffer: Network.Buffer): Adr;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END ReadDestAdr;
-
-
-		(** Creates a pseudo-header for checksum calculation (TCP/UDP) and returns the length of this header *)
-		PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR;  src, dst: Adr; protocol, pktLengthUpperLayer: LONGINT): LONGINT;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END WritePseudoHeader;
-
-
-		(** Writes the configuration of this interface *)
-		PROCEDURE OutInterface*;
-		BEGIN
-			(* Extensions have to override this method.*)
-			HALT(99);
-		END OutInterface;
-
-	END Interface;
-
-
-TYPE
-	(* List of interfaces *)
-	InterfaceList* = POINTER TO RECORD
-		interface*: Interface;
-		next*: InterfaceList;
-	END;
-
-	Receiver* = PROCEDURE {DELEGATE} (int: Interface; type: LONGINT; fip, lip: Adr; buffer: Network.Buffer);
-	V6InterfaceByDstIP* = PROCEDURE {DELEGATE} (dstAdr: Adr): Interface;
-
-	(** Handler for ARPPool.Enumerate. *)
-	ARPHandler* = PROCEDURE {DELEGATE} (ip: Adr; complete: BOOLEAN; link: Network.LinkAdr; size, sendTime, updateTime, updateDate, hash: LONGINT);
-
-	InterfaceHandler* = PROCEDURE {DELEGATE} (int: Interface);
-
-
-VAR
-	(* receiver *)
-	receivers*: ARRAY 256 OF Receiver; (* registered receivers - array position is IPv4 protocol field or IPv6 next header field *)
-
-	(* Interface by dst for IPv6 *)
-	v6InterfaceByDstIP*: V6InterfaceByDstIP;
-
-	(* IP *)
-	NilAdr*: Adr; (* To check if an IP address is NIL use IsNilAdr instead *)
-	preferredProtocol*: LONGINT;	(* Preferred IP protocol *)
-
-	(* IP counters *)
-	NIPSentToSubnet*, NIPSentToGateway*, NIPSentBroadcast*, NIPCantFragment*,
-	NIPRcvTotal*, NIPTooSmall*, NIPBadVersion*, NIPOptions*, NIPBadChecksum*,
-	NIPBadLength*, NIPTrim*, NIPBadHdrLen*, NIPNotForUs*, NIPCantReassemble*, NIPSrcIsBroadcast*,
-	NIPDelivered*, NIPNoReceiver*, NIPForwarded*, NIPSentLocalLoopback*, NIPSentPointToPoint*: LONGINT;
-
-	(* turn on/off IP forwarding, echo replay *)
-	IPForwarding*: BOOLEAN;
-	EchoReply*: BOOLEAN;
-
-	(* Interface *)
-	interfaces*: Interface; (* list of all installed interfaces *)
-
-	counter: LONGINT; (* Use it only in the module body! *)
-
-
-(** Is address not yet specified *)
-PROCEDURE IsNilAdr* (adr: Adr): BOOLEAN;
-VAR
-	isNil: BOOLEAN;
-	i: LONGINT;
-
-BEGIN
-	CASE adr.usedProtocol OF
-		IPv4:
-			RETURN (adr.ipv4Adr = NilAdrIPv4)
-
-		|IPv6:
-			isNil := TRUE;
-			i := 0;
-			WHILE ((i<16) & isNil) DO
-				IF adr.ipv6Adr[i] # 0X THEN
-					isNil := FALSE;
-				END;
-				INC(i);
-			END;
-			RETURN isNil;
-
-		|NilAdrIdent:
-			RETURN TRUE;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN TRUE;
-	END;
-END IsNilAdr;
-
-
-(* Checks if two addresses are equal *)
-PROCEDURE AdrsEqual* (adr1, adr2: Adr): BOOLEAN;
-VAR
-	equal: BOOLEAN;
-	i: LONGINT;
-
-BEGIN
-	IF adr1.usedProtocol # adr2.usedProtocol THEN
-		RETURN FALSE;
-	END;
-
-	CASE adr1.usedProtocol OF
-		IPv4:
-			IF adr1.ipv4Adr = adr2.ipv4Adr THEN
-				RETURN TRUE;
-			END;
-
-		|IPv6:
-			equal := TRUE;
-			i := 0;
-			WHILE ((i < 16) & equal) DO
-				IF adr1.ipv6Adr[i] # adr2.ipv6Adr[i] THEN
-					equal := FALSE;
-				END;
-				INC(i);
-			END;
-
-			IF adr1.data # adr2.data THEN
-				equal := FALSE;
-			END;
-
-			RETURN equal;
-
-		|NilAdrIdent:
-			(* both addresses NIL therefore equal *)
-			IF adr2.usedProtocol = NilAdrIdent THEN
-				RETURN TRUE;
-			ELSE
-				RETURN FALSE;
-			END;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN FALSE;
-	END;
-	RETURN FALSE;
-END AdrsEqual;
-
-
-(** Convert a dotted-decimal string to an ip address. Return NilAdr on failure. *)
-PROCEDURE StrToAdr*(ipString: ARRAY OF CHAR): Adr;
-VAR
-	retAdr: Adr;
-	i, j, x: LONGINT;
-	adr: ARRAY 4 OF CHAR;
-	ok: BOOLEAN;
-	charCount: LONGINT;				(* ipv6: number of character between two : *)
-	ipv6AdrPart: ARRAY 6 OF CHAR;		(* two bytes of an IPv6 address *)
-	ipv6AdrRight: ARRAY 16 OF CHAR;	(* right part of an IPv6 address; after :: *)
-	hexToChar: ARRAY 3 OF CHAR;
-	leftParts: LONGINT;					(* number of bytes before :: *)
-	rightParts: LONGINT;				(* number of bytes after :: *)
-	val, res: LONGINT;
-	state: LONGINT;						(* state of the FSM look at the eof for more info *)
-	dPointOcc: BOOLEAN;				(* double point occured *)
-	prefixVal: LONGINT;
-
-
-	(* compute a subpart (two bytes) of a IPv6 address; subpart:=between two : *)
-	PROCEDURE ComputeIPv6Part():BOOLEAN;
-	BEGIN
-		CASE charCount OF
-			0:
-				RETURN TRUE;
-
-			|1,2:
-				IF dPointOcc THEN
-					ipv6AdrRight[rightParts] := 0X;
-					INC(rightParts);
-				ELSE
-					retAdr.ipv6Adr[leftParts] := 0X;
-					INC(leftParts);
-				END;
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			|3:
-				hexToChar[0] := ipv6AdrPart[0];
-				hexToChar[1] := 0X;
-				Strings.HexStrToInt(hexToChar, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-				ipv6AdrPart[0] := "0";
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			|4:
-				hexToChar[0] := ipv6AdrPart[0];
-				hexToChar[1] := ipv6AdrPart[1];
-				hexToChar[2] := 0X;
-				Strings.HexStrToInt(hexToChar, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-				ipv6AdrPart[0] := "0";
-				ipv6AdrPart[1] := "0";
-				Strings.HexStrToInt(ipv6AdrPart, val, res);
-
-				IF res = Strings.Ok THEN
-					IF dPointOcc THEN
-						ipv6AdrRight[rightParts] := CHR(val);
-						INC(rightParts);
-					ELSE
-						retAdr.ipv6Adr[leftParts] := CHR(val);
-						INC(leftParts);
-					END;
-				ELSE
-					RETURN FALSE;
-				END;
-
-			ELSE
-				IF DEBUG THEN
-					ASSERT(TRUE);
-				END;
-				RETURN FALSE;
-		END;
-		charCount := 0;
-		RETURN TRUE;
-	END ComputeIPv6Part;
-
-
-BEGIN
-	retAdr := NilAdr;
-
-	IF IsValidIPv4Str(ipString) THEN
-		(* Return an ipv4 address *)
-		i := 0;
-		j := 0;
-		x := -1;
-		ok := FALSE;
-
-		LOOP
-			IF (ipString[i] = ".") OR (ipString[i] = 0X) THEN
-				IF (x < 0) OR (x > 255) OR (j = 4) THEN EXIT END;
-				adr[j] := CHR(x);
-				IF ipString[i] = 0X THEN ok := (j = 3); EXIT END;
-				x := -1; INC(i); INC(j)
-			ELSIF (ipString[i] >= "0") & (ipString[i] <= "9") THEN
-				IF x = -1 THEN x := 0 END;
-				x := x*10 + (ORD(ipString[i])-ORD("0"));
-				INC(i)
-			ELSE
-				EXIT
-			END
-		END;
-
-		IF ok THEN
-			retAdr.ipv4Adr := SYSTEM.VAL (LONGINT, adr);
-			retAdr.usedProtocol := IPv4;
-			RETURN retAdr;
-		ELSE
-			RETURN NilAdr;
-		END
-
-
-	(* IPv6 *)
-	ELSIF IsValidIPv6Str(ipString) THEN
-		i := 0;
-		state := 1;
-		charCount := 0;
-		dPointOcc := FALSE;
-		retAdr.usedProtocol := 6;
-		retAdr.ipv4Adr := NilAdrIPv4;
-		i := 0;
-		j := 0;
-		charCount := 0;
-		leftParts := 0;
-		rightParts := 0;
-		prefixVal := 0;
-
-		Strings.UpperCase(ipString);
-
-		WHILE (i < (LEN(ipString) - 1)) & (ipString[i] # 0X) DO
-
-			CASE state OF  (* Using the same FSM as IsValidIPv6Str *)
-				-1:	(* Error state
-					    Should never happen, is checked by IsValidIPv6Str() *)
-					RETURN NilAdr;
-
-				|1:	(* reading two blocks of two bytes of 0-9\A-F *)
-					IF ipString[i] = ":" THEN
-						ipv6AdrPart[charCount] := 0X;
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-						state := 2;
-
-					ELSIF ipString[i] = "/" THEN
-						ipv6AdrPart[charCount] := 0X;
-
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-						state := 3;
-
-					ELSE
-						(* 0-9, A-F *)
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-
-				|2:	(* a : occured *)
-					IF ipString[i] = ":" THEN
-						dPointOcc := TRUE;
-						state := 4;
-					ELSE
-						(* 0-9, A-F *)
-						state := 1;
-						charCount := 0;
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-
-				|3:	(* prefix will follow *)
-					prefixVal := (prefixVal * 10) + (ORD(ipString[i]) - ORD("0"));
-
-				|4:	(* A :: occured *)
-					IF ipString[i] = "/" THEN
-						state := 3;
-					ELSE
-						IF ~ComputeIPv6Part() THEN
-							RETURN NilAdr;
-						END;
-
-						(* 0-9, A-F *)
-						state := 1;
-						charCount := 0;
-						ipv6AdrPart[charCount] := ipString[i];
-						INC(charCount);
-					END;
-				ELSE
-					IF DEBUG THEN
-						ASSERT(TRUE);
-					END;
-			END;
-			INC(i);
-		END;
-
-		ipv6AdrPart[charCount] := 0X;
-		IF charCount # 0 THEN
-			IF ~ComputeIPv6Part() THEN
-				RETURN NilAdr;
-			END;
-		END;
-
-		IF dPointOcc THEN
-			(* fill 0X for :: *)
-			FOR i:= leftParts TO ((LEN(retAdr.ipv6Adr) -1) - rightParts) DO
-				retAdr.ipv6Adr[i] := 0X;
-			END;
-
-			(* fill part behind :: *)
-			FOR i := 0 TO (rightParts - 1) DO
-				retAdr.ipv6Adr[(LEN(retAdr.ipv6Adr) - rightParts) + i] := ipv6AdrRight[i];
-			END;
-		END;
-
-		IF prefixVal > 64 THEN
-			RETURN NilAdr;
-		END;
-		retAdr.data := prefixVal;
-		RETURN retAdr;
-	END;
-	RETURN NilAdr;
-END StrToAdr;
-
-
-(** Convert an IP address to a dotted-decimal string. *)
-PROCEDURE AdrToStr*(adr: Adr; VAR string: ARRAY OF CHAR);
-VAR
-	i, j, x: LONGINT;
-	a: ARRAY 4 OF CHAR;
-	val: LONGINT;
-	hexToStr: ARRAY 5 OF CHAR;
-	prefixLenStr: ARRAY 64 OF CHAR;
-	maxZeroRow: LONGINT;
-	currentZeroRow: LONGINT;
-	maxZeroStart: LONGINT;
-	currentZeroStart: LONGINT;
-	lastZero: BOOLEAN;
-	lastDPoint: BOOLEAN;
-	countEnded: BOOLEAN;
-
-BEGIN
-	CASE adr.usedProtocol OF
-		IPv4:
-			ASSERT(LEN(string) >= 16);	(* enough space for largest result *)
-			Network.Put4(a, 0, adr.ipv4Adr);
-			i := 0;
-			FOR j := 0 TO 3 DO
-				x := ORD(a[j]);
-				IF x >= 100 THEN string[i] := CHR(ORD("0")+x DIV 100); INC(i) END;
-				IF x >= 10 THEN string[i] := CHR(ORD("0")+x DIV 10 MOD 10); INC(i) END;
-				string[i] := CHR(ORD("0")+x MOD 10); INC(i);
-				IF j = 3 THEN string[i] := 0X ELSE string[i] := "." END;
-				INC(i)
-			END
-
-		|IPv6:
-			FOR i := 0 TO (LEN(adr.ipv6Adr) -1) BY 2 DO
-				(* simple version *)
-				val :=  ORD(adr.ipv6Adr[i]) * 256;
-				val := val + ORD(adr.ipv6Adr[i+1]);
-				Strings.IntToHexStr (val, 3, hexToStr);
-
-				(* Delete leading zeros *)
-				WHILE (hexToStr[0] = "0") & (hexToStr[1] # 0X) DO
-					Strings.Delete(hexToStr, 0, 1);
-				END;
-				Strings.Append (string, hexToStr);
-
-				IF i # (LEN(adr.ipv6Adr) - 2) THEN
-					Strings.Append (string, ":");
-				END;
-			END;
-
-			(* replace longest row of zeros with :: *)
-			maxZeroRow := 0;
-			currentZeroRow := 0;
-			maxZeroStart := 0;
-			currentZeroStart := 0;
-			i := 0;
-			lastZero := FALSE;
-			lastDPoint := TRUE;
-			countEnded :=TRUE;
-
-			WHILE string[i] # 0X DO
-				IF string[i] = "0" THEN
-					IF lastDPoint THEN
-						INC(currentZeroRow);
-						lastZero := TRUE;
-						lastDPoint := FALSE;
-						IF countEnded THEN
-							currentZeroStart := i;
-							countEnded := FALSE;
-						END;
-					END;
-				ELSIF string[i] = ":" THEN
-					lastDPoint := TRUE;
-					IF lastZero THEN
-						lastZero := FALSE;
-					END;
-				ELSE
-					IF lastDPoint THEN
-						lastDPoint := FALSE;
-						countEnded := TRUE;
-						IF currentZeroRow > maxZeroRow THEN
-							maxZeroRow := currentZeroRow;
-							maxZeroStart := currentZeroStart;
-						END;
-					END;
-				END;
-
-				INC(i);
-			END;
-
-			IF ~countEnded THEN
-				IF currentZeroRow > maxZeroRow THEN
-					maxZeroRow := currentZeroRow;
-					maxZeroStart := currentZeroStart;
-				END;
-			END;
-			IF maxZeroRow # 0 THEN
-				(* write a :: *)
-				IF maxZeroStart = 0 THEN
-					string[0] := ":";
-					i := 1;
-					WHILE ((string[i] # 0X) & ~((string[i] # "0") & (string[i] # ":"))) DO INC(i); END;
-					IF string[i] = 0X THEN
-						string := "::";
-					ELSE
-						Strings.Delete(string, 1, i-2);
-					END;
-				ELSE
-					i := maxZeroStart;
-					WHILE ((string[i] = "0") OR (string[i] = ":")) DO INC(i); END;
-					IF string[i] = 0X THEN
-						string[maxZeroStart] := ":";
-						string[maxZeroStart+1] := 0X;
-					ELSE
-						Strings.Delete(string, maxZeroStart, i - maxZeroStart - 1);
-					END;
-				END;
-			END;
-
-			IF adr.data # 0 THEN
-				(* write prefix *)
-				Strings.IntToStr(adr.data, prefixLenStr);
-				Strings.Append (string, "/");
-				Strings.Append (string, prefixLenStr);
-			END;
-
-		ELSE
-			IF IsNilAdr (adr) THEN
-				string := "";
-			END;
-	END;
-END AdrToStr;
-
-
-(** Convert a IP address from an array [ofs..ofs+x] to an
-	Adr-type variable.
-	Example for IPv4:
-	If the LSB (least significant byte) is stored the the beginning [ofs],
-	LSBfirst must be set to TRUE.
-		(address "a.b.c.d" is stored as [d,c,b,a])
-	If the LSB is stored at the end [ofs+3], LSBfirst must be set to FALSE.
-		(address "a.b.c.d" is stored as [a,b,c,d])
-*)
-PROCEDURE ArrayToAdr*(CONST array: ARRAY OF CHAR; ofs, protocol: LONGINT; LSBfirst: BOOLEAN): Adr;
-VAR
-	adr: Adr;
-	i, swapTemp: LONGINT;
-BEGIN
-	ASSERT((protocol = 4) OR (protocol = 6));
-
-	IF protocol = IPv4 THEN  (* index check *)
-		IF ~(ofs + 4 <= LEN(array)) THEN
-			RETURN NilAdr;
-		END;
-
-		SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv4Adr), 4);
-		IF LSBfirst THEN
-			SwapEndian(adr.ipv4Adr);
-		END;
-		adr.usedProtocol := IPv4;
-
-	ELSIF protocol = IPv6 THEN
-		IF ~(ofs + 16 <= LEN(array)) THEN
-			RETURN NilAdr;
-		END;
-
-		SYSTEM.MOVE(ADDRESSOF(array[ofs]), ADDRESSOF(adr.ipv6Adr), 16);
-		IF LSBfirst THEN
-			FOR i := 0 TO 3 DO
-				SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
-				SwapEndian(swapTemp);
-				SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(adr.ipv6Adr[i*4]), 4);
-			END;
-		END;
-		adr.usedProtocol := IPv6;
-
-	ELSE
-		IF DEBUG THEN
-			ASSERT(TRUE);
-		END;
-		RETURN NilAdr;
-	END;
-	RETURN adr;
-END ArrayToAdr;
-
-
-(** Convert an Adr-type variable  into an array [ofs..ofs+x]
-	Example in IPv4:
-	If the LSB (least significant byte) should be stored the the
-	beginning [ofs], LSBfirst must be set to TRUE.
-		(address "a.b.c.d" is stored as [d,c,b,a])
-	If the LSB should be stored at the end [ofs+3], LSBfirst must be set to FALSE.
-		(address "a.b.c.d" is stored as [a,b,c,d])
-*)
-PROCEDURE AdrToArray*(adr: Adr; VAR array: ARRAY OF CHAR; ofs: LONGINT; LSBfirst: BOOLEAN);
-VAR
-	tempAdr: Adr;
-	i, swapTemp: LONGINT;
-
-BEGIN
-	tempAdr := adr;
-
-	CASE adr.usedProtocol OF
-		IPv4:
-			IF ~(ofs+4 <= LEN(array)) THEN
-				tempAdr := NilAdr;
-			END;
-
-			IF LSBfirst THEN
-				SwapEndian(tempAdr.ipv4Adr);
-			END;
-			SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv4Adr), ADDRESSOF(array[ofs]), 4);
-
-		| IPv6:
-			IF ~(ofs + 16 <= LEN(array)) THEN
-				tempAdr := NilAdr;
-			END;
-
-			IF LSBfirst THEN
-				FOR i := 0 TO 3 DO
-					SYSTEM.MOVE(ADDRESSOF(tempAdr.ipv6Adr[i*4]), ADDRESSOF(swapTemp), 4);
-					SwapEndian(swapTemp);
-					SYSTEM.MOVE(ADDRESSOF(swapTemp), ADDRESSOF(tempAdr.ipv6Adr[i*4]), 4);
-				END;
-			END;
-			SYSTEM.MOVE(ADDRESSOF(adr.ipv6Adr), ADDRESSOF(array[ofs]), 16);
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-	END;
-END AdrToArray;
-
-
-(** Reads the IP source address from a buffer *)
-PROCEDURE SrcAdrFromBuffer* (buffer: Network.Buffer): Adr;
-VAR
-	i: LONGINT;
-	adr: Adr;
-
-BEGIN
-	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
-		IPv4:
-			adr.usedProtocol := IPv4;
-			adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+12]);
-			SetIPv6AdrNil(adr);
-			RETURN adr;
-
-		|IPv6:
-			adr.usedProtocol := IPv6;
-			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+8 + i];
-			END;
-			adr.ipv4Adr := NilAdrIPv4;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NilAdr;
-	END;
-	RETURN NilAdr;
-END SrcAdrFromBuffer;
-
-
-(** Reads the IP destination address from a buffer *)
-PROCEDURE DestAdrFromBuffer* (buffer: Network.Buffer): Adr;
-VAR
-	adr: Adr;
-	i: LONGINT;
-
-BEGIN
-	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
-		IPv4:
-			adr.usedProtocol := IPv4;
-			adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+16]);
-			SetIPv6AdrNil(adr);
-			RETURN adr;
-
-		|IPv6:
-			adr.usedProtocol := IPv6;
-			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+24 + i];
-			END;
-			adr.ipv4Adr := NilAdrIPv4;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NilAdr;
-	END;
-	RETURN NilAdr;
-END DestAdrFromBuffer;
-
-
-(* Swap internal representation of an IP address from big to little endian or vice versa. *)
-PROCEDURE -SwapEndian(VAR adr: LONGINT);
-CODE {SYSTEM.i386}
-	POP EAX
-	MOV ECX, [EAX]
-	XCHG CL, CH
-	ROL ECX, 16
-	XCHG CL, CH
-	MOV [EAX], ECX
-END SwapEndian;
-
-
-(** Write an IP address. *)
-PROCEDURE OutAdr*(adr: Adr);
-VAR
-	s: ARRAY 64 OF CHAR;
-
-BEGIN
-	AdrToStr(adr, s); KernelLog.String(s);
-END OutAdr;
-
-
-(** Enumerate all installed interfaces *)
-PROCEDURE Enumerate*(handler: InterfaceHandler);
-VAR item: Interface;
-BEGIN
-	item := interfaces;
-	WHILE item # NIL DO
-		handler(item);
-		item := item.next;
-	END;
-END Enumerate;
-
-
-(** Output the configuration of the specified interface. Can be used as Handler in Enumerate(). *)
-PROCEDURE OutInterface*(interface: Interface);
-BEGIN
-	interface.OutInterface;
-END OutInterface;
-
-
-(** Aos command: Output statistics and configuration of all installed interfaces. *)
-PROCEDURE IPConfig*(context : Commands.Context);
-BEGIN
-	context.out.String("Interfaces:"); context.out.Ln;
-	context.out.String("----------------------"); context.out.Ln;
-	Enumerate(OutInterface);
-	context.out.Ln;
-	context.out.String("IP statistics:"); context.out.Ln;
-	context.out.String("----------------------"); context.out.Ln;
-	context.out.String("NIPSentToSubnet"); context.out.Int(NIPSentToSubnet,10);context.out.Ln;
-	context.out.String("NIPSentToGateway"); context.out.Int(NIPSentToGateway,10);context.out.Ln;
-	context.out.String("NIPSentBroadcast"); context.out.Int(NIPSentBroadcast,10);context.out.Ln;
-	context.out.String("NIPCantFragment"); context.out.Int(NIPCantFragment,10);context.out.Ln;
-	context.out.String("NIPRcvTotal"); context.out.Int(NIPRcvTotal,10);context.out.Ln;
-	context.out.String("NIPTooSmall"); context.out.Int(NIPTooSmall,10);context.out.Ln;
-	context.out.String("NIPBadVersion"); context.out.Int(NIPBadVersion,10);context.out.Ln;
-	context.out.String("NIPOptions"); context.out.Int(NIPOptions,10);context.out.Ln;
-	context.out.String("NIPBadChecksum"); context.out.Int(NIPBadChecksum,10);context.out.Ln;
-	context.out.String("NIPBadLength"); context.out.Int(NIPBadLength,10);context.out.Ln;
-	context.out.String("NIPTrim"); context.out.Int(NIPTrim, 10);context.out.Ln;
-	context.out.String("NIPBadHdrLen"); context.out.Int(NIPBadHdrLen,10);context.out.Ln;
-	context.out.String("NIPNotForUs"); context.out.Int(NIPNotForUs,10);context.out.Ln;
-	context.out.String("NIPCantReassemble"); context.out.Int(NIPCantReassemble,10);context.out.Ln;
-	context.out.String("NIPSrcIsBroadcast"); context.out.Int(NIPSrcIsBroadcast,10);context.out.Ln;
-	context.out.String("NIPDelivered"); context.out.Int(NIPDelivered,10);context.out.Ln;
-	context.out.String("NIPNoReceiver"); context.out.Int(NIPNoReceiver,10);context.out.Ln;
-	context.out.String("NIPForwarded"); context.out.Int(NIPForwarded,10);context.out.Ln;
-	context.out.String("NIPSentLocalLoopback"); context.out.Int(NIPSentLocalLoopback,10);context.out.Ln;
-	context.out.String("NIPSentPointToPoint"); context.out.Int(NIPSentPointToPoint,10);context.out.Ln; context.out.Ln;
-END IPConfig;
-
-
-(** 	First part of a split checksum operation. len must be non-zero and even. chk1 must be 0 at the
-	beginning. The result can be passed to a following call to Checksum1(). The last chk1 result must
-	be passed to Checksum2, which sums the data following sequentially on the data summed by this
-	operation. Carries from bit 15 are accumulated in the top 16 bits, so at most 65535 words can be
-	summed by Checksum1 and Checksum2 together. *)
-PROCEDURE Checksum1*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): LONGINT;
-CODE {SYSTEM.i386}
-	MOV EAX, [EBP+chk1]
-	MOV EBX, [EBP+data]
-	ADD EBX, [EBP+ofs]
-	MOV ECX, [EBP+len]
-	SHR ECX, 1
-	JNC sloop
-	PUSH 8	; ASSERT(~ODD(len))
-	INT 3
-sloop:
-	MOVZX EDX, WORD [EBX]
-	ADD EAX, EDX
-	ADD EBX, 2
-	DEC ECX
-	JNZ sloop
-END Checksum1;
-
-
-(** 	Continue a checksum operation. len can be zero or odd. chk1 can be the result of Checksum1 for
-	the immediately preceding data, or 0 for contiguous data. *)
-PROCEDURE Checksum2*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): INTEGER;
-	CODE {SYSTEM.i386}
-	MOV EAX, [EBP+chk1]
-	MOV EBX, [EBP+data]
-	ADD EBX, [EBP+ofs]
-	MOV ECX, [EBP+len]
-	SHR ECX, 1
-	JZ eloop
-sloop:
-	MOVZX EDX, WORD [EBX]
-	ADD EAX, EDX
-	ADD EBX, 2
-	DEC ECX
-	JNZ sloop
-eloop:
-	TEST [EBP+len], 1	; check for odd length
-	JZ even
-	MOVZX EDX, BYTE [EBX]	; add last byte
-	ADD EAX, EDX
-even:
-	MOV ECX, EAX	; now add in all the carries
-	SHR ECX, 16
-	AND EAX, 0FFFFH
-	ADD EAX, ECX
-	MOV ECX, EAX	; add in additional carry
-	SHR ECX, 16
-	ADD EAX, ECX	; result is in low 16 bits of EAX
-	NOT EAX
-END Checksum2;
-
-
-(* Return TRUE if "adr1" and "adr2" are in the same subnet defined by "mask". Only for IPv4 *)
-PROCEDURE -SameSubnetv4(adr1, adr2, mask: LONGINT): BOOLEAN;
-CODE {SYSTEM.i386}
-	POP ECX
-	POP EBX
-	POP EAX
-	AND EAX, ECX
-	AND EBX, ECX
-	CMP EAX, EBX
-	SETZ AL
-END SameSubnetv4;
-
-
-(* Return TRUE if adr matches the prefix *)
-PROCEDURE MatchPrefix*(adr: Adr; prefix: Adr): BOOLEAN;
-VAR
-	bytesToCheck: LONGINT;
-	bitsToCheck: LONGINT;
-	i: LONGINT;
-	matches: BOOLEAN;
-	diffSet: SET;
-
-BEGIN
-	IF DEBUG THEN
-		ASSERT ((IsNilAdr(adr)) OR (adr.usedProtocol = IPv6));
-	END;
-
-	matches := TRUE;
-
-	bytesToCheck := prefix.data DIV 8;
-	bitsToCheck := prefix.data MOD 8;
-
-	FOR i := 0 TO bytesToCheck - 1 DO
-		IF adr.ipv6Adr[i] # prefix.ipv6Adr[i] THEN
-			matches := FALSE;
-		END;
-	END;
-
-	IF bitsToCheck # 0 THEN
-		diffSet := {};
-		FOR i := 0 TO 8 - bitsToCheck - 1 DO
-			diffSet := diffSet + {i};
-		END;
-
-		FOR i := 0 TO bitsToCheck - 1 DO
-			IF (SYSTEM.VAL(SET, adr.ipv6Adr[bytesToCheck]) - diffSet) # (SYSTEM.VAL(SET, prefix.ipv6Adr[bytesToCheck]) - diffSet) THEN
-				matches := FALSE;
-			END;
-		END;
-	END;
-	RETURN matches;
-END MatchPrefix;
-
-
-(** Return the interface on which packets with "dst" address should be sent. Return NIL if no interface matches. *)
-PROCEDURE InterfaceByDstIP*(dest: Adr): Interface;
-VAR
-	item, gw: Interface;
-
-BEGIN
-	CASE dest.usedProtocol OF
-		IPv4:
-			gw := NIL;
-			item := interfaces;
-			LOOP
-				IF item = NIL THEN EXIT END;
-				IF (item.protocol = IPv4) & (~IsNilAdr(item.localAdr)) & (item.dev.Linked() # Network.LinkNotLinked) THEN
-					IF SameSubnetv4(dest.ipv4Adr, item.subnetAdr.ipv4Adr, item.maskAdr.ipv4Adr) THEN
-						EXIT;
-					ELSIF (gw = NIL) & (~IsNilAdr(item.subnetAdr)) THEN
-						IF item.protocol # IPv4 THEN
-							gw := item;
-						ELSIF ~IsNilAdr(item.gatewayAdr) THEN
-							gw := item;
-						END;
-					END;
-				END;
-				item := item.next;
-			END;
-			IF item # NIL THEN
-				RETURN item;
-			ELSE
-				RETURN gw;
-			END;
-
-		|IPv6:
-			(* Requires special handling when multiple devices are present *)
-			RETURN v6InterfaceByDstIP(dest);
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN NIL;
-	END;
-END InterfaceByDstIP;
-
-
-(** Return the reference to an installed interface by its name. NIL is returned if no interface with this name
-	was found. *)
-PROCEDURE InterfaceByName*(CONST name: ARRAY OF CHAR): Interface;
-VAR item: Interface;
-BEGIN
-	item := interfaces;
-	WHILE (item # NIL) & (item.name # name) DO
-		item := item.next;
-	END;
-	RETURN item;
-END InterfaceByName;
-
-
-(** Delivers first preferred (if possible) interface of an device.
-	Return the reference to an installed interface by its device. NIL is returned if no interface with this
-	device was found. *)
-PROCEDURE InterfaceByDevice*(dev: Network.LinkDevice): Interface;
-VAR
-	item: Interface;
-	unprefInt: Interface;
-BEGIN
-	unprefInt := NIL;
-	item := interfaces;
-	WHILE (item # NIL) DO
-		IF item.dev = dev THEN
-			IF item.protocol # preferredProtocol THEN
-				unprefInt := item;
-			ELSE
-				RETURN item;
-			END;
-		END;
-		item := item.next;
-	END;
-	(* return interface with unpreferred protocol or NIL *)
-	RETURN unprefInt;
-END InterfaceByDevice;
-
-
-(** Return a list of installed interfaces of a certain device. *)
-PROCEDURE InterfaceListByDevice* (dev: Network.LinkDevice):InterfaceList;
-VAR
-	item: Interface;
-	interfaceList: InterfaceList;
-	interfaceListItem: InterfaceList;
-
-BEGIN
-	item := interfaces;
-	interfaceList := NIL;
-
-	(* search for interfaces with matching device and put them in a list *)
-	WHILE item # NIL DO
-		IF item.dev = dev THEN
-			NEW(interfaceListItem);
-			interfaceListItem.interface := item;
-			interfaceListItem.next := interfaceList;
-			interfaceList := interfaceListItem;
-		END;
-		item := item.next;
-	END;
-	RETURN interfaceList;
-END InterfaceListByDevice;
-
-
-(** Install a receiver for a type. The type is stored in
-	IPv4: Protocol field
-	IPv6: Next header field *)
-PROCEDURE InstallReceiver*( type: LONGINT; r: Receiver);
-BEGIN {EXCLUSIVE}
-	IF DEBUG THEN
-		ASSERT(r # NIL);
-		ASSERT((type >=0) & (type <= 255));
-		ASSERT(receivers[type] = NIL);
-	END;
-
-	receivers[type] := r;
-END InstallReceiver;
-
-
-(** Remove the currently installed receiver for a type. The type is stored in
-	IPv4: Protocol field
-	IPv6: Next header field *)
-PROCEDURE RemoveReceiver*(type: LONGINT);
-BEGIN {EXCLUSIVE}
-	ASSERT((type >=0) & (type <= 255));
-	ASSERT(receivers[type] # NIL);
-
-	receivers[type] := NIL;
-END RemoveReceiver;
-
-
-(** Checks if a string is a valid IPv4 address *)
-PROCEDURE IsValidIPv4Str (CONST ipString: ARRAY OF CHAR): BOOLEAN;
-VAR
-	i,j: LONGINT;
-	ipNr: LONGINT;
-	digits: ARRAY 4 OF CHAR;
-	startClass: LONGINT;
-BEGIN
-	i := 0;
-
-	(* Class A *)
-	WHILE (i < Strings.Length(ipString)) & (ipString[i] #'.') & (i < 3) DO
-		digits[i] := ipString[i];
-		INC (i);
-	END;
-	digits[i] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only numbers *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class B *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length(ipString)) & (ipString[i] # '.') & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class C *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length (ipString)) & (ipString[i] # '.') & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	IF ipString[i] # '.' THEN RETURN FALSE END;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	(* Class D *)
-	INC(i);
-	startClass := i;
-	WHILE (i < Strings.Length (ipString)) & (i - startClass <= 3) DO
-		digits[i-startClass] := ipString[i];
-		INC (i);
-	END;
-	digits[i-startClass] := 0X;
-
-	(* Check if in digits are only number *)
-	j := 0;
-	WHILE digits[j] # 0X DO
-		IF (ORD(digits[j]) - ORD("0")) > 9 THEN RETURN FALSE END;
-		INC (j);
-	END;
-	Strings.StrToInt (digits, ipNr);
-	IF ipNr > 255 THEN RETURN FALSE END;
-
-	RETURN TRUE;
-END IsValidIPv4Str;
-
-
-(** Checks if a string is a valid IPv6 address *)
-PROCEDURE IsValidIPv6Str (ipString: ARRAY OF CHAR): BOOLEAN;
-VAR
-	i: LONGINT;
-	state: LONGINT; (* -1: error *)
-	charCount: LONGINT;
-	ascD: LONGINT;
-	ascH: LONGINT;
-	dPointOcc: BOOLEAN;
-	prefixLenArr: ARRAY 3 OF LONGINT;
-	prefixLen: LONGINT;
-
-BEGIN
-	i := 0;
-	state := 1;
-	dPointOcc := FALSE;
-
-	Strings.UpperCase(ipString);
-
-	WHILE (i < (LEN(ipString) - 1)) & (ipString[i] # 0X) DO
-
-		CASE state OF
-			-1:
-				RETURN FALSE;
-
-			|1:
-				(* 0-9 & A-F *)
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-
-					(* more than 4 digits between two : *)
-					IF charCount > 4 THEN
-						state := -1;
-					END;
-
-				(* : *)
-				ELSIF ipString[i] = ":" THEN
-					charCount := 0;
-					state := 2;
-				ELSIF ipString[i] = "/" THEN
-					charCount := 0;
-					state := 3;
-				ELSE
-					state := -1;
-				END;
-
-			|2:
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ipString[i] = ":" THEN
-					IF dPointOcc THEN
-						state := -1;
-					ELSE
-						dPointOcc := TRUE;
-						state := 4;
-					END
-
-				ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-					state := 1;
-				ELSE
-					state := -1;
-				END;
-
-			|3:
-				ascD := ORD(ipString[i]) - ORD("0");
-
-				IF ~((ascD >= 0) & (ascD <= 9)) THEN
-					state := -1;
-				ELSE
-					IF charCount > 3 THEN
-						state := -1;
-					ELSE
-						prefixLenArr[charCount] := ascD;
-						INC(charCount);
-					END;
-				END;
-
-			|4:
-				ascD := ORD(ipString[i]) - ORD("0");
-				ascH := ORD(ipString[i]) - ORD("A");
-
-				IF ipString[i] = "/" THEN
-					state := 3;
-				ELSIF ((ascD >= 0) & (ascD <= 9)) OR ((ascH >= 0) & (ascH <= 5)) THEN
-					INC(charCount);
-					state := 1;
-				ELSE
-					state := -1;
-				END;
-
-			ELSE
-				IF DEBUG THEN
-					ASSERT(TRUE);
-				END;
-		END;
-		INC(i);
-	END;
-
-	CASE state OF
-		1:
-			RETURN TRUE;
-
-		|3:
-			IF charCount > 0 THEN
-				prefixLen := 0;
-				FOR i:= 0 TO charCount - 1 DO
-					prefixLen := prefixLen * 10;
-					INC(prefixLen, prefixLenArr[i]);
-				END;
-				IF prefixLen <= 64 THEN
-					RETURN TRUE;
-				ELSE
-					RETURN FALSE;
-				END;
-			ELSE
-				RETURN FALSE;
-			END;
-
-		|4:
-			RETURN TRUE;
-
-		ELSE
-			IF DEBUG THEN
-				ASSERT(TRUE);
-			END;
-			RETURN FALSE;
-	END;
-	RETURN FALSE;
-END IsValidIPv6Str;
-
-
-(** Set IPv6 address to zero *)
-PROCEDURE SetIPv6AdrNil (adr: Adr);
-VAR
-	i: LONGINT;
-
-BEGIN
-	FOR i := 0 TO 15 DO
-		adr.ipv6Adr[i] := 0X;
-	END;
-END SetIPv6AdrNil;
-
-
-(* Add the interface to the IP configuration. *)
-PROCEDURE AddInterface*(int: Interface; VAR res: WORD);
-VAR
-	item: Interface;
-BEGIN {EXCLUSIVE}
-	item := interfaces;
-	WHILE item # NIL DO
-		(* Check if interface name already exists *)
-		IF item.name = int.name THEN
-			res := DuplicateInterfaceName;
-			RETURN;
-		END;
-		item := item.next;
-	END;
-	(* Add interface *)
-	int.next := interfaces;
-	interfaces := int;
-	res := Ok;
-END AddInterface;
-
-
-(* Remove the interface from the IP configuration. *)
-PROCEDURE RemoveInterface*(int: Interface);
-VAR
-	item: Interface;
-
-BEGIN {EXCLUSIVE}
-	item := interfaces;
-	IF item = NIL THEN
-		(* empty list *)
-	ELSIF item = int THEN
-		(* remove first item *)
-		interfaces := interfaces.next;
-	ELSE
-		WHILE item.next # int DO
-			item := item.next;
-		END;
-		IF item.next # NIL THEN
-			item.next := item.next.next;
-		ELSE
-			(* not found *)
-		END;
-	END;
-END RemoveInterface;
-
-
-(* Prints out a packet *)
-PROCEDURE PacketOut*(CONST title, buffer: ARRAY OF CHAR; all: BOOLEAN);
-VAR
-	i: LONGINT;
-	length: LONGINT;
-
-BEGIN
-	KernelLog.Ln;KernelLog.String("********************");KernelLog.Ln;
-	KernelLog.String(title); KernelLog.Ln;
-
-	IF all THEN
-		length := LEN(buffer) -1;
-	ELSE
-		length := Strings.Min(LEN(buffer) - 1, 256);
-	END;
-
-	FOR i := 0 TO length DO
-		IF (i MOD 4) = 0 THEN
-			KernelLog.Ln;
-			KernelLog.Int(i, 2);KernelLog.String(":  ");
-		END;
-		KernelLog.Hex(ORD(buffer[i]), -1);
-		KernelLog.String(" ");
-	END;
-
-	KernelLog.Ln;KernelLog.String("********************");KernelLog.Ln;
-END PacketOut;
-
-
-BEGIN
-	(* IPFowarding default value is FALSE *)
-	IPForwarding := FALSE;
-
-	(* EchoReply default value is TRUE *)
-	EchoReply := TRUE;
-
-	(* Initializations *)
-	(* NilAdr *)
-	NilAdr.ipv4Adr := NilAdrIPv4;
-	SetIPv6AdrNil (NilAdr);
-	NilAdr.usedProtocol := NilAdrIdent;
-
-	(* Initialize receiver list *)
-	FOR counter:=0 TO NbrOfReceivers-1 DO
-		receivers[counter] := NIL;
-	END;
-
-	(* Initialize inteface list *)
-	interfaces := NIL;
-END IP.
-
-
-
-Free:
-System.Free TraceRoute VNC Ping WMFTPClient FTPClient WebFTPServer TCPServices TLS InitNetwork Ping DHCP TCP DNS UDP ICMP IPv4 IPv6 IP~
-
-Start:
-InitNetwork.Init
-
-Compile:
-PC.Compile \s IP.Mod IPv4.Mod IPv6.Mod ICMP.Mod UDP.Mod DNS.Mod TCP.Mod DHCP.Mod InitNetwork.Mod WebFTPServer.Mod FTPClient.Mod WMFTPClient.Mod Ping.Mod VNC.Mod TraceRoute.Mod~
-
-
-
-History:
-02.05.2005	eb	Supports IPv6 and fragmented IPv6 packets.
-
-
-
-
-IsValidIPv6Str:
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
-
-FSM used in IsValidIPv6Str:
------------------------
-EOS: end of string
-	State 1: Initial state
-			0-9/A-F goto state 1
-			: goto state 2
-			/ goto state 3
-			EOS valid
-	State 2:	0-9/A-F goto state 1
-			: goto state 4
-			EOS invalid
-	State 3:	0-9 goto state 3
-			EOS valid
-	State 4:	/ goto state 3
-			0-9/A-F goto state 1
-			EOS valid
-
-			

+ 147 - 25
source/ARM.IP.Mod → source/IP.Mod

@@ -873,14 +873,14 @@ BEGIN
 	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
 		IPv4:
 			adr.usedProtocol := IPv4;
-			SYSTEM.MOVE(ADDRESSOF(buffer.data[buffer.l3ofs+12]),ADDRESSOF(adr.ipv4Adr),4); (*adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+12]);*)
+			SYSTEM.MOVE(ADDRESSOF(buffer.data[buffer.l3ofs+12]),ADDRESSOF(adr.ipv4Adr),4); (* data might be unaligned *)
 			SetIPv6AdrNil(adr);
 			RETURN adr;
 
 		|IPv6:
 			adr.usedProtocol := IPv6;
 			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+8+i];
+				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+8 + i];
 			END;
 			adr.ipv4Adr := NilAdrIPv4;
 
@@ -904,14 +904,14 @@ BEGIN
 	CASE ORD(buffer.data[buffer.l3ofs]) DIV 16 OF
 		IPv4:
 			adr.usedProtocol := IPv4;
-			SYSTEM.MOVE(ADDRESSOF(buffer.data[buffer.l3ofs+16]),ADDRESSOF(adr.ipv4Adr),4); (*adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[buffer.l3ofs+16]);*)
+			SYSTEM.MOVE(ADDRESSOF(buffer.data[buffer.l3ofs+16]),ADDRESSOF(adr.ipv4Adr),4); (* data might be unaligned *)
 			SetIPv6AdrNil(adr);
 			RETURN adr;
 
 		|IPv6:
 			adr.usedProtocol := IPv6;
 			FOR i := 0 TO 15 DO
-				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+24+i];
+				adr.ipv6Adr[i] := buffer.data[buffer.l3ofs+24 + i];
 			END;
 			adr.ipv4Adr := NilAdrIPv4;
 
@@ -928,11 +928,26 @@ END DestAdrFromBuffer;
 (* Swap internal representation of an IP address from big to little endian or vice versa. *)
 PROCEDURE -SwapEndian(VAR adr: LONGINT);
 CODE
-	LDR	R0, [FP, #adr]
+#IF I386 THEN
+	POP EAX
+	MOV ECX, [EAX]
+	XCHG CL, CH
+	ROL ECX, 16
+	XCHG CL, CH
+	MOV [EAX], ECX
+#ELSIF AMD64 THEN
+	POP RAX
+	MOV ECX, [RAX]
+	BSWAP ECX
+	MOV [RAX], ECX
+#ELSIF ARM THEN
+	LDMIA	SP!, {R0}
 	LDR	R1, [R0, #0]
 	REV	R1, R1
 	STR	R1, [R0, #0]
-	ADD	SP, SP, #4
+#ELSE
+	unimplemented
+#END
 END SwapEndian;
 
 
@@ -997,14 +1012,44 @@ BEGIN
 END IPConfig;
 
 
-(**
-	First part of a split checksum operation. len must be non-zero and even. chk1 must be 0 at the
+(** 	First part of a split checksum operation. len must be non-zero and even. chk1 must be 0 at the
 	beginning. The result can be passed to a following call to Checksum1(). The last chk1 result must
 	be passed to Checksum2, which sums the data following sequentially on the data summed by this
 	operation. Carries from bit 15 are accumulated in the top 16 bits, so at most 65535 words can be
 	summed by Checksum1 and Checksum2 together. *)
 PROCEDURE Checksum1*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): LONGINT;
 CODE
+#IF I386 THEN
+	MOV EAX, [EBP+chk1]
+	MOV EBX, [EBP+data]
+	ADD EBX, [EBP+ofs]
+	MOV ECX, [EBP+len]
+	SHR ECX, 1
+	JNC sloop
+	PUSH 8	; ASSERT(~ODD(len))
+	INT 3
+sloop:
+	MOVZX EDX, WORD [EBX]
+	ADD EAX, EDX
+	ADD EBX, 2
+	DEC ECX
+	JNZ sloop
+#ELSIF AMD64 THEN
+	MOV EAX, [RBP+chk1]
+	MOV RBX, [RBP+data]
+	ADD EBX, [RBP+ofs]
+	MOV ECX, [RBP+len]
+	SHR ECX, 1
+	JNC sloop
+	PUSH 8	; ASSERT(~ODD(len))
+	INT 3
+sloop:
+	MOVZX EDX, WORD [RBX]
+	ADD EAX, EDX
+	ADD RBX, 2
+	DEC ECX
+	JNZ sloop
+#ELSIF ARM THEN
 	LDR R0, [FP, #chk1]
 	LDR R1, [FP, #ofs]
 	LDR R2, [FP, #len]
@@ -1022,13 +1067,71 @@ WordLoop: ; sum up the words
 	SUB R2, R2, #1
 	CMP R2, #0
 	BNE WordLoop
+#ELSE
+	unimplemented
+#END
 END Checksum1;
 
-(**
-	Continue a checksum operation. len can be zero or odd. chk1 can be the result of Checksum1 for
+
+(** 	Continue a checksum operation. len can be zero or odd. chk1 can be the result of Checksum1 for
 	the immediately preceding data, or 0 for contiguous data. *)
 PROCEDURE Checksum2*(CONST data: ARRAY OF CHAR; ofs, len, chk1: LONGINT): INTEGER;
 CODE
+#IF I386 THEN
+	MOV EAX, [EBP+chk1]
+	MOV EBX, [EBP+data]
+	ADD EBX, [EBP+ofs]
+	MOV ECX, [EBP+len]
+	SHR ECX, 1
+	JZ eloop
+sloop:
+	MOVZX EDX, WORD [EBX]
+	ADD EAX, EDX
+	ADD EBX, 2
+	DEC ECX
+	JNZ sloop
+eloop:
+	TEST [EBP+len], 1	; check for odd length
+	JZ even
+	MOVZX EDX, BYTE [EBX]	; add last byte
+	ADD EAX, EDX
+even:
+	MOV ECX, EAX	; now add in all the carries
+	SHR ECX, 16
+	AND EAX, 0FFFFH
+	ADD EAX, ECX
+	MOV ECX, EAX	; add in additional carry
+	SHR ECX, 16
+	ADD EAX, ECX	; result is in low 16 bits of EAX
+	NOT EAX
+#ELSIF AMD64 THEN
+	MOV EAX, [RBP + chk1]
+	MOV RBX, [RBP + data]
+	ADD EBX, [RBP + ofs]
+	MOV ECX, [RBP + len]
+	SHR ECX, 1
+	JZ eloop
+sloop:
+	MOVZX EDX, WORD [RBX]
+	ADD EAX, EDX
+	ADD RBX, 2
+	DEC ECX
+	JNZ sloop
+eloop:
+	TEST [RBP + len], 1	; check for odd length
+	JZ even
+	MOVZX EDX, BYTE [RBX]	; add last byte
+	ADD EAX, EDX
+even:
+	MOV ECX, EAX	; now add in all the carries
+	SHR ECX, 16
+	AND EAX, 0FFFFH
+	ADD EAX, ECX
+	MOV ECX, EAX	; add in additional carry
+	SHR ECX, 16
+	ADD EAX, ECX	; result is in low 16 bits of EAX
+	NOT EAX
+#ELSIF ARM THEN
 	LDR	R0, [FP, #chk1]
 	LDR	R1, [FP, #20] ; LDR R1, [FP, #data]
 	LDR	R2, [FP, #ofs]
@@ -1062,24 +1165,43 @@ WrapUp: ; 32-bit sum is in R0
 data:
 	WordMask:	d32 0FFFFH
 end:
+#ELSE
+	unimplemented
+#END
 END Checksum2;
 
+
 (* Return TRUE if "adr1" and "adr2" are in the same subnet defined by "mask". Only for IPv4 *)
-PROCEDURE -SameSubnetv4(adr1, adr2, mask: LONGINT): BOOLEAN;
+PROCEDURE SameSubnetv4(adr1, adr2, mask: LONGINT): BOOLEAN;
 CODE
-	LDR		R0, [FP, #adr1]
-	LDR		R1, [FP, #adr2]
-	LDR		R2, [FP, #mask]
-	AND		R0, R0, R2
-	AND		R1, R1, R2
-	CMP		R0, R1
-	BNE false
-	MOV		R0, #1
-	B end
-false:
-	MOV		R0, #0
-end:
-	ADD		SP, SP, #12
+#IF I386 THEN
+	MOV EAX, [EBP + adr1]
+	MOV EBX, [EBP + adr2]
+	MOV ECX, [EBP + mask]
+	AND EAX, ECX
+	AND EBX, ECX
+	CMP EAX, EBX
+	SETE AL
+#ELSIF AMD64 THEN
+	MOV EAX, [RBP + adr1]
+	MOV EBX, [RBP + adr2]
+	MOV ECX, [RBP + mask]
+	AND EAX, ECX
+	AND EBX, ECX
+	CMP EAX, EBX
+	SETE AL
+#ELSIF ARM THEN
+	LDR R0, [FP, #adr1]
+	LDR R1, [FP, #adr2]
+	LDR R2, [FP, #mask]
+	AND R0, R0, R2
+	AND R1, R1, R2
+	CMP R0, R1
+	MOVEQ R0, #1
+	MOVNE R0, #0
+#ELSE
+	unimplemented
+#END
 END SameSubnetv4;
 
 
@@ -1632,4 +1754,4 @@ EOS: end of string
 			0-9/A-F goto state 1
 			EOS valid
 
-			
+			

+ 1 - 4
source/Release.Tool

@@ -424,11 +424,8 @@ PACKAGE System ARCHIVE "System.zip" SOURCE "SystemSrc.zip" DESCRIPTION "System"
 		Windows.CommandLine.Mod	# Command Line Parsing for Windows A2
 	}
 
-	BIOS32 { I386.IP.Mod IPv4.Mod }
-	BIOS64 { AMD64.IP.Mod IPv4.Mod }
-	ARM { ARM.IP.Mod IPv4.Mod }
-
 	NATIVE {
+		IP.Mod IPv4.Mod
 		IPv6.Mod ICMP.Mod UDP.Mod DNS.Mod	# IP, UDP, TCP
 		TCP.Mod DHCP.Mod
 		InitNetwork.Mod MinInitNetwork.Mod						# network initialisation