MODULE IPv4;
IMPORT SYSTEM, Machine, Kernel, Modules, Clock, KernelLog, Network, IP;
CONST
DEBUG = TRUE;
ARPHdrLen = 8;
ARPPktLen = 28;
EtherTypeARP* = 806H;
ARPMonitor = FALSE;
ARPHashSize = 256;
MinARPTime = 1000;
EtherTypeIP* = 800H;
MinIPHdrLen*= 20;
MaxIPHdrLen* = 60;
TOS = 10X;
BroadcastAdr = SHORT(0FFFFFFFFH);
TYPE
ARPEntry = POINTER TO RECORD
next: ARPEntry;
ip: IP.Adr;
ether: Network.LinkAdr;
sendTime, updateTime, updateDate: LONGINT;
complete: BOOLEAN;
buf: IP.Packet;
END;
TYPE
Interface* = OBJECT(IP.Interface)
VAR
arpTable: ARRAY ARPHashSize OF ARPEntry;
NARPEntries: LONGINT;
doingDHCPRequest*: BOOLEAN;
PROCEDURE &Constr*(name: IP.Name; dev: Network.LinkDevice; VAR res: LONGINT);
VAR
i: LONGINT;
BEGIN
ASSERT(dev # NIL);
SELF.dev := dev;
protocol := IP.IPv4;
doingDHCPRequest := FALSE;
IF name = "" THEN
res := IP.NoInterfaceName;
RETURN;
END;
COPY(name, SELF.name);
localAdr := IP.NilAdr;
maskAdr := IP.NilAdr;
gatewayAdr := IP.NilAdr;
subnetAdr := IP.NilAdr;
broadAdr.usedProtocol := IP.IPv4;
broadAdr.ipv4Adr := BroadcastAdr;
FOR i := 0 TO ARPHashSize-1 DO
arpTable[i] := NIL;
END;
NARPEntries := 0;
DNScount := 0;
closed := FALSE;
IP.AddInterface(SELF, res);
IF res = IP.Ok THEN
dev.InstallReceiver(SELF, EtherTypeIP, IPInput, IsIPPacketValid, IsIPPacketForSingleInt, IsIPPacketAccepted, IP.IPForwarding);
dev.InstallReceiver(SELF, EtherTypeARP, ARPInput, IsARPPacketValid, IsARPPacketForSingleInt, IsARPPacketAccepted, FALSE);
ELSE
closed := TRUE;
END;
END Constr;
PROCEDURE Close*;
BEGIN {EXCLUSIVE}
ASSERT(~closed);
closed := TRUE;
dev.RemoveReceiver(SELF, EtherTypeIP);
dev.RemoveReceiver(SELF, EtherTypeARP);
IP.RemoveInterface(SELF);
END Close;
PROCEDURE Send*(type: LONGINT; fip:IP. Adr; VAR l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, TTL: LONGINT);
VAR
l3hdr: ARRAY MaxIPHdrLen OF CHAR;
BEGIN
ASSERT (fip.usedProtocol = 4, 2345 );
IF closed THEN RETURN END;
l3hdr[0] := CHR(IP.IPv4*10H + MinIPHdrLen DIV 4);
l3hdr[1] := TOS;
Network.PutNet2(l3hdr, 2, MinIPHdrLen+h4len+dlen);
Network.PutNet2(l3hdr, 4, GetNextID());
Network.Put2(l3hdr, 6, 0);
l3hdr[8] := CHR(TTL);
l3hdr[9] := CHR(type);
Network.Put4(l3hdr, 12, localAdr.ipv4Adr);
Network.Put4(l3hdr, 16, fip.ipv4Adr);
Network.Put2(l3hdr, 10, 0);
IF ~(Network.ChecksumIP IN dev.calcChecksum) THEN
Network.Put2(l3hdr, 10, IP.Checksum2(l3hdr, 0, MinIPHdrLen, 0));
END;
DoSend(fip, l3hdr, l4hdr, data, MinIPHdrLen, h4len, dofs, dlen);
END Send;
PROCEDURE DoSend*(destAdr: IP.Adr; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT) ;
VAR
linkDst: Network.LinkAdr;
BEGIN
ASSERT (destAdr.usedProtocol = 4, 2345);
IF h3len+h4len+dlen <= dev.mtu THEN
IF dev.type = Network.TypeEthernet THEN
IF IP.AdrsEqual (destAdr, localAdr) THEN
Machine.AtomicInc(IP.NIPSentLocalLoopback);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, TRUE);
ELSIF IsBroadcast(destAdr) THEN
Machine.AtomicInc(IP.NIPSentBroadcast);
dev.Send(dev.broadcast, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
ELSIF IsMulticast(destAdr) THEN
ELSE
IF (~IP.IsNilAdr (gatewayAdr)) & ~SameSubnet(destAdr.ipv4Adr, subnetAdr.ipv4Adr, maskAdr.ipv4Adr) THEN
Machine.AtomicInc(IP.NIPSentToGateway);
destAdr := gatewayAdr;
ELSE
Machine.AtomicInc(IP.NIPSentToSubnet);
END;
IF ARPLookup(destAdr, linkDst) THEN
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
ELSE
ARPQueue(destAdr, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen);
END;
END;
ELSE
Machine.AtomicInc(IP.NIPSentPointToPoint);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, IP.AdrsEqual (destAdr, localAdr));
END;
ELSE
Machine.AtomicInc(IP.NIPCantFragment);
END;
END DoSend;
PROCEDURE ARPInput* (dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
VAR
src, dst: IP.Adr;
forus: BOOLEAN;
BEGIN
src := ARPReadSrcAdr (buffer);
dst := ARPReadDestAdr (buffer);
IF IP.AdrsEqual (src, localAdr) THEN
Machine.AtomicInc(NARPRcvDuplicate);
KernelLog.Enter;
KernelLog.String("IP: Address "); IP.OutAdr(src); KernelLog.String(" hijacked by ");
Network.OutLinkAdr(SYSTEM.VAL(Network.LinkAdr, buffer.data[buffer.ofs+8]), dev.adrSize); KernelLog.Ln;
KernelLog.Exit;
ELSIF (buffer.data[buffer.ofs+7] = 1X) OR (buffer.data[buffer.ofs+7] = 2X) THEN
IF ~ODD(LONG(ORD(buffer.data[buffer.ofs+8]))) & (~IP.IsNilAdr(src)) THEN
forus := (IP.AdrsEqual(dst, localAdr));
ARPEnter(src, SYSTEM.VAL(Network.LinkAdr, buffer.data[buffer.ofs+8]), forus);
IF (buffer.data[buffer.ofs+7] = 1X) & forus THEN
ARPReply(buffer.data, buffer.ofs);
END;
ELSE
Machine.AtomicInc(NARPBadAddr)
END
ELSE
Machine.AtomicInc(NARPRcvIgnored)
END;
Network.ReturnBuffer(buffer);
END ARPInput;
PROCEDURE IPInput(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
VAR
hlen: LONGINT;
src, dst: IP.Adr;
receiver: IP.Receiver;
int: IP.Interface;
BEGIN
hlen := ORD(buffer.data[buffer.ofs]) MOD 10H * 4;
src := ReadSrcAdr (buffer);
dst := ReadDestAdr (buffer);
IF ~IsBroadcast(src) & ~IsMulticast(src) THEN
IF (IP.AdrsEqual (dst,localAdr)) OR IsBroadcast(dst) THEN
type := ORD(buffer.data[buffer.ofs+9]);
receiver := IP.receivers[type];
IF receiver # NIL THEN
buffer.l3ofs := buffer.ofs;
INC(buffer.ofs, hlen);
DEC(buffer.len, hlen);
receiver(SELF, type, src, dst, buffer);
Machine.AtomicInc(IP.NIPDelivered);
RETURN;
ELSE
Machine.AtomicInc(IP.NIPNoReceiver);
END;
ELSIF IsMulticast(dst) THEN
ELSIF IP.IPForwarding THEN
int := IP.InterfaceByDstIP(dst);
IF int # NIL THEN
int.DoSend(dst, buffer.data, buffer.data, buffer.data, 0, 0, buffer.ofs, buffer.len);
Machine.AtomicInc(IP.NIPForwarded)
ELSE
Machine.AtomicInc(IP.NIPNotForUs)
END;
ELSE
Machine.AtomicInc(IP.NIPNotForUs)
END
ELSE
Machine.AtomicInc(IP.NIPSrcIsBroadcast)
END;
Network.ReturnBuffer(buffer);
END IPInput;
PROCEDURE IsBroadcast*(adr: IP.Adr) : BOOLEAN;
BEGIN
ASSERT (adr.usedProtocol = 4, 2345);
RETURN (adr.ipv4Adr = broadAdr.ipv4Adr) OR
(adr.ipv4Adr = subnetAdr.ipv4Adr) OR (adr.ipv4Adr = BroadcastAdr)
END IsBroadcast;
PROCEDURE IsMulticast*(adr: IP.Adr) : BOOLEAN;
VAR
arr: ARRAY 4 OF CHAR;
BEGIN
ASSERT (adr.usedProtocol = 4, 2345);
IP.AdrToArray(adr, arr, 0, FALSE);
RETURN (ORD(arr[0]) >= 224) & (ORD(arr[0]) < 240)
END IsMulticast;
PROCEDURE IsIPPacketAccepted(buffer: Network.Buffer): BOOLEAN;
VAR
dstAdr: LONGINT;
interface: IP.Interface;
accept: BOOLEAN;
BEGIN
dstAdr := Network.Get4(buffer.data, buffer.ofs+16);
IF IP.IsNilAdr(localAdr) THEN
IF doingDHCPRequest THEN
interface := IP.interfaces;
WHILE (interface # NIL) & (interface.localAdr.ipv4Adr # dstAdr) DO
interface := interface.next;
END;
IF interface # NIL THEN
accept := FALSE;
ELSE
accept := TRUE;
END;
ELSE
accept := FALSE;
END;
ELSE
accept := dstAdr = localAdr.ipv4Adr;
END;
RETURN accept;
END IsIPPacketAccepted;
PROCEDURE SetAdrs*(localAdr, maskAdr, gatewayAdr: IP.Adr; VAR res: LONGINT);
VAR
maskSet: SET;
BEGIN {EXCLUSIVE}
IF DEBUG THEN
ASSERT ((IP.IsNilAdr(localAdr)) OR (localAdr.usedProtocol = 4), 2345);
ASSERT ((IP.IsNilAdr(maskAdr)) OR (maskAdr.usedProtocol = 4), 2345);
ASSERT ((IP.IsNilAdr(gatewayAdr)) OR (gatewayAdr.usedProtocol = 4), 2345);
END;
IF ~IP.IsNilAdr (localAdr) THEN
IF ((localAdr.usedProtocol # maskAdr.usedProtocol) OR
((~IP.IsNilAdr (gatewayAdr)) & (localAdr.usedProtocol # gatewayAdr.usedProtocol))) THEN
res := IP.MixedIpProtocols;
RETURN;
END;
IF localAdr.usedProtocol # IP.IPv4 THEN
res := IP.IPv6AdrUsedOnIPv4Interface;
RETURN;
END;
END;
SELF.localAdr := localAdr;
SELF.maskAdr := maskAdr;
SELF.gatewayAdr := gatewayAdr;
maskSet := SYSTEM.VAL(SET, maskAdr.ipv4Adr);
subnetAdr.usedProtocol := IP.IPv4;
subnetAdr.ipv4Adr := SYSTEM.VAL (LONGINT, SYSTEM.VAL (SET, localAdr.ipv4Adr) * maskSet);
broadAdr.usedProtocol := IP.IPv4;
broadAdr.ipv4Adr := SYSTEM.VAL (LONGINT, SYSTEM.VAL (SET, subnetAdr.ipv4Adr) + (-maskSet));
IF (~IP.IsNilAdr (gatewayAdr)) &
( ~SameSubnet(gatewayAdr.ipv4Adr, localAdr.ipv4Adr, maskAdr.ipv4Adr)) THEN
res := IP.GatewayNotInSubnet;
ELSE
res := IP.Ok;
END;
END SetAdrs;
PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): IP.Adr;
VAR
adr: IP.Adr;
BEGIN
adr.usedProtocol := IP.IPv4;
adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+12);
RETURN adr;
END ReadSrcAdr;
PROCEDURE ReadDestAdr* (buffer: Network.Buffer): IP.Adr;
VAR
adr: IP.Adr;
BEGIN
adr.usedProtocol := IP.IPv4;
adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+16);
RETURN adr;
END ReadDestAdr;
PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR; src, dst: IP.Adr; protocol, pktLengthUpperLayer: LONGINT): LONGINT;
BEGIN
Network.Put4(pseudoHdr, 0, src.ipv4Adr);
Network.Put4(pseudoHdr, 4, dst.ipv4Adr);
Network.PutNet2(pseudoHdr, 8, protocol);
Network.PutNet2(pseudoHdr, 10, pktLengthUpperLayer);
RETURN 12;
END WritePseudoHeader;
PROCEDURE ARPReadSrcAdr* (buffer: Network.Buffer): IP.Adr;
VAR
adr: IP.Adr;
BEGIN
adr.usedProtocol := IP.IPv4;
adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+14);
RETURN adr;
END ARPReadSrcAdr;
PROCEDURE ARPReadDestAdr* (buffer: Network.Buffer): IP.Adr;
VAR
adr: IP.Adr;
BEGIN
adr.usedProtocol := IP.IPv4;
adr.ipv4Adr := Network.Get4(buffer.data, buffer.ofs+24);
RETURN adr;
END ARPReadDestAdr;
PROCEDURE ARPEnumerate*(handle: IP.ARPHandler);
VAR
p: ARPEntry;
i: LONGINT;
BEGIN
FOR i := 0 TO ARPHashSize-1 DO
p := arpTable[i];
WHILE p # NIL DO
handle(p.ip, p.complete, p.ether, 6, p.sendTime, p.updateTime, p.updateDate, i);
p := p.next
END
END
END ARPEnumerate;
PROCEDURE ARPEnter(ip:IP. Adr; ether: Network.LinkAdr; forus: BOOLEAN);
VAR
p, q: ARPEntry;
n: LONGINT;
PROCEDURE NewEntry;
BEGIN
NEW(p);
p.ip := ip;
p.buf := NIL;
p.sendTime := Kernel.GetTicks() - minARPTime;
p.complete := FALSE;
p.next := arpTable[n];
arpTable[n] := p;
Machine.AtomicInc(NARPEntries);
END NewEntry;
BEGIN {EXCLUSIVE}
ASSERT (ip.usedProtocol = 4, 2345);
n := ARPHash(ip.ipv4Adr);
p := arpTable[n];
WHILE (p # NIL) & (~IP.AdrsEqual(p.ip,ip)) DO
p := p.next;
END;
IF (p = NIL) & (ARPMonitor OR forus) THEN
NewEntry();
END;
IF p # NIL THEN
IF ARPMonitor & p.complete & ~Network.Equal(ether, p.ether, 0, 0, 6) THEN
q := p.next;
WHILE (q # NIL) & (~Network.Equal(ether, q.ether, 0, 0, 6) OR ~IP.AdrsEqual(q.ip, ip)) DO
q := q.next
END;
IF q # NIL THEN
p := q;
ELSE
KernelLog.Enter;
KernelLog.String("IP: Address for "); IP.OutAdr(p.ip);
KernelLog.String(" changed from "); Network.OutLinkAdr(p.ether, 6);
KernelLog.String(" to "); Network.OutLinkAdr(ether, 6);
KernelLog.Exit;
NewEntry();
END;
END;
IF p.buf # NIL THEN
dev.Send(ether, EtherTypeIP, p.buf^, p.buf^, p.buf^, 0, 0, 0, LEN(p.buf^), FALSE);
p.buf := NIL;
END;
p.ether := ether;
p.complete := TRUE;
Clock.Get(p.updateTime, p.updateDate);
END
END ARPEnter;
PROCEDURE ARPReply(VAR arp: ARRAY OF CHAR; ofs: LONGINT);
BEGIN
Machine.AtomicInc(NARPReply);
arp[ofs+7] := 2X;
Network.Copy(arp, arp, ofs+8, ofs+18, 6+4);
Network.Copy(dev.local, arp, 0, ofs+8, 6);
Network.Put4(arp, ofs+14, localAdr.ipv4Adr);
dev.Send(SYSTEM.VAL(Network.LinkAdr, arp[ofs + 18]), EtherTypeARP, arp, arp, arp, 0, 0, ofs, ARPPktLen, FALSE);
END ARPReply;
PROCEDURE ARPLookup(ip: IP.Adr; VAR ether: Network.LinkAdr): BOOLEAN;
VAR p: ARPEntry; c: BOOLEAN;
BEGIN
ASSERT (ip.usedProtocol = 4, 2345);
p := arpTable[ARPHash(ip.ipv4Adr)];
LOOP
IF p = NIL THEN RETURN FALSE END;
IF IP.AdrsEqual (p.ip, ip) THEN
c := p.complete;
ether := p.ether;
RETURN c;
END;
p := p.next
END
END ARPLookup;
PROCEDURE ARPQueue(dst: IP.Adr; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
VAR p: ARPEntry; n: LONGINT;
BEGIN {EXCLUSIVE}
ASSERT (dst.usedProtocol = 4, 2345);
Machine.AtomicInc(NARPPut);
n := ARPHash(dst.ipv4Adr);
p := arpTable[n];
WHILE (p # NIL) & (~IP.AdrsEqual (p.ip, dst)) DO
p := p.next
END;
IF p = NIL THEN
NEW(p);
p.complete := FALSE;
p.ip := dst;
p.sendTime := Kernel.GetTicks() - minARPTime;
NEW(p.buf, h3len+h4len+dlen);
Network.Copy(l3hdr, p.buf^, 0, 0, h3len);
Network.Copy(l4hdr, p.buf^, 0, h3len, h4len);
Network.Copy(data, p.buf^, dofs, h3len+h4len, dlen);
p.next := arpTable[n];
arpTable[n] := p;
Machine.AtomicInc(NARPEntries);
END;
IF p.complete THEN
dev.Send(p.ether, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
ELSE
IF Kernel.GetTicks() - p.sendTime >= minARPTime THEN
ARPRequest(dst);
p.sendTime := Kernel.GetTicks();
ELSE
Machine.AtomicInc(NARPSkipped);
END
END
END ARPQueue;
PROCEDURE ARPRequest(ip: IP.Adr);
VAR
i: LONGINT;
arp: ARRAY ARPPktLen OF CHAR;
BEGIN
ASSERT (ip.usedProtocol = 4, 2345);
Machine.AtomicInc(NARPRequest);
Network.Copy(arpProto, arp, 0, 0, ARPHdrLen);
arp[7] := 1X;
Network.Copy(dev.local, arp, 0, 8, 6);
Network.Put4(arp, 14, localAdr.ipv4Adr);
FOR i:= 18 TO 23 DO
arp[i] := 0X;
END;
Network.Put4(arp, 24, ip.ipv4Adr);
dev.Send(dev.broadcast, EtherTypeARP, arp, arp, arp, 0, 0, 0, ARPPktLen, FALSE);
END ARPRequest;
PROCEDURE OutInterface*;
VAR i: LONGINT;
str : ARRAY 32 OF CHAR;
BEGIN
IF closed THEN
KernelLog.Enter;
KernelLog.String("IP.OutInterface: Error: Interface already closed!"); KernelLog.Ln;
KernelLog.Exit;
ELSE
KernelLog.Enter; KernelLog.Ln;
KernelLog.String("=== Interface ==="); KernelLog.Ln;
KernelLog.String("Interface name: "); KernelLog.String(name); KernelLog.Ln;
KernelLog.String("Attached device: "); KernelLog.String(dev.name);
IF dev.Linked() = Network.LinkLinked THEN
KernelLog.String(" (LinkLinked)"); KernelLog.Ln;
ELSIF dev.Linked() = Network.LinkNotLinked THEN
KernelLog.String(" (LinkNotLinked)"); KernelLog.Ln;
ELSE
KernelLog.String(" (LinkUnknown)"); KernelLog.Ln;
END;
Network.LinkAdrToStr(dev.local, 8, str);
KernelLog.String("MAC address: "); KernelLog.String(str); KernelLog.Ln;
KernelLog.String("Local address: "); IP.OutAdr(localAdr); KernelLog.Ln;
KernelLog.String("Netmask: "); IP.OutAdr(maskAdr); KernelLog.Ln;
KernelLog.String("Gateway address: "); IP.OutAdr(gatewayAdr); KernelLog.Ln;
KernelLog.String("Subnet: "); IP.OutAdr(subnetAdr); KernelLog.Ln;
KernelLog.String("Net broadcast: "); IP.OutAdr(broadAdr); KernelLog.Ln;
IF DNScount > 0 THEN
FOR i:= 0 TO DNScount-1 DO
KernelLog.String("DNS server: "); IP.OutAdr(DNS[i]); KernelLog.Ln;
END;
ELSE
KernelLog.String("DNS server: none"); KernelLog.Ln;
END;
KernelLog.Exit;
END;
END OutInterface;
END Interface;
VAR
nextID: INTEGER;
arpProto: ARRAY ARPHdrLen OF CHAR;
minARPTime: LONGINT;
NARPPut-, NARPRcvTotal-, NARPRcvTooSmall-, NARPRcvIgnored-, NARPRcvDuplicate-, NARPBadAddr-,
NARPRequest-, NARPReply-, NARPSkipped-: LONGINT;
PROCEDURE SameSubnet(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 SameSubnet;
PROCEDURE -ARPHash(ip: LONGINT): LONGINT;
CODE {SYSTEM.AMD64}
; hash := ip MOD ARPHashSize;
POP EAX
; Convert IP to host byte order
BSWAP EAX
; MOD operation
MOV EBX, ARPHashSize
XOR EDX, EDX
DIV EBX
MOV EAX, EDX
END ARPHash;
PROCEDURE IsARPPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
BEGIN
RETURN FALSE;
END IsARPPacketForSingleInt;
PROCEDURE IsIPPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
BEGIN
RETURN ~(buffer.data[buffer.ofs+19] = 0FFX);
END IsIPPacketForSingleInt;
PROCEDURE IsARPPacketAccepted(buffer: Network.Buffer): BOOLEAN;
BEGIN
RETURN TRUE;
END IsARPPacketAccepted;
PROCEDURE IsIPPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
VAR
isValid: BOOLEAN;
hlen, tlen, frag: LONGINT;
BEGIN
isValid := FALSE;
Machine.AtomicInc(IP.NIPRcvTotal);
IF buffer.len >= MinIPHdrLen THEN
IF SYSTEM.LSH(ORD(buffer.data[buffer.ofs]), -4) = IP.IPv4 THEN
hlen := ORD(buffer.data[buffer.ofs]) MOD 10H * 4;
IF (hlen >= MinIPHdrLen) & (hlen <= MaxIPHdrLen) THEN
IF (Network.ChecksumIP IN buffer.calcChecksum) OR (IP.Checksum2(buffer.data, buffer.ofs, hlen, 0) = 0) THEN
tlen := Network.GetNet2(buffer.data, buffer.ofs+2);
IF (tlen >= hlen) & (tlen <= buffer.len) THEN
IF tlen < buffer.len THEN
Machine.AtomicInc(IP.NIPTrim);
buffer.len := tlen;
END;
frag := Network.GetNet2(buffer.data, buffer.ofs+6);
IF (frag = 0) OR (frag = 4000H) THEN
IF hlen # MinIPHdrLen THEN
Machine.AtomicInc(IP.NIPOptions);
END;
isValid := TRUE;
ELSE
Machine.AtomicInc(IP.NIPCantReassemble)
END
ELSE
Machine.AtomicInc(IP.NIPBadLength)
END
ELSE
Machine.AtomicInc(IP.NIPBadChecksum)
END
ELSE
Machine.AtomicInc(IP.NIPBadHdrLen)
END
ELSE
Machine.AtomicInc(IP.NIPBadVersion)
END
ELSE
Machine.AtomicInc(IP.NIPTooSmall)
END;
RETURN isValid;
END IsIPPacketValid;
PROCEDURE IsARPPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
VAR
isValid: BOOLEAN;
BEGIN
isValid := FALSE;
Machine.AtomicInc(NARPRcvTotal);
IF buffer.len >= ARPPktLen THEN
IF Network.Equal(buffer.data, arpProto, buffer.ofs, 0, ARPHdrLen-1) THEN
isValid := TRUE;
ELSE
Machine.AtomicInc(NARPRcvIgnored)
END
ELSE
Machine.AtomicInc(NARPRcvTooSmall)
END;
RETURN isValid;
END IsARPPacketValid;
PROCEDURE GetNextID*(): INTEGER;
BEGIN {EXCLUSIVE}
INC(nextID);
RETURN nextID;
END GetNextID;
PROCEDURE Cleanup;
BEGIN
WHILE IP.interfaces # NIL DO
IP.interfaces.Close();
END;
END Cleanup;
BEGIN
nextID := 0;
minARPTime := MinARPTime * Kernel.second DIV 1000;
arpProto[0] := 0X; arpProto[1] := 1X;
arpProto[2] := CHR(EtherTypeIP DIV 100H);
arpProto[3] := CHR(EtherTypeIP MOD 100H);
arpProto[4] := 6X; arpProto[5] := 4X;
arpProto[6] := 0X; arpProto[7] := 0X;
Modules.InstallTermHandler(Cleanup);
END IPv4.
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 Created.