MODULE IP;
IMPORT SYSTEM, KernelLog, Commands, Strings, Network;
CONST
DEBUG = TRUE;
Ok* = 0;
DeviceAlreadyUsed* = 3901;
DuplicateInterfaceName* = 3902;
NoInterfaceName* = 3903;
GatewayNotInSubnet* = 3904;
IPv6AdrUsedOnIPv4Interface* = 4001;
IPv4AdrUsedOnIPv6Interface* = 4002;
DublicatedAddresses* = 4003;
MixedIpProtocols* = 4003;
LocalAdrSetIntv6* = 4004;
PrefixNotSet* = 4005;
MaxNofDNS* = 10;
MaxTTL* = 255;
NbrOfReceivers = 255;
NilAdrIPv4 = 0;
IPv4* = 4;
IPv6* = 6;
NilAdrIdent = -1;
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;
TYPE
Packet* = POINTER TO ARRAY OF CHAR;
Name* = ARRAY 128 OF CHAR;
Interface* = OBJECT
VAR
localAdr*, maskAdr*, gatewayAdr*, subnetAdr*, broadAdr*: Adr;
name*: Name;
dev*: Network.LinkDevice;
DNS-: ARRAY MaxNofDNS OF Adr;
DNScount*: LONGINT;
next*: Interface;
closed*: BOOLEAN;
protocol*: LONGINT;
PROCEDURE SetAdrs*(localAdr, maskOrPrefixAdr, gatewayAdr: Adr; VAR res: LONGINT);
BEGIN
HALT(99);
END SetAdrs;
PROCEDURE DNSRemoveAll*;
BEGIN {EXCLUSIVE}
DNScount := 0;
END DNSRemoveAll;
PROCEDURE DNSAdd*(adr: Adr);
VAR
i: LONGINT;
BEGIN {EXCLUSIVE}
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;
PROCEDURE DNSRemove*(adr: Adr);
VAR i: LONGINT;
BEGIN {EXCLUSIVE}
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;
PROCEDURE Send*(type: LONGINT; destAdr: Adr; VAR l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, TTL: LONGINT);
BEGIN
HALT(99);
END Send;
PROCEDURE DoSend*(destAdr: Adr; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT) ;
BEGIN
HALT(99);
END DoSend;
PROCEDURE ARPEnumerate*(handle: ARPHandler);
BEGIN
HALT(99);
END ARPEnumerate;
PROCEDURE Close*;
BEGIN
HALT(99);
END Close;
PROCEDURE IsBroadcast*(adr: Adr) : BOOLEAN;
BEGIN
HALT(99);
END IsBroadcast;
PROCEDURE IsMulticast*(adr: Adr) : BOOLEAN;
BEGIN
HALT(99);
END IsMulticast;
PROCEDURE IPInput*(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
BEGIN
HALT(99);
END IPInput;
PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): Adr;
BEGIN
HALT(99);
END ReadSrcAdr;
PROCEDURE ReadDestAdr* (buffer: Network.Buffer): Adr;
BEGIN
HALT(99);
END ReadDestAdr;
PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR; src, dst: Adr; protocol, pktLengthUpperLayer: LONGINT): LONGINT;
BEGIN
HALT(99);
END WritePseudoHeader;
PROCEDURE OutInterface*;
BEGIN
HALT(99);
END OutInterface;
END Interface;
TYPE
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;
ARPHandler* = PROCEDURE {DELEGATE} (ip: Adr; complete: BOOLEAN; link: Network.LinkAdr; size, sendTime, updateTime, updateDate, hash: LONGINT);
InterfaceHandler* = PROCEDURE {DELEGATE} (int: Interface);
VAR
receivers*: ARRAY 256 OF Receiver;
v6InterfaceByDstIP*: V6InterfaceByDstIP;
NilAdr*: Adr;
preferredProtocol*: LONGINT;
NIPSentToSubnet*, NIPSentToGateway*, NIPSentBroadcast*, NIPCantFragment*,
NIPRcvTotal*, NIPTooSmall*, NIPBadVersion*, NIPOptions*, NIPBadChecksum*,
NIPBadLength*, NIPTrim*, NIPBadHdrLen*, NIPNotForUs*, NIPCantReassemble*, NIPSrcIsBroadcast*,
NIPDelivered*, NIPNoReceiver*, NIPForwarded*, NIPSentLocalLoopback*, NIPSentPointToPoint*: LONGINT;
IPForwarding*: BOOLEAN;
EchoReply*: BOOLEAN;
interfaces*: Interface;
counter: LONGINT;
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;
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:
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;
PROCEDURE StrToAdr*(ipString: ARRAY OF CHAR): Adr;
VAR
retAdr: Adr;
i, j, x: LONGINT;
adr: ARRAY 4 OF CHAR;
ok: BOOLEAN;
charCount: LONGINT;
ipv6AdrPart: ARRAY 6 OF CHAR;
ipv6AdrRight: ARRAY 16 OF CHAR;
hexToChar: ARRAY 3 OF CHAR;
leftParts: LONGINT;
rightParts: LONGINT;
val, res: LONGINT;
state: LONGINT;
dPointOcc: BOOLEAN;
prefixVal: LONGINT;
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
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
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
-1:
RETURN NilAdr;
|1:
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
ipv6AdrPart[charCount] := ipString[i];
INC(charCount);
END;
|2:
IF ipString[i] = ":" THEN
dPointOcc := TRUE;
state := 4;
ELSE
state := 1;
charCount := 0;
ipv6AdrPart[charCount] := ipString[i];
INC(charCount);
END;
|3:
prefixVal := (prefixVal * 10) + (ORD(ipString[i]) - ORD("0"));
|4:
IF ipString[i] = "/" THEN
state := 3;
ELSE
IF ~ComputeIPv6Part() THEN
RETURN NilAdr;
END;
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
FOR i:= leftParts TO ((LEN(retAdr.ipv6Adr) -1) - rightParts) DO
retAdr.ipv6Adr[i] := 0X;
END;
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;
PROCEDURE AdrToStr*(adr: Adr; VAR string: ARRAY OF CHAR);
VAR
i, j, x: LONGINT;
a: ARRAY 4 OF CHAR;
val, res: 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);
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
val := ORD(adr.ipv6Adr[i]) * 256;
val := val + ORD(adr.ipv6Adr[i+1]);
Strings.IntToHexStr (val, 3, hexToStr);
IF res # Strings.Ok THEN
string := "";
RETURN;
END;
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;
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
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
Strings.IntToStr(adr.data, prefixLenStr);
Strings.Append (string, "/");
Strings.Append (string, prefixLenStr);
END;
ELSE
IF IsNilAdr (adr) THEN
string := "";
END;
END;
END AdrToStr;
PROCEDURE ArrayToAdr*(VAR 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
IF ~(ofs + 4 <= LEN(array)) THEN
RETURN NilAdr;
END;
SYSTEM.MOVE(SYSTEM.ADR(array[ofs]), SYSTEM.ADR(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(SYSTEM.ADR(array[ofs]), SYSTEM.ADR(adr.ipv6Adr), 16);
IF LSBfirst THEN
FOR i := 0 TO 3 DO
SYSTEM.MOVE(SYSTEM.ADR(adr.ipv6Adr[i*4]), SYSTEM.ADR(swapTemp), 4);
SwapEndian(swapTemp);
SYSTEM.MOVE(SYSTEM.ADR(swapTemp), SYSTEM.ADR(adr.ipv6Adr[i*4]), 4);
END;
END;
adr.usedProtocol := IPv6;
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
RETURN NilAdr;
END;
RETURN adr;
END ArrayToAdr;
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(SYSTEM.ADR(tempAdr.ipv4Adr), SYSTEM.ADR(array[ofs]), 4);
| IPv6:
IF ~(ofs + 16 <= LEN(array)) THEN
tempAdr := NilAdr;
END;
IF LSBfirst THEN
FOR i := 0 TO 3 DO
SYSTEM.MOVE(SYSTEM.ADR(tempAdr.ipv6Adr[i*4]), SYSTEM.ADR(swapTemp), 4);
SwapEndian(swapTemp);
SYSTEM.MOVE(SYSTEM.ADR(swapTemp), SYSTEM.ADR(tempAdr.ipv6Adr[i*4]), 4);
END;
END;
SYSTEM.MOVE(SYSTEM.ADR(adr.ipv6Adr), SYSTEM.ADR(array[ofs]), 16);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
END;
END AdrToArray;
PROCEDURE SrcAdrFromBuffer* (buffer: Network.Buffer): Adr;
VAR
i: LONGINT;
adr: Adr;
BEGIN
CASE ORD(buffer.data[0]) DIV 16 OF
IPv4:
adr.usedProtocol := IPv4;
adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[12]);
SetIPv6AdrNil(adr);
RETURN adr;
|IPv6:
adr.usedProtocol := IPv6;
FOR i := 0 TO 15 DO
adr.ipv6Adr[i] := buffer.data[8 + i];
END;
adr.ipv4Adr := NilAdrIPv4;
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
RETURN NilAdr;
END;
RETURN NilAdr;
END SrcAdrFromBuffer;
PROCEDURE DestAdrFromBuffer* (buffer: Network.Buffer): Adr;
VAR
adr: Adr;
i: LONGINT;
BEGIN
CASE ORD(buffer.data[0]) DIV 16 OF
IPv4:
adr.usedProtocol := IPv4;
adr.ipv4Adr := SYSTEM.VAL(LONGINT, buffer.data[16]);
SetIPv6AdrNil(adr);
RETURN adr;
|IPv6:
adr.usedProtocol := IPv6;
FOR i := 0 TO 15 DO
adr.ipv6Adr[i] := buffer.data[24 + i];
END;
adr.ipv4Adr := NilAdrIPv4;
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
RETURN NilAdr;
END;
RETURN NilAdr;
END DestAdrFromBuffer;
PROCEDURE -SwapEndian(VAR adr: LONGINT);
CODE {SYSTEM.AMD64}
POP RAX
MOV ECX, [RAX]
BSWAP ECX
MOV [RAX], ECX
END SwapEndian;
PROCEDURE OutAdr*(adr: Adr);
VAR
s: ARRAY 64 OF CHAR;
BEGIN
AdrToStr(adr, s); KernelLog.String(s);
END OutAdr;
PROCEDURE Enumerate*(handler: InterfaceHandler);
VAR item: Interface;
BEGIN
item := interfaces;
WHILE item # NIL DO
handler(item);
item := item.next;
END;
END Enumerate;
PROCEDURE OutInterface*(interface: Interface);
BEGIN
interface.OutInterface;
END OutInterface;
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;
PROCEDURE Checksum1*(VAR 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;
PROCEDURE Checksum2*(VAR 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;
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;
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;
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:
RETURN v6InterfaceByDstIP(dest);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
RETURN NIL;
END;
END InterfaceByDstIP;
PROCEDURE InterfaceByName*(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;
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 unprefInt;
END InterfaceByDevice;
PROCEDURE InterfaceListByDevice* (dev: Network.LinkDevice):InterfaceList;
VAR
item: Interface;
interfaceList: InterfaceList;
interfaceListItem: InterfaceList;
BEGIN
item := interfaces;
interfaceList := NIL;
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;
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;
PROCEDURE RemoveReceiver*(type: LONGINT);
BEGIN {EXCLUSIVE}
ASSERT((type >=0) & (type <= 255));
ASSERT(receivers[type] # NIL);
receivers[type] := NIL;
END RemoveReceiver;
PROCEDURE IsValidIPv4Str (ipString: ARRAY OF CHAR): BOOLEAN;
VAR
i,j: LONGINT;
ipNr: LONGINT;
digits: ARRAY 4 OF CHAR;
startClass: LONGINT;
BEGIN
i := 0;
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;
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;
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;
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;
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;
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;
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;
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;
PROCEDURE IsValidIPv6Str (ipString: ARRAY OF CHAR): BOOLEAN;
VAR
i: LONGINT;
state: LONGINT;
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:
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);
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;
PROCEDURE SetIPv6AdrNil (adr: Adr);
VAR
i: LONGINT;
BEGIN
FOR i := 0 TO 15 DO
adr.ipv6Adr[i] := 0X;
END;
END SetIPv6AdrNil;
PROCEDURE AddInterface*(int: Interface; VAR res: LONGINT);
VAR
item: Interface;
BEGIN {EXCLUSIVE}
item := interfaces;
WHILE item # NIL DO
IF item.name = int.name THEN
res := DuplicateInterfaceName;
RETURN;
END;
item := item.next;
END;
int.next := interfaces;
interfaces := int;
res := Ok;
END AddInterface;
PROCEDURE RemoveInterface*(int: Interface);
VAR
item: Interface;
BEGIN {EXCLUSIVE}
item := interfaces;
IF item = NIL THEN
ELSIF item = int THEN
interfaces := interfaces.next;
ELSE
WHILE item.next # int DO
item := item.next;
END;
IF item.next # NIL THEN
item.next := item.next.next;
ELSE
END;
END;
END RemoveInterface;
PROCEDURE PacketOut*(title: ARRAY OF CHAR; 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
IPForwarding := FALSE;
EchoReply := TRUE;
NilAdr.ipv4Adr := NilAdrIPv4;
SetIPv6AdrNil (NilAdr);
NilAdr.usedProtocol := NilAdrIdent;
FOR counter:=0 TO NbrOfReceivers-1 DO
receivers[counter] := NIL;
END;
interfaces := NIL;
END IP.
Free:
SystemTools.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