MODULE IPv6;
IMPORT SYSTEM, Machine, Kernel, Objects, Modules, Strings, KernelLog, Network, IP, Plugins;
CONST
DEBUG = TRUE;
EtherTypeIP* = 86DDH;
MinIPHdrLen*= 40;
MaxIPHdrLen* = 40;
MaxFragPacketSize* = 65536;
V6RouterIntName = "v6Router";
V6OwnRouterIntName = "v6OwnRouter";
V6DHCPIntName = "v6DHCP";
CacheSize = 256;
Incomplete = 0;
Reachable = 1;
Stale = 2;
Delay = 3;
Probe = 4;
ReachableTime = 30000;
TentativeInterface = 0;
PreferredInterface = 1;
DepricatedInterface = 2;
InvalidInterface = 3;
IPv6FragmentType = 44;
IPv6RoutingHdrType = 43;
IPv6HopByHopHdrType = 0;
IPv6DestinationHdrType = 60;
ICMPv6Type = 58;
NeighborHdrLen* = 20;
RouterSolHdrLen* = 4;
RouterAdvHdrLen = 12;
LLAdrOptionLen* = 8;
FragmentHdrLen = 8;
RoutingHdrLen = 8;
HopByHopHdrLen = 8;
DestinationHdrLen = 8;
MaxPrefixOptions = 10;
ShortTimerTimeout = 3000;
LongTimerTimeout = 600000;
ICMPv6CodeHopLimitExc* = 0;
ICMPv6FragmentReassemblyExc* = 3;
MaxRtrAdvInterval = 600000;
MinRtrAdvInterval = 198000;
RouterPrefHigh = 1;
RouterPrefMedium = 0;
RouterPrefLow = 3;
TYPE
FragmentList = POINTER TO RECORD
fragmentID: LONGINT;
nextHeader: LONGINT;
srcAdr: IP.Adr;
dstAdr: IP.Adr;
packets: PacketFragment;
startedAt: Kernel.MilliTimer;
fragmentCount: LONGINT;
next: FragmentList;
END;
PacketFragment = POINTER TO RECORD
buffer: Network.Buffer;
fragmentOffset: LONGINT;
moreFragments: BOOLEAN;
next: PacketFragment;
prev: PacketFragment;
END;
DeviceList = POINTER TO RECORD
device: Network.LinkDevice;
linkLocalInterface: Interface;
next: DeviceList;
END;
RouterConfig* = POINTER TO RECORD
Device*: Plugins.Name;
SendRouterAdvertisements*: BOOLEAN;
ManagedAddressConfig*: BOOLEAN;
OtherStatefulConfig*: BOOLEAN;
LinkMTU*: LONGINT;
ReachableTime*: LONGINT;
RetransTimer*: LONGINT;
CurrentHopLimit*: LONGINT;
Lifetime*: LONGINT;
Prefixes*: PrefixConfig;
next*: RouterConfig;
END;
PrefixConfig* = POINTER TO RECORD
Prefix*: IP.Adr;
IsSitePrefix*: BOOLEAN;
ValidLifetime*: LONGINT;
OnLink*: BOOLEAN;
PreferredLifetime*: LONGINT;
Autonomous*: BOOLEAN;
next*: PrefixConfig;
END;
PacketQueue = POINTER TO RECORD
l3hdr: POINTER TO ARRAY OF CHAR;
l4hdr: POINTER TO ARRAY OF CHAR;
data: POINTER TO ARRAY OF CHAR;
h3len: LONGINT;
h4len: LONGINT;
dofs: LONGINT;
dlen: LONGINT;
next: PacketQueue;
END;
NeighborCacheEntry* = POINTER TO RECORD
next: NeighborCacheEntry;
neighborIP: IP.Adr;
linkAdr: Network.LinkAdr;
reachability: LONGINT;
isRouter: BOOLEAN;
queuedPackets: PacketQueue;
probes: LONGINT;
lastConfirmation: Kernel.MilliTimer;
END;
DestCacheEntry = POINTER TO RECORD
next: DestCacheEntry;
dest: IP.Adr;
nextHop: IP.Adr;
pmtu: LONGINT;
END;
PrefixesEntry = POINTER TO RECORD
next: PrefixesEntry;
prefix: IP.Adr;
lifetime: Kernel.MilliTimer;
END;
RoutersEntry = POINTER TO RECORD
next: RoutersEntry;
router: NeighborCacheEntry;
routerLifetime: Kernel.MilliTimer;
END;
LocalAdrCacheEntry = POINTER TO RECORD
next: LocalAdrCacheEntry;
localAdr: IP.Adr;
interface: Interface;
created: Kernel.MilliTimer;
END;
TYPE
DestCache = OBJECT
VAR
destArray: ARRAY CacheSize OF DestCacheEntry;
interface: Interface;
PROCEDURE &Constr*(int: Interface; prefixes: Prefixes);
VAR
i: LONGINT;
BEGIN
FOR i := 0 TO 255 DO
destArray[i] := NIL;
END;
interface := int;
END Constr;
PROCEDURE Add(destAdr, nextHop: IP.Adr);
VAR
newDestItem: DestCacheEntry;
destItem: DestCacheEntry;
BEGIN {EXCLUSIVE}
destItem := destArray[ORD(destAdr.ipv6Adr[15])];
WHILE (destItem # NIL) & (~IP.AdrsEqual(destItem.dest, destAdr)) DO
destItem := destItem.next;
END;
IF destItem = NIL THEN
NEW(newDestItem);
newDestItem.next := NIL;
newDestItem.dest := destAdr;
newDestItem.nextHop := nextHop;
newDestItem.pmtu := interface.linkMTU;
destItem := destArray[ORD(destAdr.ipv6Adr[15])];
IF destItem = NIL THEN
destArray[ORD(destAdr.ipv6Adr[15])] := newDestItem;
ELSE
WHILE destItem.next # NIL DO
destItem := destItem.next;
END;
destItem.next := newDestItem;
END;
END;
END Add;
PROCEDURE Remove(destAdr: IP.Adr);
VAR
destItem: DestCacheEntry;
BEGIN {EXCLUSIVE}
destItem := destArray[ORD(destAdr.ipv6Adr[15])];
IF destItem # NIL THEN
IF IP.AdrsEqual(destItem.dest, destAdr) THEN
destArray[ORD(destAdr.ipv6Adr[15])] := destItem.next;
ELSIF destItem.next # NIL THEN
WHILE (destItem.next.next # NIL) & (~IP.AdrsEqual(destItem.next.dest, destAdr)) DO
destItem := destItem.next;
END;
IF destItem.next # NIL THEN
destItem.next := destItem.next.next;
END;
END;
END;
END Remove;
PROCEDURE ChangePMTU(adr: IP.Adr; newPMTU: LONGINT);
VAR
destItem: DestCacheEntry;
BEGIN
destItem := destArray[ORD(adr.ipv6Adr[15])];
IF destItem # NIL THEN
WHILE (destItem # NIL) & (~IP.AdrsEqual(destItem.dest, adr)) DO
destItem := destItem.next;
END;
IF destItem # NIL THEN
destItem.pmtu := newPMTU;
END;
END;
END ChangePMTU;
PROCEDURE GetNextHop(destAdr: IP.Adr): IP.Adr;
VAR
nextHop: IP.Adr;
destItem: DestCacheEntry;
BEGIN
IF interface.IsMulticast(destAdr) THEN
nextHop := destAdr;
ELSE
nextHop := IP.NilAdr;
destItem := destArray[ORD(destAdr.ipv6Adr[15])];
WHILE (destItem # NIL) & (~IP.AdrsEqual(destAdr, destItem.dest)) DO
destItem := destItem.next;
END;
IF destItem # NIL THEN
nextHop := destItem.nextHop;
ELSE
nextHop := NextHopDetermination(destAdr);
IF IP.IsNilAdr(nextHop) THEN
nextHop := destAdr;
END;
Add(destAdr, nextHop);
END;
END;
RETURN nextHop;
END GetNextHop;
PROCEDURE GetPMTU(adr: IP.Adr): LONGINT;
VAR
destItem: DestCacheEntry;
pmtu: LONGINT;
BEGIN
destItem := destArray[ORD(adr.ipv6Adr[15])];
WHILE (destItem # NIL) & (~IP.AdrsEqual(adr, destItem.dest)) DO
destItem := destItem.next;
END;
IF destItem # NIL THEN
pmtu := destItem.pmtu;
ELSE
pmtu := interface.linkMTU;
END;
RETURN pmtu;
END GetPMTU;
PROCEDURE NextHopDetermination(destAdr: IP.Adr): IP.Adr;
VAR
longestPrefix: PrefixesEntry;
nextHop: IP.Adr;
BEGIN
longestPrefix := interface.prefixes.FindLongestMatch(destAdr);
IF longestPrefix = NIL THEN
nextHop := interface.routers.GetRouter();
IF IP.IsNilAdr(nextHop) THEN
nextHop := destAdr;
END;
ELSE
nextHop := destAdr;
END;
RETURN nextHop;
END NextHopDetermination;
PROCEDURE ChangeDests(fromAdr: IP.Adr; toAdr: IP.Adr);
VAR
destItem: DestCacheEntry;
i: LONGINT;
BEGIN
FOR i := 0 TO CacheSize DO
destItem := destArray[i];
WHILE destItem # NIL DO
IF IP.AdrsEqual(fromAdr, destItem.dest) THEN
destItem.dest := toAdr;
END;
destItem := destItem.next;
END;
END;
END ChangeDests;
PROCEDURE Clear;
VAR
i: LONGINT;
BEGIN
FOR i := 0 TO CacheSize - 1 DO
destArray[i] := NIL;
END;
END Clear;
END DestCache;
TYPE
NeighborCache = OBJECT
VAR
neighbors: ARRAY CacheSize OF NeighborCacheEntry;
interface: Interface;
PROCEDURE &Constr *(int: Interface);
VAR
i: LONGINT;
BEGIN
interface := int;
FOR i := 0 TO (CacheSize - 1) DO
neighbors[i] := NIL;
END;
END Constr;
PROCEDURE Add(neighborIP: IP.Adr);
VAR
newNeighborEntry: NeighborCacheEntry;
neighborItem: NeighborCacheEntry;
BEGIN {EXCLUSIVE}
newNeighborEntry := Get(neighborIP);
IF newNeighborEntry = NIL THEN
NEW(newNeighborEntry);
newNeighborEntry.next := NIL;
newNeighborEntry.neighborIP := neighborIP;
newNeighborEntry.reachability := Incomplete;
newNeighborEntry.isRouter := FALSE;
newNeighborEntry.queuedPackets := NIL;
newNeighborEntry.probes := 0;
Kernel.SetTimer(newNeighborEntry.lastConfirmation, 0);
neighborItem := neighbors[ORD(neighborIP.ipv6Adr[15])];
IF neighborItem = NIL THEN
neighbors[ORD(neighborIP.ipv6Adr[15])] := newNeighborEntry;
ELSE
WHILE (neighborItem.next # NIL) DO
neighborItem := neighborItem.next
END;
neighborItem.next := newNeighborEntry;
END;
END;
END Add;
PROCEDURE Remove(neighborIP: IP.Adr);
VAR
neighborItem: NeighborCacheEntry;
BEGIN {EXCLUSIVE}
neighborItem := neighbors[ORD(neighborIP.ipv6Adr[15])];
IF IP.AdrsEqual(neighborItem.neighborIP, neighborIP) THEN
neighbors[ORD(neighborIP.ipv6Adr[15])] := neighborItem.next;
ELSE
WHILE (neighborItem.next # NIL) & (~IP.AdrsEqual(neighborItem.neighborIP, neighborIP)) DO
neighborItem := neighborItem.next;
END;
IF neighborItem.next # NIL THEN
neighborItem.next := neighborItem.next.next;
END;
END;
END Remove;
PROCEDURE ClearExpired;
VAR
neighborItem: NeighborCacheEntry;
neighborItemPrev: NeighborCacheEntry;
i: LONGINT;
BEGIN {EXCLUSIVE}
FOR i := 0 TO CacheSize - 1 DO
neighborItem := neighbors[i];
WHILE neighborItem # NIL DO
IF Kernel.Expired(neighborItem.lastConfirmation) THEN
IF neighborItemPrev = NIL THEN
neighbors[i] := neighborItem.next;
ELSE
neighborItemPrev.next := neighborItem.next;
END;
END;
IF (neighborItem.next # NIL) & (neighborItem.next # neighbors[i]) THEN
neighborItemPrev := neighborItem;
ELSE
neighborItemPrev := NIL;
END;
neighborItem := neighborItem.next;
END;
END;
END ClearExpired;
PROCEDURE Get*(adr: IP.Adr): NeighborCacheEntry;
VAR
neighborItem: NeighborCacheEntry;
BEGIN
neighborItem := neighbors[ORD(adr.ipv6Adr[15])];
WHILE (neighborItem # NIL) & (~IP.AdrsEqual(neighborItem.neighborIP, adr)) DO
neighborItem := neighborItem.next;
END;
RETURN neighborItem;
END Get;
PROCEDURE GetLinkLayerAdr(adr: IP.Adr; VAR linkAdr: Network.LinkAdr): BOOLEAN;
VAR
neighborItem: NeighborCacheEntry;
found: BOOLEAN;
BEGIN
neighborItem := neighbors[ORD(adr.ipv6Adr[15])];
WHILE (neighborItem # NIL) & (~IP.AdrsEqual(neighborItem.neighborIP, adr)) DO
neighborItem := neighborItem.next;
END;
IF (neighborItem # NIL) & (neighborItem.reachability # Incomplete) THEN
IF Kernel.Expired(neighborItem.lastConfirmation) THEN
sendNeighborSolicitation(interface, neighborItem.linkAdr, adr, FALSE);
END;
linkAdr := neighborItem.linkAdr;
found := TRUE;
ELSE
found := FALSE;
END;
RETURN found;
END GetLinkLayerAdr;
PROCEDURE AddressResolution(neighborIP: IP.Adr; VAR l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
VAR
neighborEntry: NeighborCacheEntry;
packetQueue: PacketQueue;
packetQueueItem: PacketQueue;
linkDst: Network.LinkAdr;
i: LONGINT;
BEGIN
Add(neighborIP);
neighborEntry := Get(neighborIP);
IF neighborEntry # NIL THEN
NEW(packetQueueItem);
NEW(packetQueueItem.l3hdr, LEN(l3hdr));
FOR i := 0 TO LEN(l3hdr) - 1 DO
packetQueueItem.l3hdr[i] := l3hdr[i];
END;
NEW(packetQueueItem.l4hdr, LEN(l4hdr));
FOR i := 0 TO LEN(l4hdr) - 1 DO
packetQueueItem.l4hdr[i] := l4hdr[i];
END;
NEW(packetQueueItem.data, LEN(data));
FOR i := 0 TO LEN(data) - 1 DO
packetQueueItem.data[i] := data[i];
END;
packetQueueItem.h3len := h3len;
packetQueueItem.h4len := h4len;
packetQueueItem.dofs := dofs;
packetQueueItem.dlen := dlen;
packetQueue := neighborEntry.queuedPackets;
packetQueueItem.next := packetQueue;
neighborEntry.queuedPackets := packetQueueItem;
linkDst := linkMulticastAllNodesAdr;
linkDst[2] := 0FFX;
linkDst[3] := neighborIP.ipv6Adr[13];
linkDst[4] := neighborIP.ipv6Adr[14];
linkDst[5] := neighborIP.ipv6Adr[15];
sendNeighborSolicitation(interface, linkDst, neighborIP, TRUE);
END;
END AddressResolution;
PROCEDURE SendQueuedPackets(neighborCacheEntry: NeighborCacheEntry);
VAR
queuedPacket: PacketQueue;
pmtu: LONGINT;
toFragment: BOOLEAN;
BEGIN {EXCLUSIVE}
toFragment := FALSE;
queuedPacket := neighborCacheEntry.queuedPackets;
WHILE queuedPacket # NIL DO
pmtu := interface.destCache.GetPMTU(neighborCacheEntry.neighborIP);
IF queuedPacket.h3len+queuedPacket.h4len+queuedPacket.dlen > pmtu THEN
toFragment := TRUE;
END;
IF ~toFragment THEN
interface.dev.Send(neighborCacheEntry.linkAdr,
EtherTypeIP,
queuedPacket.l3hdr^,
queuedPacket.l4hdr^,
queuedPacket.data^,
queuedPacket.h3len,
queuedPacket.h4len,
queuedPacket.dofs,
queuedPacket.dlen,
FALSE);
ELSE
interface.DoFragAndSend(pmtu,
neighborCacheEntry.linkAdr,
queuedPacket.l3hdr^,
queuedPacket.l4hdr^,
queuedPacket.data^,
queuedPacket.h3len,
queuedPacket.h4len,
queuedPacket.dofs,
queuedPacket.dlen);
END;
queuedPacket := queuedPacket.next;
END;
neighborCacheEntry.queuedPackets := NIL;
END SendQueuedPackets;
END NeighborCache;
TYPE
Prefixes = OBJECT
VAR
prefixes: PrefixesEntry;
PROCEDURE &Constr*;
BEGIN
prefixes := NIL;
END Constr;
PROCEDURE Add(prefix: IP.Adr; lifetime: LONGINT);
VAR
prefixItem: PrefixesEntry;
BEGIN {EXCLUSIVE}
NEW(prefixItem);
prefixItem.prefix := prefix;
Kernel.SetTimer(prefixItem.lifetime, lifetime * 1000);
prefixItem.next := prefixes;
prefixes := prefixItem;
END Add;
PROCEDURE Remove(prefix: IP.Adr);
VAR
prefixItem: PrefixesEntry;
BEGIN {EXCLUSIVE}
prefixItem := prefixes;
IF prefixItem # NIL THEN
IF IP.AdrsEqual(prefix, prefixItem.prefix) THEN
prefixes := prefixItem.next;
ELSE
WHILE (prefixItem.next # NIL) & (~IP.AdrsEqual(prefix, prefixItem.next.prefix)) DO
prefixItem := prefixItem.next;
END;
IF prefixItem # NIL THEN
prefixItem.next := prefixItem.next.next;
END;
END;
END;
END Remove;
PROCEDURE ClearExpired;
VAR
prefixItem: PrefixesEntry;
prefixItemPrev: PrefixesEntry;
BEGIN {EXCLUSIVE}
prefixItem := prefixes;
WHILE prefixItem # NIL DO
IF Kernel.Expired(prefixItem.lifetime) THEN
IF prefixItemPrev = NIL THEN
prefixes := prefixItem.next;
ELSE
prefixItemPrev.next := prefixItem.next;
END;
END;
IF (prefixItem.next # NIL) & (prefixItem.next # prefixes) THEN
prefixItemPrev := prefixItem;
ELSE
prefixItemPrev := NIL;
END;
prefixItem := prefixItem.next;
END;
END ClearExpired;
PROCEDURE Get(prefix: IP.Adr): PrefixesEntry;
VAR
prefixItem: PrefixesEntry;
BEGIN
prefixItem := prefixes;
WHILE ((prefixItem # NIL) & (~IP.AdrsEqual(prefix, prefixItem.prefix)) & (~(prefix.data = prefixItem.prefix.data))) DO
prefixItem := prefixItem.next;
END;
RETURN prefixItem;
END Get;
PROCEDURE FindLongestMatch(adr: IP.Adr): PrefixesEntry;
VAR
prefixItem: PrefixesEntry;
longestPrefixItem: PrefixesEntry;
longestPrefix: LONGINT;
BEGIN
prefixItem := prefixes;
longestPrefixItem := NIL;
longestPrefix := 0;
WHILE (prefixItem # NIL) DO
IF IP.MatchPrefix (adr, prefixItem.prefix) THEN
IF prefixItem.prefix.data > longestPrefix THEN
longestPrefix := prefixItem.prefix.data;
longestPrefixItem := prefixItem;
END;
END;
prefixItem := prefixItem.next;
END;
IF longestPrefixItem # NIL THEN
RETURN longestPrefixItem;
END;
RETURN NIL;
END FindLongestMatch;
END Prefixes;
TYPE
Routers = OBJECT
VAR
routers: RoutersEntry;
lastRobinRouter: RoutersEntry;
interface: Interface;
PROCEDURE &Constr*(int: Interface);
BEGIN
routers := NIL;
lastRobinRouter := routers;
interface := int;
END Constr;
PROCEDURE Add(routerIP: IP.Adr; routerLinkAdr: Network.LinkAdr; lifetime: LONGINT): RoutersEntry;
VAR
router: RoutersEntry;
neighbor: NeighborCacheEntry;
BEGIN {EXCLUSIVE}
lifetime := lifetime * 1000;
router := Get(routerIP);
IF router = NIL THEN
NEW(router);
router.next := routers;
routers := router;
END;
Kernel.SetTimer(router.routerLifetime, lifetime);
neighbor := interface.neighborCache.Get(routerIP);
IF neighbor = NIL THEN
interface.neighborCache.Add(routerIP);
neighbor := interface.neighborCache.Get(routerIP);
neighbor.linkAdr := routerLinkAdr;
neighbor.reachability := Stale;
neighbor.isRouter := TRUE;
neighbor.probes := 0;
Kernel.SetTimer(neighbor.lastConfirmation, lifetime);
ELSE
Kernel.SetTimer(neighbor.lastConfirmation, lifetime);
END;
router.router := neighbor;
RETURN router;
END Add;
PROCEDURE Remove(router: IP.Adr);
VAR
routerItem: RoutersEntry;
routerItemPrev: RoutersEntry;
BEGIN {EXCLUSIVE}
routerItem := routers;
WHILE (routerItem # NIL) & (~IP.AdrsEqual(routerItem.router.neighborIP, router)) DO
routerItemPrev := routerItem;
routerItem := routerItem.next;
END;
IF routerItem # NIL THEN
IF routerItemPrev = NIL THEN
routers := routerItem.next;
ELSE
routerItemPrev.next := routerItem.next;
END;
END;
END Remove;
PROCEDURE Get(routerIP: IP.Adr): RoutersEntry;
VAR
item: RoutersEntry;
BEGIN
item := routers;
WHILE (item # NIL) & (~IP.AdrsEqual(item.router.neighborIP, routerIP)) DO
item := item.next;
END;
RETURN item;
END Get;
PROCEDURE GetRouter(): IP.Adr;
VAR
routersItem: RoutersEntry;
routerAdr: IP.Adr;
searchReachable: BOOLEAN;
BEGIN
routerAdr := IP.NilAdr;
IF routers # NIL THEN
IF lastRobinRouter = NIL THEN
lastRobinRouter := routers;
END;
routersItem := lastRobinRouter.next;
IF routersItem = NIL THEN
routersItem := routers.next;
END;
searchReachable := TRUE;
LOOP
IF routersItem = NIL THEN
routersItem := routers;
END;
IF (routersItem = lastRobinRouter) & ~searchReachable THEN
IF routersItem.router.reachability # Incomplete THEN
routerAdr := routersItem.router.neighborIP;
ELSE
lastRobinRouter := NIL;
routerAdr := IP.NilAdr;
EXIT;
END;
END;
IF (routersItem = lastRobinRouter) & searchReachable THEN
searchReachable := FALSE;
IF routersItem.router.reachability = Reachable THEN
EXIT;
END;
routersItem := routersItem.next;
IF routersItem = NIL THEN
routersItem := routers;
END;
END;
IF searchReachable & (routersItem.router.reachability = Reachable) THEN
routerAdr := routersItem.router.neighborIP;
lastRobinRouter := routersItem;
EXIT;
END;
IF ~searchReachable & (routersItem.router.reachability # Incomplete) THEN
routerAdr := routersItem.router.neighborIP;
lastRobinRouter := routersItem;
EXIT;
END;
routersItem := routersItem.next;
END;
END;
RETURN routerAdr;
END GetRouter;
PROCEDURE ClearExpired;
VAR
routerItem: RoutersEntry;
routerItemPrev: RoutersEntry;
BEGIN {EXCLUSIVE}
routerItem := routers;
WHILE routerItem # NIL DO
IF Kernel.Expired(routerItem.routerLifetime) THEN
IF routerItemPrev = NIL THEN
routers := routerItem.next;
ELSE
routerItemPrev.next := routerItem.next;
END;
END;
IF (routerItem.next # NIL) & (routerItem.next # routers) THEN
routerItemPrev := routerItem;
ELSE
routerItemPrev := NIL;
END;
routerItem := routerItem.next;
END;
END ClearExpired;
PROCEDURE OutRouters;
VAR
item: RoutersEntry;
BEGIN
KernelLog.String("Default routers:"); KernelLog.Ln;
item := routers;
WHILE item # NIL DO
IP.OutAdr(item.router.neighborIP); KernelLog.Ln;
item := item.next;
END;
END OutRouters;
END Routers;
TYPE
LocalAdrCache = OBJECT
VAR
localAdrs: ARRAY CacheSize OF LocalAdrCacheEntry;
PROCEDURE &Constr*;
VAR
i: LONGINT;
BEGIN
FOR i := 0 TO (CacheSize - 1) DO
localAdrs[i] := NIL;
END;
END Constr;
PROCEDURE Add(localIP: IP.Adr; interface: Interface);
VAR
newLocalAdrEntry: LocalAdrCacheEntry;
localAdrItem: LocalAdrCacheEntry;
BEGIN {EXCLUSIVE}
newLocalAdrEntry := Get(localIP);
IF newLocalAdrEntry = NIL THEN
NEW(newLocalAdrEntry);
newLocalAdrEntry.next := NIL;
newLocalAdrEntry.localAdr := localIP;
newLocalAdrEntry.interface := interface;
Kernel.SetTimer(newLocalAdrEntry.created, LongTimerTimeout);
localAdrItem := localAdrs[ORD(localIP.ipv6Adr[15])];
IF localAdrItem = NIL THEN
localAdrs[ORD(localIP.ipv6Adr[15])] := newLocalAdrEntry;
ELSE
WHILE (localAdrItem.next # NIL) DO
localAdrItem := localAdrItem.next
END;
localAdrItem.next := newLocalAdrEntry;
END;
END;
END Add;
PROCEDURE Remove(localIP: IP.Adr);
VAR
localAdrItem: LocalAdrCacheEntry;
BEGIN {EXCLUSIVE}
localAdrItem := localAdrs[ORD(localIP.ipv6Adr[15])];
IF IP.AdrsEqual(localAdrItem.localAdr, localIP) THEN
localAdrs[ORD(localIP.ipv6Adr[15])] := localAdrItem.next;
ELSE
WHILE (localAdrItem.next # NIL) & (~IP.AdrsEqual(localAdrItem.localAdr, localIP)) DO
localAdrItem := localAdrItem.next;
END;
IF localAdrItem.next # NIL THEN
localAdrItem.next := localAdrItem.next.next;
END;
END;
END Remove;
PROCEDURE ClearExpired;
VAR
localAdrItem: LocalAdrCacheEntry;
localAdrItemPrev: LocalAdrCacheEntry;
i: LONGINT;
BEGIN {EXCLUSIVE}
FOR i := 0 TO CacheSize - 1 DO
localAdrItem := localAdrs[i];
WHILE localAdrItem # NIL DO
IF Kernel.Expired(localAdrItem.created) THEN
IF localAdrItemPrev = NIL THEN
localAdrs[i] := localAdrItem.next;
ELSE
localAdrItemPrev.next := localAdrItem.next;
END;
END;
IF (localAdrItem.next # NIL) & (localAdrItem.next # localAdrs[i]) THEN
localAdrItemPrev := localAdrItem;
ELSE
localAdrItemPrev := NIL;
END;
localAdrItem := localAdrItem.next;
END;
END;
END ClearExpired;
PROCEDURE Get*(localAdr: IP.Adr): LocalAdrCacheEntry;
VAR
localAdrItem: LocalAdrCacheEntry;
BEGIN
localAdrItem := localAdrs[ORD(localAdr.ipv6Adr[15])];
WHILE (localAdrItem # NIL) & (~IP.AdrsEqual(localAdrItem.localAdr, localAdr)) DO
localAdrItem := localAdrItem.next;
END;
RETURN localAdrItem;
END Get;
PROCEDURE GetInterface*(localAdr: IP.Adr): Interface;
VAR
localAdrItem: LocalAdrCacheEntry;
BEGIN
localAdrItem := localAdrs[ORD(localAdr.ipv6Adr[15])];
WHILE (localAdrItem # NIL) & (~IP.AdrsEqual(localAdrItem.localAdr, localAdr)) DO
localAdrItem := localAdrItem.next;
END;
IF localAdrItem # NIL THEN
RETURN localAdrItem.interface;
ELSE
RETURN NIL;
END;
END GetInterface;
END LocalAdrCache;
TYPE
Interface* = OBJECT (IP.Interface)
VAR
destCache: DestCache;
neighborCache: NeighborCache;
prefixes: Prefixes;
routers: Routers;
linkMTU: LONGINT;
curHopLimit*: LONGINT;
linkMulticastSolicited: Network.LinkAdr;
linkLocalSolicitedNodeAdr: IP.Adr;
autoconfigurated*: BOOLEAN;
autoconfigState: LONGINT;
createStatelessInterface*: BOOLEAN;
createStatefulInterface: BOOLEAN;
routerSolCount: LONGINT;
shortTimer: Kernel.Timer;
longTimer: Kernel.MilliTimer;
duplicateTimer: Kernel.MilliTimer;
intName: IP.Name;
intv6: Interface;
int: IP.Interface;
res: LONGINT;
fragmentList: FragmentList;
isRouter*: BOOLEAN;
routerConfig: RouterConfig;
nextRtrAdvertisement: LONGINT;
PROCEDURE &Constr*(name: IP.Name; dev: Network.LinkDevice; VAR res: LONGINT);
VAR
devListItem: DeviceList;
BEGIN
ASSERT(dev # NIL);
SELF.dev := dev;
protocol := IP.IPv6;
autoconfigurated := FALSE;
autoconfigState := TentativeInterface;
createStatelessInterface := FALSE;
createStatefulInterface := FALSE;
routerSolCount := 0;
fragmentList := NIL;
isRouter := FALSE;
routerConfig:= NIL;
nextRtrAdvertisement := 0;
NEW(prefixes);
NEW(routers, SELF);
NEW(destCache, SELF, prefixes);
NEW(neighborCache, SELF);
IF name = "" THEN
res := IP.NoInterfaceName;
RETURN;
END;
COPY(name, SELF.name);
localAdr := IP.NilAdr;
maskAdr := IP.NilAdr;
gatewayAdr := IP.NilAdr;
subnetAdr := IP.NilAdr;
linkLocalSolicitedNodeAdr := IP.NilAdr;
broadAdr := IP.NilAdr;
broadAdr.usedProtocol := IP.IPv6;
broadAdr.ipv6Adr[0] := 0FFX;
broadAdr.ipv6Adr[1] := 2X;
broadAdr.ipv6Adr[15] := 1X;
broadAdr.data := 0;
DNScount := 0;
closed := FALSE;
IP.AddInterface(SELF, res);
IF res = IP.Ok THEN
dev.InstallReceiver(SELF, EtherTypeIP, IPInput, IsPacketValid, IsPacketForSingleInt, IsPacketAccepted
, IP.IPForwarding);
devListItem := devList;
WHILE (devListItem # NIL) & (devListItem.device # dev) DO
devListItem := devListItem.next;
END;
IF devListItem = NIL THEN
NEW(devListItem);
devListItem.device := dev;
devListItem.next := devList;
devList := devListItem;
END;
ELSE
closed := TRUE;
END;
END Constr;
PROCEDURE Close*;
VAR
i: LONGINT;
BEGIN {EXCLUSIVE}
ASSERT(~closed);
dev.RemoveReceiver(SELF, EtherTypeIP);
closed := TRUE;
shortTimer.Wakeup;
FOR i := 0 TO 9999 DO
Objects.Yield;
END;
IP.RemoveInterface(SELF);
END Close;
PROCEDURE SetAdrs*(localAdr, prefixAdr, defaultRouterAdr: IP.Adr; VAR res: LONGINT);
VAR
devListItem: DeviceList;
BEGIN {EXCLUSIVE}
IF DEBUG THEN
ASSERT ((IP.IsNilAdr(localAdr)) OR (localAdr.usedProtocol = 6), 2345);
ASSERT ((IP.IsNilAdr(prefixAdr)) OR (prefixAdr.usedProtocol = 6), 2345);
END;
IF (~IP.IsNilAdr(localAdr)) THEN
IF IP.IsNilAdr(prefixAdr) & ~(dev.name = "Loopback") THEN
res := IP.PrefixNotSet;
RETURN;
END;
IF dev.name = "Loopback" THEN
IF localAdr.usedProtocol # IP.IPv6 THEN
res := IP.IPv4AdrUsedOnIPv6Interface;
RETURN;
END;
ELSIF (localAdr.usedProtocol # IP.IPv6) OR (prefixAdr.usedProtocol # IP.IPv6) THEN
res := IP.IPv4AdrUsedOnIPv6Interface;
RETURN;
END;
SELF.localAdr := localAdr;
SELF.maskAdr := prefixAdr;
linkLocalSolicitedNodeAdr := IP.NilAdr;
linkLocalSolicitedNodeAdr.usedProtocol := IP.IPv6;
linkLocalSolicitedNodeAdr.ipv6Adr[0] := 0FFX;
linkLocalSolicitedNodeAdr.ipv6Adr[1] := 2X;
linkLocalSolicitedNodeAdr.ipv6Adr[11] := 1X;
linkLocalSolicitedNodeAdr.ipv6Adr[12] := 0FFX;
linkLocalSolicitedNodeAdr.ipv6Adr[13] := localAdr.ipv6Adr[13];
linkLocalSolicitedNodeAdr.ipv6Adr[14] := localAdr.ipv6Adr[14];
linkLocalSolicitedNodeAdr.ipv6Adr[15] := localAdr.ipv6Adr[15];
IF name # "Loopbackv6" THEN
Kernel.SetTimer(duplicateTimer, ShortTimerTimeout);
sendNeighborSolicitation(SELF, linkMulticastSolicited, linkLocalSolicitedNodeAdr, FALSE);
END;
res := IP.Ok;
IF IsLinkLocalAdr(localAdr) THEN
devListItem := devList;
WHILE (devListItem # NIL) & (devListItem.device # dev) DO
devListItem := devListItem.next;
END;
devListItem.linkLocalInterface := SELF;
END;
ELSE
END;
END SetAdrs;
PROCEDURE IPInput*(dev: Network.LinkDevice; type: LONGINT; buffer: Network.Buffer);
VAR
payloadLength: LONGINT;
nextHeader: LONGINT;
srcAdr: IP.Adr;
dstAdr: IP.Adr;
forwardInt: IP.Interface;
receiver: IP.Receiver;
incomingFragment: BOOLEAN;
forwardBuffer: Network.Buffer;
BEGIN
IF DEBUG THEN
ASSERT(type = EtherTypeIP);
ASSERT(dev = SELF.dev);
END;
incomingFragment := FALSE;
IF buffer.nextFragment = NIL THEN
payloadLength := Network.GetNet2(buffer.data, buffer.ofs+4);
nextHeader := ORD(buffer.data[buffer.ofs+6]);
ELSE
nextHeader := ORD(buffer.data[buffer.ofs]);
payloadLength := buffer.len - MinIPHdrLen;
END;
IF ((payloadLength + MinIPHdrLen) <= buffer.len) THEN
srcAdr := ReadSrcAdr (buffer);
dstAdr := ReadDestAdr (buffer);
IF (nextHeader = IPv6FragmentType) & (buffer.nextFragment = NIL) THEN
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
AddToFragmentList(srcAdr, dstAdr, buffer);
incomingFragment := TRUE;
END;
IF ~IsMulticast(srcAdr) & ~incomingFragment THEN
IF ~IsMulticast(dstAdr) THEN
IF (IP.AdrsEqual(dstAdr, localAdr)) THEN
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
buffer.l3ofs := buffer.ofs;
IF buffer.nextFragment # NIL THEN
INC(buffer.ofs, FragmentHdrLen);
DEC(buffer.len, FragmentHdrLen);
ELSE
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
END;
receiver(SELF, nextHeader, srcAdr, dstAdr, buffer);
Machine.AtomicInc(IP.NIPDelivered);
RETURN;
ELSE
Machine.AtomicInc(IP.NIPNoReceiver);
END;
ELSIF IP.IPForwarding THEN
IF nextHeader = IPv6RoutingHdrType THEN
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
dstAdr := ReadDestAdr (buffer);
END;
forwardInt := IP.InterfaceByDstIP(dstAdr);
IF forwardInt # NIL THEN
forwardBuffer := buffer;
WHILE forwardBuffer # NIL DO
IF ORD(forwardBuffer.data[7]) > 0 THEN
forwardBuffer.data[7] := CHR(ORD(forwardBuffer.data[7]) - 1);
forwardInt.DoSend(dstAdr,
forwardBuffer.data,
forwardBuffer.data,
forwardBuffer.data,
0,
0,
forwardBuffer.ofs,
forwardBuffer.len);
Machine.AtomicInc(IP.NIPForwarded);
ELSE
sendICMPv6TimeExceeded(SELF, forwardBuffer, srcAdr, ICMPv6CodeHopLimitExc);
END;
forwardBuffer := forwardBuffer.nextFragment;
END;
ELSE
Machine.AtomicInc(IP.NIPNotForUs)
END;
ELSE
Machine.AtomicInc(IP.NIPNotForUs);
END
ELSIF IsSolicitedNodeAdr(dstAdr) THEN
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
buffer.l3ofs := buffer.ofs;
IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
INC(buffer.ofs, FragmentHdrLen + MinIPHdrLen);
DEC(buffer.len, FragmentHdrLen + MinIPHdrLen);
ELSE
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
END;
receiver(SELF, nextHeader, srcAdr, dstAdr, buffer);
Machine.AtomicInc(IP.NIPDelivered);
RETURN;
ELSE
Machine.AtomicInc(IP.NIPNoReceiver);
END;
ELSIF ORD(dstAdr.ipv6Adr[15]) = 1 THEN
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
buffer.l3ofs := buffer.ofs;
IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
INC(buffer.ofs, FragmentHdrLen + MinIPHdrLen);
DEC(buffer.len, FragmentHdrLen + MinIPHdrLen);
ELSE
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
END;
receiver(SELF, nextHeader, srcAdr, dstAdr, buffer);
Machine.AtomicInc(IP.NIPDelivered);
RETURN;
ELSE
Machine.AtomicInc(IP.NIPNoReceiver);
END;
ELSIF IsMulticast(dstAdr) & (isRouter) & (ORD(dstAdr.ipv6Adr[15]) = 2) THEN
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
buffer.l3ofs := buffer.ofs;
IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
INC(buffer.ofs, FragmentHdrLen + MinIPHdrLen);
DEC(buffer.len, FragmentHdrLen + MinIPHdrLen);
ELSE
INC(buffer.ofs, MinIPHdrLen);
DEC(buffer.len, MinIPHdrLen);
END;
receiver(SELF, nextHeader, srcAdr, dstAdr, buffer);
Machine.AtomicInc(IP.NIPDelivered);
RETURN;
ELSE
Machine.AtomicInc(IP.NIPNoReceiver);
END;
ELSE
Machine.AtomicInc(IP.NIPNotForUs)
END;
ELSE
IF ~incomingFragment THEN
Machine.AtomicInc(IP.NIPSrcIsBroadcast)
END;
END;
ELSE
Machine.AtomicInc(IP.NIPBadLength)
END;
IF ~incomingFragment THEN
Network.ReturnBuffer(buffer);
END;
END IPInput;
PROCEDURE SendDirectly*(linkDst: Network.LinkAdr;
nextHeader: LONGINT;
destAdr: IP.Adr;
VAR l4hdr, data: ARRAY OF CHAR;
h4len, dofs, dlen, hopLimit: LONGINT);
VAR
l3hdr: ARRAY MaxIPHdrLen OF CHAR;
i: LONGINT;
BEGIN
IF DEBUG THEN
ASSERT (destAdr.usedProtocol = 6, 2345 );
END;
IF closed THEN
RETURN;
END;
l3hdr[0] := CHR(IP.IPv6*10H);
l3hdr[1] := 0X;
Network.Put2(l3hdr, 2, 0);
Network.PutNet2(l3hdr, 4, h4len+dlen);
l3hdr[6] := CHR(nextHeader);
l3hdr[7] := CHR(hopLimit);
FOR i := 0 TO 15 DO
l3hdr[i+8] := localAdr.ipv6Adr[i];
END;
FOR i := 0 TO 15 DO
l3hdr[i+24] := destAdr.ipv6Adr[i];
END;
DoSendDirectly(linkDst, destAdr, l3hdr, l4hdr, data, MinIPHdrLen, h4len, dofs, dlen);
END SendDirectly;
PROCEDURE DoSendDirectly*(linkDst: Network.LinkAdr;
destAdr: IP.Adr;
VAR l3hdr, l4hdr, data: ARRAY OF CHAR;
h3len, h4len, dofs, dlen: LONGINT) ;
BEGIN
ASSERT (destAdr.usedProtocol = 6, 2345);
IF h3len+h4len+dlen <= dev.mtu THEN
IF dev.type = Network.TypeEthernet THEN
IF IsNodeLocalAdr(destAdr) THEN
Machine.AtomicInc(IP.NIPSentLocalLoopback);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, TRUE);
ELSE
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
END;
ELSE
Machine.AtomicInc(IP.NIPSentPointToPoint);
dev.Send(linkDst,
EtherTypeIP,
l3hdr,
l4hdr,
data,
h3len,
h4len,
dofs,
dlen,
IP.AdrsEqual (destAdr, localAdr));
END;
END;
END DoSendDirectly;
PROCEDURE Send*(nextHeader: LONGINT; destAdr: IP.Adr; VAR l4hdr, data: ARRAY OF CHAR; h4len, dofs, dlen, hopLimit: LONGINT);
VAR
l3hdr: ARRAY MaxIPHdrLen OF CHAR;
i: LONGINT;
BEGIN
IF DEBUG THEN
ASSERT (destAdr.usedProtocol = 6, 2345 );
END;
IF closed THEN RETURN END;
l3hdr[0] := CHR(IP.IPv6*10H);
l3hdr[1] := 0X;
Network.Put2(l3hdr, 2, 0);
Network.PutNet2(l3hdr, 4, h4len+dlen);
l3hdr[6] := CHR(nextHeader);
l3hdr[7] := CHR(hopLimit);
FOR i := 0 TO 15 DO
l3hdr[i+8] := localAdr.ipv6Adr[i];
END;
FOR i := 0 TO 15 DO
l3hdr[i+24] := destAdr.ipv6Adr[i];
END;
DoSend(destAdr, 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;
nextHop: IP.Adr;
pmtu: LONGINT;
toFragment: BOOLEAN;
BEGIN
ASSERT (destAdr.usedProtocol = 6, 2345);
toFragment := FALSE;
pmtu := destCache.GetPMTU(destAdr);
pmtu := Strings.Min(pmtu, linkMTU);
pmtu := Strings.Min(pmtu, dev.mtu);
IF h3len+h4len+dlen > pmtu THEN
toFragment := TRUE;
END;
IF dev.type = Network.TypeEthernet THEN
IF IsNodeLocalAdr(destAdr) OR IsLinkLocalMulticastAdr(destAdr) OR IP.AdrsEqual(destAdr, localAdr) THEN
Machine.AtomicInc(IP.NIPSentLocalLoopback);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, TRUE);
ELSE
nextHop := destCache.GetNextHop(destAdr);
IF ~neighborCache.GetLinkLayerAdr(nextHop, linkDst) THEN
neighborCache.AddressResolution(nextHop, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen);
ELSE
IF ~toFragment THEN
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, FALSE);
ELSE
DoFragAndSend(pmtu, linkDst, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen);
END;
END;
END;
ELSE
Machine.AtomicInc(IP.NIPSentPointToPoint);
dev.Send(linkDst,
EtherTypeIP,
l3hdr,
l4hdr,
data,
h3len,
h4len,
dofs,
dlen,
IP.AdrsEqual (destAdr, localAdr));
END;
END DoSend;
PROCEDURE DoFragAndSend(pmtu: LONGINT; linkDst: Network.LinkAdr; l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
VAR
maxDataLen: LONGINT;
fragmentOffset: LONGINT;
oldNextHeader: LONGINT;
l4hdrFragment: POINTER TO ARRAY OF CHAR;
dataFragment: POINTER TO ARRAY OF CHAR;
fragmentHdrSet: SET;
fragID: LONGINT;
i: LONGINT;
BEGIN
fragID := GetFragmentID();
maxDataLen := pmtu - MinIPHdrLen - FragmentHdrLen;
DEC(maxDataLen, maxDataLen MOD 8);
fragmentOffset := 0;
oldNextHeader := ORD(l3hdr[6]);
l3hdr[6] := CHR(IPv6FragmentType);
NEW(l4hdrFragment, FragmentHdrLen);
fragmentHdrSet := {};
fragmentHdrSet := fragmentHdrSet + {0};
Network.PutNet4(l4hdrFragment^, 0, SYSTEM.VAL(LONGINT, fragmentHdrSet));
l4hdrFragment^[0] := CHR(oldNextHeader);
Network.PutNet4(l4hdrFragment^, 4, fragID);
NEW(dataFragment, maxDataLen);
FOR i := 0 TO h4len - 1 DO
dataFragment^[i] := l4hdr[i];
END;
FOR i := h4len TO maxDataLen - 1 DO
dataFragment^[i] := data[i-h4len + dofs];
END;
INC(fragmentOffset, maxDataLen - h4len + dofs);
Network.PutNet2(l3hdr, 4, maxDataLen + FragmentHdrLen);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdrFragment^, dataFragment^, h3len, FragmentHdrLen, 0, maxDataLen, FALSE);
WHILE fragmentOffset < h4len + dlen DO
IF fragmentOffset + maxDataLen > h4len + dlen THEN
fragmentHdrSet := SYSTEM.VAL(SET, SYSTEM.LSH((fragmentOffset - dofs + h4len) DIV 8, 3));
fragmentHdrSet := fragmentHdrSet - {0, 1, 2};
Network.PutNet4(l4hdrFragment^, 0, SYSTEM.VAL(LONGINT, fragmentHdrSet));
l4hdrFragment^[0] := CHR(oldNextHeader);
l4hdrFragment^[1] := 0X;
Network.PutNet4(l4hdrFragment^, 4, fragID);
FOR i := 0 TO dlen - fragmentOffset - 1 DO
dataFragment^[i] := data[i + fragmentOffset];
END;
Network.PutNet2(l3hdr, 4, dlen - fragmentOffset + FragmentHdrLen);
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdrFragment^, dataFragment^, h3len, FragmentHdrLen, 0, dlen - fragmentOffset, FALSE);
INC(fragmentOffset, maxDataLen);
ELSE
fragmentHdrSet := SYSTEM.VAL(SET, SYSTEM.LSH((fragmentOffset - dofs + h4len) DIV 8, 3));
fragmentHdrSet := fragmentHdrSet + {0} - {1,2};
Network.PutNet4(l4hdrFragment^, 0, SYSTEM.VAL(LONGINT, fragmentHdrSet));
l4hdrFragment^[0] := CHR(oldNextHeader);
l4hdrFragment^[1] := 0X;
Network.PutNet4(l4hdrFragment^, 4, fragID);
FOR i := 0 TO maxDataLen - 1 DO
dataFragment^[i] := data[i + fragmentOffset];
END;
dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdrFragment^, dataFragment^, h3len, FragmentHdrLen, 0, maxDataLen, FALSE);
INC(fragmentOffset, maxDataLen);
END;
END;
END DoFragAndSend;
PROCEDURE ARPEnumerate*(handle: IP.ARPHandler);
END ARPEnumerate;
PROCEDURE IsPacketAccepted(buffer: Network.Buffer): BOOLEAN;
VAR
i: LONGINT;
isAccepted: BOOLEAN;
BEGIN
isAccepted := TRUE;
IF ~IP.IsNilAdr(localAdr) THEN
IF ~((IsLinkLocalAdr(localAdr)) & (buffer.data[24] = 0FFX)) THEN
FOR i := 0 TO 15 DO
IF buffer.data[i+24] # localAdr.ipv6Adr[i] THEN
isAccepted := FALSE;
END;
END;
END;
END;
RETURN isAccepted;
END IsPacketAccepted;
PROCEDURE IsBroadcast*(adr: IP.Adr) : BOOLEAN;
BEGIN
RETURN IsMulticast (adr);
END IsBroadcast;
PROCEDURE IsMulticast*(adr: IP.Adr) : BOOLEAN;
BEGIN
IF adr.ipv6Adr[0] = 0FFX THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END IsMulticast;
PROCEDURE IsSolicitedNodeAdr(adr: IP.Adr): BOOLEAN;
VAR
isSolicitedNode: BOOLEAN;
BEGIN
isSolicitedNode := TRUE;
IF ~AdrsPartEqual(linkLocalMulticastNodeAdr, adr, 0, 1) THEN
isSolicitedNode := FALSE;
END;
IF ~AdrsPartEqual(IP.NilAdr, adr, 2, 10) THEN
isSolicitedNode := FALSE;
END;
IF ~((adr.ipv6Adr[11] = 1X) & (adr.ipv6Adr[12] = 0FFX)) THEN
isSolicitedNode := FALSE;
END;
IF ~AdrsPartEqual(localAdr, adr, 13, 15) THEN
isSolicitedNode := FALSE
END;
RETURN isSolicitedNode;
END IsSolicitedNodeAdr;
PROCEDURE IsNodeLocalAdr (adr: IP.Adr): BOOLEAN;
VAR
isNodeLocal: BOOLEAN;
BEGIN
isNodeLocal := FALSE;
IF (IP.AdrsEqual(adr, localAdr)) OR (IP.AdrsEqual(adr, nodeLocalMulticastNodeAdr)) THEN
isNodeLocal := TRUE;
END;
RETURN isNodeLocal;
END IsNodeLocalAdr;
PROCEDURE ReadSrcAdr* (buffer: Network.Buffer): IP.Adr;
VAR
i: LONGINT;
retAdr: IP.Adr;
BEGIN
retAdr.usedProtocol := IP.IPv6;
FOR i := 0 TO 15 DO
retAdr.ipv6Adr[i] := buffer.data[i+8];
END;
RETURN retAdr;
END ReadSrcAdr;
PROCEDURE ReadDestAdr* (buffer: Network.Buffer):IP. Adr;
VAR
i: LONGINT;
retAdr: IP.Adr;
BEGIN
retAdr.usedProtocol := IP.IPv6;
FOR i := 0 TO 15 DO
retAdr.ipv6Adr[i] := buffer.data[i+24];
END;
RETURN retAdr;
END ReadDestAdr;
PROCEDURE SetInterfaceID*(VAR ip: IP.Adr);
VAR
bitSet: SET;
BEGIN
ip.usedProtocol := IP.IPv6;
ip.ipv6Adr[13] := dev.local[3];
ip.ipv6Adr[14] := dev.local[4];
ip.ipv6Adr[15] := dev.local[5];
ip.ipv6Adr[11] := 0FFX;
ip.ipv6Adr[12] := 0FEX;
ip.ipv6Adr[8] := dev.local[0];
ip.ipv6Adr[9] := dev.local[1];
ip.ipv6Adr[10] := dev.local[2];
bitSet := SYSTEM.VAL(SET, ip.ipv6Adr[8]);
IF 1 IN bitSet THEN
bitSet := bitSet - {1};
ELSE
bitSet := bitSet + {1};
END;
ip.ipv6Adr[8] := SYSTEM.VAL(CHAR, bitSet);
END SetInterfaceID;
PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR;
src, dst: IP.Adr;
nextHeader, pktLengthUpperLayer: LONGINT): LONGINT;
VAR
i: LONGINT;
tmpAdr: ARRAY 4 OF LONGINT;
BEGIN
IF DEBUG THEN
ASSERT (IP.IsNilAdr(src) OR (src.usedProtocol = IP.IPv6));
ASSERT (IP.IsNilAdr(dst) OR (dst.usedProtocol = IP.IPv6));
END;
FOR i := 0 TO 3 DO
tmpAdr[i] := ORD(src.ipv6Adr[i*4 + 0]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(src.ipv6Adr[i*4 + 1]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(src.ipv6Adr[i*4 + 2]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(src.ipv6Adr[i*4 + 3]);
Network.PutNet4(pseudoHdr, i*4, tmpAdr[i]);
END;
FOR i := 0 TO 3 DO
tmpAdr[i] := 0;
tmpAdr[i] := ORD(dst.ipv6Adr[i*4 + 0]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(dst.ipv6Adr[i*4 + 1]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(dst.ipv6Adr[i*4 + 2]);
tmpAdr[i] := (tmpAdr[i] * 256) + ORD(dst.ipv6Adr[i*4 + 3]);
Network.PutNet4(pseudoHdr, (i*4)+16, tmpAdr[i]);
END;
Network.PutNet4(pseudoHdr, 32, pktLengthUpperLayer);
Network.PutNet4(pseudoHdr, 36, nextHeader);
RETURN 40;
END WritePseudoHeader;
PROCEDURE ReceiveNeighborSolicitation*(srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
target: IP.Adr;
i: LONGINT;
int: IP.Interface;
BEGIN
target.usedProtocol := IP.IPv6;
FOR i := 0 TO 15 DO
target.ipv6Adr[i] := buffer.data[buffer.ofs + 4 + i];
END;
int := IP.InterfaceByDstIP(target);
IF (int # NIL) & (IP.AdrsEqual(int.localAdr, target)) THEN
sendNeighborAdvertisement(int(Interface), buffer.src, srcAdr, TRUE);
END;
Network.ReturnBuffer(buffer);
END ReceiveNeighborSolicitation;
PROCEDURE ReceiveNeighborAdvertisement* (srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
neighborEntry: NeighborCacheEntry;
flags: SET;
routerFlag: BOOLEAN;
solicitedFlag: BOOLEAN;
overrideFlag: BOOLEAN;
linkAdrsEqual: BOOLEAN;
hasTargetLinkOption: BOOLEAN;
targetLinkAdr: Network.LinkAdr;
newRouter: IP.Adr;
BEGIN
IF IP.AdrsEqual(srcAdr, localAdr) THEN
KernelLog.Ln; KernelLog.String("Duplicate address detected. Shuting down interface: ");
KernelLog.String(dev.name);
KernelLog.Ln;
Close;
ELSE
neighborEntry := neighborCache.Get(srcAdr);
IF neighborEntry = NIL THEN
neighborCache.Add(srcAdr);
neighborEntry := neighborCache.Get(srcAdr);
END;
flags := SYSTEM.VAL(SET, Network.GetNet4(buffer.data, buffer.ofs));
routerFlag := 31 IN flags;
solicitedFlag := 30 IN flags;
overrideFlag := 29 IN flags;
IF neighborEntry.reachability = Incomplete THEN
neighborEntry.linkAdr := buffer.src;
IF solicitedFlag THEN
neighborEntry.reachability := Reachable;
Kernel.SetTimer(neighborEntry.lastConfirmation, ReachableTime);
ELSE
neighborEntry.reachability := Stale;
END;
neighborEntry.isRouter := routerFlag;
neighborCache.SendQueuedPackets(neighborEntry);
ELSE
IF (buffer.len - buffer.ofs) > (MinIPHdrLen + IP.ICMPHdrLen + NeighborHdrLen) THEN
IF (buffer.data[buffer.ofs + NeighborHdrLen] = 2X) & (buffer.data[buffer.ofs + NeighborHdrLen + 1] = 1X) THEN
hasTargetLinkOption := TRUE;
buffer.ofs := buffer.ofs + NeighborHdrLen;
icmpLinkLayerAdrOption(buffer, targetLinkAdr);
linkAdrsEqual := Network.LinkAdrsEqual(targetLinkAdr, neighborEntry.linkAdr);
ELSE
hasTargetLinkOption := FALSE;
linkAdrsEqual := FALSE;
END;
ELSE
hasTargetLinkOption := FALSE;
linkAdrsEqual := FALSE;
END;
IF (~overrideFlag) & (~linkAdrsEqual) & (neighborEntry.reachability = Reachable) THEN
neighborEntry.reachability := Stale;
END;
IF overrideFlag OR (~overrideFlag & linkAdrsEqual) OR (~hasTargetLinkOption) THEN
IF hasTargetLinkOption THEN
neighborEntry.linkAdr := targetLinkAdr
END;
IF solicitedFlag THEN
neighborEntry.reachability := Reachable;
Kernel.SetTimer(neighborEntry.lastConfirmation, ReachableTime);
ELSIF hasTargetLinkOption THEN
neighborEntry.reachability := Stale;
END;
IF (neighborEntry.isRouter) & ~routerFlag THEN
routers.Remove(neighborEntry.neighborIP);
newRouter := routers.GetRouter();
destCache.ChangeDests(neighborEntry.neighborIP, newRouter);
END;
neighborEntry.isRouter := routerFlag;
END;
END;
END;
Network.ReturnBuffer(buffer);
END ReceiveNeighborAdvertisement;
PROCEDURE RouterSolicitation*;
BEGIN
sendRouterSolicitation(SELF);
INC(routerSolCount);
END RouterSolicitation;
PROCEDURE ReceiveRouterAdvertisement*(srcAdr: IP.Adr; buffer: Network.Buffer);
VAR
int: IP.Interface;
intv6: Interface;
intName: IP.Name;
newLocalAdr: IP.Adr;
hopLimit: LONGINT;
flags: SET;
managedFlag: BOOLEAN;
otherStatefulFlag: BOOLEAN;
homeAgentFlag: BOOLEAN;
routerLifetime: LONGINT;
reachableTime: LONGINT;
retransTimer: LONGINT;
linkAdr: Network.LinkAdr;
mtu: LONGINT;
onLink: ARRAY MaxPrefixOptions OF BOOLEAN;
autonomous: ARRAY MaxPrefixOptions OF BOOLEAN;
routerAddress: ARRAY MaxPrefixOptions OF BOOLEAN;
sitePrefix: ARRAY MaxPrefixOptions OF BOOLEAN;
validLifetime: ARRAY MaxPrefixOptions OF LONGINT;
preferredLifetime: ARRAY MaxPrefixOptions OF LONGINT;
sitePrefixLength: ARRAY MaxPrefixOptions OF LONGINT;
localPrefix: ARRAY MaxPrefixOptions OF IP.Adr;
router: RoutersEntry;
hasSrcLinkLayerOption: BOOLEAN;
hasMTUOption: BOOLEAN;
prefixItem: PrefixesEntry;
nbrOfPrefixOpt: LONGINT;
i: LONGINT;
res: LONGINT;
tmpStr: ARRAY 8 OF CHAR;
PROCEDURE ParseRouterAdvOptions(): BOOLEAN;
BEGIN
WHILE buffer.len > 0 DO
CASE ORD(buffer.data[buffer.ofs]) OF
IP.ICMPSrcLLAdrOptionType:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
hasSrcLinkLayerOption := TRUE;
icmpLinkLayerAdrOption(buffer, linkAdr);
|IP.ICMPPrefixInfoOptionType:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
icmpPrefixInfoOption(buffer,
onLink[nbrOfPrefixOpt],
autonomous[nbrOfPrefixOpt],
routerAddress[nbrOfPrefixOpt],
sitePrefix[nbrOfPrefixOpt],
validLifetime[nbrOfPrefixOpt],
preferredLifetime[nbrOfPrefixOpt],
sitePrefixLength[nbrOfPrefixOpt],
localPrefix[nbrOfPrefixOpt]);
INC(nbrOfPrefixOpt);
|IP.ICMPMTUOptionType:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
hasMTUOption := TRUE;
icmpMTUOption(buffer, mtu);
mtu := Strings.Min(mtu, linkMTU);
mtu := Strings.Min(mtu, dev.mtu);
|IP.ICMPAdvIntOptionType:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
icmpAdvIntervalOption(buffer);
|IP.ICMPHomeAgOptionType:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
icmpHomeAgentInfoOption(buffer);
|IP.ICMPRouteOption:
IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
RETURN FALSE;
END;
icmpRouteInfoOption(buffer);
ELSE
IF DEBUG THEN
ASSERT(TRUE);
END;
RETURN FALSE;
END;
END;
RETURN TRUE;
END ParseRouterAdvOptions;
PROCEDURE createInterfaces;
VAR
i: LONGINT;
currentPrefix: LONGINT;
BEGIN
IF autoconfigurated THEN
IF createStatelessInterface THEN
currentPrefix := 0;
WHILE currentPrefix < nbrOfPrefixOpt DO
IF autonomous[currentPrefix] THEN
Strings.IntToStr(currentPrefix, tmpStr);
Strings.Concat(V6RouterIntName, tmpStr, intName);
Strings.Concat(intName , dev.name, intName);
NEW(intv6, intName, dev, res);
int := intv6;
IF res = IP.Ok THEN
int(Interface).autoconfigurated := TRUE;
newLocalAdr := localPrefix[currentPrefix];
newLocalAdr.data := 0;
int(Interface).SetInterfaceID(newLocalAdr);
int.SetAdrs(newLocalAdr, localPrefix[currentPrefix], IP.NilAdr, res);
IF res = IP.Ok THEN
KernelLog.String("IPv6: Add interface for LinkDevice '"); KernelLog.String(dev.name);
KernelLog.String("'. Error code: "); KernelLog.Int(res, 0); KernelLog.Ln;
IP.OutInterface(int);
int(Interface).createStatelessInterface := FALSE;
FOR i := 0 TO DNScount - 1 DO
int.DNSAdd(DNS[i]);
END;
int(Interface).routers := routers;
int(Interface).prefixes := prefixes;
int(Interface).neighborCache := neighborCache;
int(Interface).destCache := destCache;
END;
END;
END;
INC(currentPrefix);
END;
END;
IF createStatefulInterface THEN
END;
END;
END createInterfaces;
BEGIN
hasSrcLinkLayerOption := FALSE;
hasMTUOption := FALSE;
nbrOfPrefixOpt := 0;
IF ~AdrsPartEqual(srcAdr, linkLocalPrefix, 0, (linkLocalPrefix.data DIV 8) - 1 ) THEN
Network.ReturnBuffer(buffer);
RETURN;
END;
IF buffer.data[7] # 0FFX THEN
RETURN
END;
IF buffer.data[buffer.ofs - 3] # 0X THEN
RETURN;
END;
hopLimit := ORD(buffer.data[buffer.ofs]);
flags := SYSTEM.VAL(SET, Network.GetNet4(buffer.data, buffer.ofs + 1));
managedFlag := 31 IN flags;
otherStatefulFlag := 30 IN flags;
homeAgentFlag := 29 IN flags;
routerLifetime := Network.GetNet2(buffer.data, buffer.ofs + 2);
reachableTime := SYSTEM.VAL(LONGINT, Network.GetNet4(buffer.data, buffer.ofs + 4));
retransTimer := SYSTEM.VAL(LONGINT, Network.GetNet4(buffer.data, buffer.ofs + 8));
INC(buffer.ofs, RouterAdvHdrLen);
DEC(buffer.len, RouterAdvHdrLen);
IF ~ ParseRouterAdvOptions() THEN
Network.ReturnBuffer(buffer);
RETURN;
END;
router := routers.Get(srcAdr);
IF (router = NIL) & (routerLifetime # 0) THEN
router := routers.Add(srcAdr, linkAdr, routerLifetime);
END;
Kernel.SetTimer(router.routerLifetime, routerLifetime * 1000);
IF routerLifetime # 0 THEN
IF hopLimit # 0 THEN
curHopLimit := hopLimit;
END;
ELSE
router.router.reachability := Probe;
destCache.ChangeDests(srcAdr, routers.GetRouter());
END;
IF hasSrcLinkLayerOption & (routerLifetime # 0) THEN
IF router.router.linkAdr # linkAdr THEN
router.router.reachability := Stale;
router.router.linkAdr := linkAdr;
END;
END;
IF hasMTUOption & (mtu >= MinIPHdrLen)THEN
linkMTU := mtu;
END;
router.router.isRouter := TRUE;
FOR i := 0 TO nbrOfPrefixOpt - 1 DO
IF onLink[i] THEN
prefixItem := prefixes.Get(localPrefix[i]);
IF prefixItem = NIL THEN
IF validLifetime[i] # 0 THEN
prefixes.Add(localPrefix[i], validLifetime[i]);
END;
ELSE
IF validLifetime[i] = 0 THEN
prefixes.Remove(localPrefix[i]);
ELSE
Kernel.SetTimer(prefixItem.lifetime, validLifetime[i] * 1000);
END;
END;
END;
END;
IF managedFlag OR otherStatefulFlag THEN
createStatefulInterface := TRUE;
END;
createInterfaces;
Network.ReturnBuffer(buffer);
END ReceiveRouterAdvertisement;
PROCEDURE ReceiveRouterSolicitation*;
BEGIN
IF isRouter THEN
sendRouterAdvertisement(SELF, linkLocalMulticastNodeAdr, linkMulticastAllNodesAdr, routerConfig);
END;
END ReceiveRouterSolicitation;
PROCEDURE ReceivePacketTooBig*(from: IP.Adr; buffer: Network.Buffer);
VAR
newPMTU: LONGINT;
BEGIN
IF buffer.data[buffer.ofs - 3] = 0X THEN
newPMTU := Network.GetNet4(buffer.data, 0);
destCache.ChangePMTU(from, newPMTU);
END;
Network.ReturnBuffer(buffer);
END ReceivePacketTooBig;
PROCEDURE ConfigAsRouter*(newRouterConfig: RouterConfig);
VAR
prefixConfigItem: PrefixConfig;
intv6: Interface;
count: LONGINT;
tmpStr: ARRAY 8 OF CHAR;
newLocalAdr: IP.Adr;
res: LONGINT;
i: LONGINT;
BEGIN
isRouter := TRUE;
routerConfig := newRouterConfig;
routerConfig.next := NIL;
KernelLog.String("Interface "); KernelLog.String(name); KernelLog.String(" is configured as a IPv6 router"); KernelLog.Ln;
count := 0;
prefixConfigItem := newRouterConfig.Prefixes;
WHILE prefixConfigItem # NIL DO
IF prefixConfigItem.Autonomous THEN
Strings.IntToStr(count, tmpStr);
Strings.Concat(V6OwnRouterIntName, tmpStr, intName);
Strings.Concat(intName, dev.name, intName);
NEW(intv6, intName, dev, res);
IF res = IP.Ok THEN
intv6.autoconfigurated := TRUE;
newLocalAdr := prefixConfigItem.Prefix;
newLocalAdr.data := 0;
intv6.SetInterfaceID(newLocalAdr);
intv6.SetAdrs(newLocalAdr, prefixConfigItem.Prefix, IP.NilAdr, res);
IF res = IP.Ok THEN
KernelLog.String("IPv6: Add interface for LinkDevice '"); KernelLog.String(dev.name);
KernelLog.String("'. Error code: "); KernelLog.Int(res, 0); KernelLog.Ln;
IP.OutInterface(intv6);
intv6.createStatelessInterface := FALSE;
FOR i := 0 TO DNScount - 1 DO
intv6.DNSAdd(DNS[i]);
END;
intv6.routers := routers;
intv6.prefixes := prefixes;
intv6.neighborCache := neighborCache;
intv6.destCache := destCache;
END;
END;
INC(count);
END;
prefixConfigItem := prefixConfigItem.next;
END;
END ConfigAsRouter;
PROCEDURE AddToFragmentList(srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
fragmentListItem: FragmentList;
newPacketFragmentItem: PacketFragment;
packetFragmentItem: PacketFragment;
fragmentID: LONGINT;
PROCEDURE CreateNewFragAndAdd;
BEGIN
NEW(fragmentListItem);
fragmentListItem.fragmentID := fragmentID;
fragmentListItem.nextHeader := ORD(buffer.data[buffer.ofs]);
fragmentListItem.srcAdr := srcAdr;
fragmentListItem.dstAdr := dstAdr;
Kernel.SetTimer(fragmentListItem.startedAt, 60000);
fragmentListItem.fragmentCount := 1;
NEW(newPacketFragmentItem);
newPacketFragmentItem.buffer := buffer;
buffer.data[buffer.ofs] := 0X;
newPacketFragmentItem.fragmentOffset := Network.GetNet4(buffer.data, buffer.ofs);
newPacketFragmentItem.moreFragments := 0 IN SYSTEM.VAL(SET, newPacketFragmentItem.fragmentOffset);
newPacketFragmentItem.fragmentOffset := 8 * (newPacketFragmentItem.fragmentOffset DIV 8);
buffer.data[buffer.ofs] := CHR(fragmentListItem.nextHeader);
newPacketFragmentItem.next := NIL;
newPacketFragmentItem.prev := NIL;
fragmentListItem.packets := newPacketFragmentItem;
fragmentListItem.next := fragmentList;
fragmentList := fragmentListItem;
END CreateNewFragAndAdd;
BEGIN
fragmentID := Network.GetNet4(buffer.data, buffer.ofs + 4);
fragmentListItem := fragmentList;
WHILE (fragmentListItem # NIL) &
(fragmentListItem.fragmentID # fragmentID) &
(~IP.AdrsEqual(fragmentListItem.srcAdr, srcAdr)) &
( ~IP.AdrsEqual(fragmentListItem.dstAdr, dstAdr)) DO
fragmentListItem := fragmentListItem.next;
END;
IF fragmentListItem = NIL THEN
CreateNewFragAndAdd();
ELSE
INC(fragmentListItem.fragmentCount);
NEW(newPacketFragmentItem);
newPacketFragmentItem.buffer := buffer;
buffer.data[buffer.ofs] := 0X;
newPacketFragmentItem.fragmentOffset := Network.GetNet4(buffer.data, buffer.ofs);
newPacketFragmentItem.moreFragments := 0 IN SYSTEM.VAL(SET, newPacketFragmentItem.fragmentOffset);
newPacketFragmentItem.fragmentOffset := 8 * (newPacketFragmentItem.fragmentOffset DIV 8);
buffer.data[buffer.ofs] := CHR(fragmentListItem.nextHeader);
packetFragmentItem := fragmentListItem.packets;
LOOP
IF (packetFragmentItem.next = NIL) & (packetFragmentItem.fragmentOffset <= newPacketFragmentItem.fragmentOffset) THEN
packetFragmentItem.next := newPacketFragmentItem;
newPacketFragmentItem.next := NIL;
newPacketFragmentItem.prev := packetFragmentItem;
EXIT;
END;
IF packetFragmentItem.fragmentOffset > newPacketFragmentItem.fragmentOffset THEN
newPacketFragmentItem.next := packetFragmentItem;
newPacketFragmentItem.prev := packetFragmentItem.prev;
packetFragmentItem.prev := newPacketFragmentItem;
IF newPacketFragmentItem.prev = NIL THEN
fragmentListItem.packets := newPacketFragmentItem;
ELSE
newPacketFragmentItem.prev.next := newPacketFragmentItem;
END;
EXIT;
END;
packetFragmentItem := packetFragmentItem.next;
END;
ReassembleFragments(fragmentListItem);
END;
END AddToFragmentList;
PROCEDURE ReassembleFragments(fragmentListItem: FragmentList);
VAR
packetFragmentItem: PacketFragment;
currentFragmentOffset: LONGINT;
lastPacketOk: BOOLEAN;
lastFragment: PacketFragment;
BEGIN
IF Kernel.Expired(fragmentListItem.startedAt) THEN
IF fragmentListItem.packets.fragmentOffset = 0 THEN
sendICMPv6TimeExceeded(SELF, fragmentListItem.packets.buffer, fragmentListItem.srcAdr, ICMPv6FragmentReassemblyExc);
END;
DelFragmentListEntry(fragmentListItem, TRUE);
ELSE
packetFragmentItem := fragmentListItem.packets;
currentFragmentOffset := 0;
lastPacketOk := FALSE;
WHILE (packetFragmentItem # NIL) & (currentFragmentOffset = packetFragmentItem.fragmentOffset) DO
IF packetFragmentItem.next = NIL THEN
lastPacketOk := ~packetFragmentItem.moreFragments;
lastFragment := packetFragmentItem;
END;
INC(currentFragmentOffset, packetFragmentItem.buffer.len - FragmentHdrLen);
packetFragmentItem := packetFragmentItem.next;
END;
IF (packetFragmentItem = NIL) & lastPacketOk THEN
packetFragmentItem := fragmentListItem.packets;
WHILE packetFragmentItem.next # NIL DO
packetFragmentItem.buffer.nextFragment := packetFragmentItem.next.buffer;
INC(packetFragmentItem.next.buffer.ofs, FragmentHdrLen);
DEC(packetFragmentItem.next.buffer.len, FragmentHdrLen);
packetFragmentItem := packetFragmentItem.next;
END;
IPInput(dev, EtherTypeIP, fragmentListItem.packets.buffer);
DelFragmentListEntry(fragmentListItem, FALSE);
END;
END;
END ReassembleFragments;
PROCEDURE DelFragmentListEntry(fragmentListEntry: FragmentList; returnBuffers: BOOLEAN);
VAR
fragmentListFind: FragmentList;
BEGIN
IF returnBuffers THEN
Network.ReturnBuffer(fragmentListEntry.packets.buffer);
END;
IF fragmentList = fragmentListEntry THEN
fragmentList := fragmentListEntry.next;
ELSE
fragmentListFind := fragmentList;
WHILE (fragmentListFind.next # NIL) & (fragmentListFind.next # fragmentListEntry) DO
fragmentListFind := fragmentListFind.next;
END;
fragmentListFind.next := fragmentListFind.next.next;
END;
END DelFragmentListEntry;
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;
routers.OutRouters;
KernelLog.String("Prefix: "); IP.OutAdr(maskAdr); 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;
BEGIN {ACTIVE}
(* init timers *)
NEW(shortTimer);
Kernel.SetTimer(longTimer, LongTimerTimeout);
Kernel.SetTimer(duplicateTimer, LongTimerTimeout);
(* Init solicited multicast MAC address *)
linkMulticastSolicited[0] := 33X;
linkMulticastSolicited[1] := 33X;
linkMulticastSolicited[2] := 0FFX;
linkMulticastSolicited[3] := dev.local[3];
linkMulticastSolicited[4] := dev.local[4];
linkMulticastSolicited[5] := dev.local[5];
linkMulticastSolicited[6] := 0X;
linkMulticastSolicited[7] := 0X;
linkMTU := 1500; (* Default value for link MTU (assuming I'm on ethernet) *)
curHopLimit := 255; (* Default hop limit *)
REPEAT
shortTimer.Sleep(ShortTimerTimeout);
IF Kernel.Expired(duplicateTimer) THEN
IF autoconfigState = TentativeInterface THEN
autoconfigState := PreferredInterface;
END;
END;
(* Search fragment list for lost packets *)
fragmentListItem := fragmentList;
WHILE fragmentListItem # NIL DO
(* Check timer *)
IF Kernel.Expired(fragmentListItem.startedAt) THEN
(* send ICMP Time Exceeded -- Fragment Reassembly Time Exceeded message *)
IF fragmentListItem.packets.fragmentOffset = 0 THEN
(* only if first fragment was received *)
sendICMPv6TimeExceeded(SELF, fragmentListItem.packets.buffer, fragmentListItem.srcAdr, ICMPv6FragmentReassemblyExc);
END;
DelFragmentListEntry(fragmentListItem, TRUE);
END;
fragmentListItem := fragmentListItem.next;
END;
IF createStatelessInterface THEN
(* Do stateless autoconfiguration *)
IF sendRouterSolicitation # NIL THEN
IF routerSolCount < 4 THEN
RouterSolicitation;
ELSE
(* initiate DHCPv6 *)
createStatelessInterface := FALSE;
createStatefulInterface := TRUE;
(* (* create new interface on which asks a DHCPv6 *)
Strings.Concat(V6DHCPIntName , dev.name, intName);
NEW (intv6, intName, dev, res);
IF res = IP.Ok THEN
(* configure DHCP interface *)
END;
*) createStatefulInterface := FALSE;
END;
END;
END;
(* Interface acts as a router *)
IF isRouter THEN
IF nextRtrAdvertisement = 0 THEN
(* send a unsolicited router advertisement *)
sendRouterAdvertisement(SELF, linkLocalMulticastNodeAdr, linkMulticastAllNodesAdr, routerConfig);
(* When to send next unsolicited router advertisement *)
nextRtrAdvertisement := RandomNumber(MaxRtrAdvInterval - MinRtrAdvInterval);
INC(nextRtrAdvertisement, MinRtrAdvInterval);
nextRtrAdvertisement := nextRtrAdvertisement DIV ShortTimerTimeout;
ELSE
DEC(nextRtrAdvertisement);
END;
END;
IF Kernel.Expired(longTimer) THEN
IF autoconfigurated THEN
(* If no stateful or stateless interfaces exist, try to create them *)
int := IP.interfaces;
createStatefulInterface := TRUE;
createStatelessInterface := TRUE;
WHILE int # NIL DO
IF Strings.Pos(V6RouterIntName, int.name) = 0 THEN
createStatelessInterface := FALSE;
END;
IF Strings.Pos(V6DHCPIntName, int.name) = 0 THEN
createStatefulInterface := FALSE;
END;
int := int.next;
END;
END;
Kernel.SetTimer(longTimer, LongTimerTimeout);
(* Check caches for old entries and delete them *)
destCache.Clear(); (* Destination cache *)
prefixes.ClearExpired(); (* Clear expired prefixes *)
routers.ClearExpired(); (* Clear expired default routers *)
localAdrCache.ClearExpired(); (* Clear expored local addresses *)
RouterSolicitation();
END;
UNTIL closed;
END Interface;
TYPE
SendNeighborSolicitation* = PROCEDURE {DELEGATE} (interface: Interface; linkAdr: Network.LinkAdr; destAdr: IP.Adr; multicast: BOOLEAN);
SendNeighborAdvertisement* = PROCEDURE {DELEGATE} (interface: Interface; linkDst: Network.LinkAdr; destAdr: IP.Adr; solicited: BOOLEAN);
SendRouterSolicitation* = PROCEDURE {DELEGATE} (interface: Interface);
SendRouterAdvertisement* = PROCEDURE {DELEGATE} (interface: Interface; dstAdr: IP.Adr; dstLinkAdr: Network.LinkAdr; routerConfig:RouterConfig);
SendICMPv6TimeExceeded* = PROCEDURE {DELEGATE} (interface: Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; code: LONGINT);
SendICMPv6ParamProb* = PROCEDURE {DELEGATE} (interface: Interface; discardedPacket: Network.Buffer; srcAdr: IP.Adr; probPointer, code: LONGINT);
ICMPLinkLayerAdrOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer; VAR linkAdr: Network.LinkAdr);
ICMPPrefixInfoOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer;
VAR onLink, autonomous, routerAddress, sitePrefix: BOOLEAN;
VAR validLifetime, preferredLifetime, sitePrefixLength: LONGINT;
VAR localPrefix: IP.Adr);
ICMPRedirectHdrOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer);
ICMPMTUOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer; VAR MTU: LONGINT);
ICMPAdvIntervalOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer);
ICMPHomeAgentInfoOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer);
ICMPRouteInfoOption* = PROCEDURE {DELEGATE} (VAR buffer: Network.Buffer);
VAR
sendNeighborSolicitation*: SendNeighborSolicitation;
sendNeighborAdvertisement*: SendNeighborAdvertisement;
sendRouterSolicitation*: SendRouterSolicitation;
sendRouterAdvertisement*: SendRouterAdvertisement;
sendICMPv6TimeExceeded*: SendICMPv6TimeExceeded;
sendICMPv6ParamProb*: SendICMPv6ParamProb;
icmpLinkLayerAdrOption*: ICMPLinkLayerAdrOption;
icmpPrefixInfoOption*: ICMPPrefixInfoOption;
icmpRedirectHdrOption*: ICMPRedirectHdrOption;
icmpMTUOption*: ICMPMTUOption;
icmpAdvIntervalOption*: ICMPAdvIntervalOption;
icmpHomeAgentInfoOption*: ICMPHomeAgentInfoOption;
icmpRouteInfoOption*: ICMPRouteInfoOption;
linkLocalPrefix: IP.Adr;
nodeLocalMulticastNodeAdr: IP.Adr;
nodeLocalMulticastRouterAdr: IP.Adr;
linkLocalMulticastNodeAdr*: IP.Adr;
linkLocalMulticastRouterAdr*: IP.Adr;
linkMulticastAllNodesAdr*: Network.LinkAdr;
linkMulticastAllRoutersAdr*: Network.LinkAdr;
devList: DeviceList;
localAdrCache: LocalAdrCache;
fragmentationID: LONGINT;
fragmentListItem: FragmentList;
randomZ: LONGINT;
PROCEDURE AdrsPartEqual(adr1, adr2: IP.Adr; from, to: LONGINT): BOOLEAN;
VAR
i: LONGINT;
isPartEqual: BOOLEAN;
BEGIN
IF DEBUG THEN
ASSERT((from >= 0) & (from <= 15));
ASSERT((from >= 0) & (from <= 15));
ASSERT(from <= to);
END;
isPartEqual := TRUE;
FOR i := from TO to DO
IF (adr1.ipv6Adr[i] # adr2.ipv6Adr[i]) THEN
isPartEqual := FALSE;
END;
END;
RETURN isPartEqual;
END AdrsPartEqual;
PROCEDURE IsPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
VAR
isValid: BOOLEAN;
BEGIN
isValid := FALSE;
Machine.AtomicInc(IP.NIPRcvTotal);
IF buffer.len >= MinIPHdrLen THEN
IF SYSTEM.LSH(ORD(buffer.data[buffer.ofs]), -4) = IP.IPv6 THEN
isValid := TRUE;
ELSE
Machine.AtomicInc(IP.NIPBadVersion)
END
ELSE
Machine.AtomicInc(IP.NIPTooSmall)
END;
RETURN isValid;
END IsPacketValid;
PROCEDURE IsPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
BEGIN
RETURN TRUE;
END IsPacketForSingleInt;
PROCEDURE IsLinkLocalMulticastAdr (adr: IP.Adr): BOOLEAN;
VAR
isLinkLocal: BOOLEAN;
BEGIN
isLinkLocal := FALSE;
IF IP.AdrsEqual(adr, linkLocalMulticastNodeAdr) THEN
isLinkLocal := TRUE;
END;
RETURN isLinkLocal;
END IsLinkLocalMulticastAdr;
PROCEDURE IsLinkLocalAdr (adr: IP.Adr): BOOLEAN;
VAR
isLinkLocal: BOOLEAN;
BEGIN
isLinkLocal := FALSE;
IF IP.MatchPrefix(adr, linkLocalPrefix) THEN
isLinkLocal := TRUE;
END;
RETURN isLinkLocal;
END IsLinkLocalAdr;
PROCEDURE V6InterfaceByDstIP(dstAdr: IP.Adr): IP.Interface;
VAR
retInt: Interface;
devListItem: DeviceList;
linkLocalInt: Interface;
neighborCacheItem: NeighborCacheEntry;
sleepTimer: Kernel.Timer;
sleepCounter: LONGINT;
normalCase: BOOLEAN;
intItem: IP.Interface;
gw: IP.Interface;
linkDst: Network.LinkAdr;
devCount: LONGINT;
BEGIN
retInt := NIL;
devListItem := devList;
NEW(sleepTimer);
sleepCounter := 0;
normalCase := TRUE;
IF IsLinkLocalAdr(dstAdr) THEN
devCount := 0;
WHILE devListItem # NIL DO
IF devListItem.device.name # "Loopback" THEN
INC(devCount);
END;
devListItem := devListItem.next;
END;
IF devCount > 1 THEN
normalCase := FALSE;
retInt := localAdrCache.GetInterface(dstAdr);
WHILE (retInt = NIL) & (sleepCounter < 5) DO
devListItem := devList;
WHILE devListItem # NIL DO
linkLocalInt := devListItem.linkLocalInterface;
IF linkLocalInt # NIL THEN
neighborCacheItem := linkLocalInt.neighborCache.Get(dstAdr);
IF neighborCacheItem # NIL THEN
retInt := linkLocalInt;
END;
IF IP.AdrsEqual(dstAdr, linkLocalInt.localAdr) THEN
retInt := linkLocalInt;
END;
END;
devListItem := devListItem.next;
END;
IF retInt = NIL THEN
devListItem := devList;
WHILE devListItem # NIL DO
IF (devListItem.linkLocalInterface # NIL) &
(devListItem.linkLocalInterface IS Interface) &
(devListItem.linkLocalInterface.dev.Linked() # Network.LinkNotLinked) THEN
linkDst := linkMulticastAllNodesAdr;
linkDst[2] := 0FFX;
linkDst[3] := dstAdr.ipv6Adr[13];
linkDst[4] := dstAdr.ipv6Adr[14];
linkDst[5] := dstAdr.ipv6Adr[15];
sendNeighborSolicitation(devListItem.linkLocalInterface(Interface), linkDst, dstAdr, TRUE);
END;
devListItem := devListItem.next;
END;
END;
sleepTimer.Sleep(200);
INC(sleepCounter);
END;
IF retInt # NIL THEN
localAdrCache.Add(dstAdr, retInt);
END;
END;
END;
IF (retInt = NIL) & normalCase THEN
gw := NIL;
intItem := IP.interfaces;
LOOP
IF intItem = NIL THEN
EXIT
END;
IF (intItem.protocol = IP.IPv6) & (~IP.IsNilAdr(intItem.localAdr)) & (intItem.dev.Linked() # Network.LinkNotLinked) THEN
IF IP.MatchPrefix(dstAdr, intItem.maskAdr) THEN
EXIT;
ELSIF (gw = NIL) & (~IP.IsNilAdr(intItem.maskAdr)) THEN
gw := intItem;
END;
END;
intItem := intItem.next;
END;
IF intItem # NIL THEN
retInt := intItem(Interface);
ELSE
retInt := gw(Interface);
END;
END;
RETURN retInt;
END V6InterfaceByDstIP;
PROCEDURE GetFragmentID(): LONGINT;
BEGIN {EXCLUSIVE}
INC(fragmentationID);
RETURN fragmentationID;
END GetFragmentID;
PROCEDURE RoutingExtHeader(int: IP.Interface; type: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
segmentsLeft: LONGINT;
hdrExtLen: LONGINT;
receiver: IP.Receiver;
nextHeader: LONGINT;
nbrOfAdrs: LONGINT;
ithAddress: LONGINT;
tempAdr: ARRAY 16 OF CHAR;
intv6: Interface;
BEGIN
ASSERT (int IS Interface);
intv6 := int(Interface);
nextHeader := ORD(buffer.data[buffer.ofs]);
hdrExtLen := ORD(buffer.data[buffer.ofs + 1]);
segmentsLeft := ORD(buffer.data[buffer.ofs + 3]);
IF IP.AdrsEqual(dstAdr, int.localAdr) THEN
IF segmentsLeft = 0 THEN
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
INC(buffer.ofs, hdrExtLen * 8 + RoutingHdrLen);
DEC(buffer.len, hdrExtLen * 8 + RoutingHdrLen);
receiver(int, nextHeader, srcAdr, dstAdr, buffer);
RETURN;
ELSE
Network.ReturnBuffer(buffer);
END;
ELSIF IP.IPForwarding THEN
IF hdrExtLen MOD 2 = 1 THEN
sendICMPv6ParamProb(intv6, buffer, srcAdr, MinIPHdrLen + 2, 0);
Network.ReturnBuffer(buffer);
ELSE
nbrOfAdrs := hdrExtLen DIV 2;
IF segmentsLeft > nbrOfAdrs THEN
sendICMPv6ParamProb(intv6, buffer, srcAdr, MinIPHdrLen + 4, 0);
Network.ReturnBuffer(buffer);
ELSE
DEC(segmentsLeft);
buffer.data[buffer.ofs + 4] := CHR(segmentsLeft);
ithAddress := nbrOfAdrs - segmentsLeft;
Network.Copy(dstAdr.ipv6Adr, tempAdr, 0, 0, 16);
Network.Copy(buffer.data, dstAdr.ipv6Adr, 8 + (ithAddress - 1 * 16), 0, 16);
Network.Copy(tempAdr, buffer.data, 0, (ithAddress - 1 * 16), 16);
INC(buffer.len, buffer.ofs);
buffer.ofs := 0;
END;
END;
ELSE
Network.ReturnBuffer(buffer);
END;
END;
END RoutingExtHeader;
PROCEDURE HopByHopExtHeader(int: IP.Interface; type: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
receiver: IP.Receiver;
nextHeader: LONGINT;
hdrExtLen: LONGINT;
intv6: Interface;
BEGIN
ASSERT(int IS Interface);
intv6 := int(Interface);
nextHeader := ORD(buffer.data[buffer.ofs]);
hdrExtLen := ORD(buffer.data[buffer.ofs + 1]);
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
INC(buffer.ofs, hdrExtLen * 8 + HopByHopHdrLen);
DEC(buffer.len, hdrExtLen * 8 + HopByHopHdrLen);
receiver(intv6, nextHeader, srcAdr, dstAdr, buffer);
RETURN;
ELSE
Network.ReturnBuffer(buffer);
END;
END HopByHopExtHeader;
PROCEDURE DestinationExtHeader(int: IP.Interface; type: LONGINT; srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
VAR
receiver: IP.Receiver;
nextHeader: LONGINT;
hdrExtLen: LONGINT;
intv6: Interface;
BEGIN
ASSERT(int IS Interface);
intv6 := int(Interface);
nextHeader := ORD(buffer.data[buffer.ofs]);
hdrExtLen := ORD(buffer.data[buffer.ofs + 1]);
receiver := IP.receivers[nextHeader];
IF receiver # NIL THEN
INC(buffer.ofs, hdrExtLen * 8 + DestinationHdrLen);
DEC(buffer.len, hdrExtLen * 8 + DestinationHdrLen);
receiver(intv6, nextHeader, srcAdr, dstAdr, buffer);
RETURN;
ELSE
Network.ReturnBuffer(buffer);
END;
END DestinationExtHeader;
PROCEDURE RandomNumber(limit: LONGINT): LONGINT;
CONST
a = 16807;
m = 2147483647;
q = m DIV a;
r = m MOD a;
VAR
g: LONGINT;
BEGIN
g := a*(randomZ MOD q) - r*(randomZ DIV q);
IF g > 0 THEN randomZ := g ELSE randomZ := g + m END;
RETURN ENTIER((randomZ*1.0D0/m) * limit);
END RandomNumber;
PROCEDURE Cleanup;
BEGIN
WHILE IP.interfaces # NIL DO
IP.interfaces.Close();
END;
END Cleanup;
BEGIN
linkLocalPrefix := IP.NilAdr;
linkLocalPrefix.usedProtocol := IP.IPv6;
linkLocalPrefix.ipv6Adr[0] := 0FEX;
linkLocalPrefix.ipv6Adr[1] := 80X;
linkLocalPrefix.data := 64;
nodeLocalMulticastNodeAdr := IP.NilAdr;
nodeLocalMulticastRouterAdr := IP.NilAdr;
linkLocalMulticastNodeAdr := IP.NilAdr;
linkLocalMulticastRouterAdr := IP.NilAdr;
nodeLocalMulticastNodeAdr.usedProtocol := IP.IPv6;
nodeLocalMulticastRouterAdr.usedProtocol := IP.IPv6;
linkLocalMulticastNodeAdr.usedProtocol := IP.IPv6;
linkLocalMulticastRouterAdr.usedProtocol := IP.IPv6;
nodeLocalMulticastNodeAdr.ipv6Adr[0] := 0FFX;
nodeLocalMulticastRouterAdr.ipv6Adr[0] := 0FFX;
linkLocalMulticastNodeAdr.ipv6Adr[0] := 0FFX;
linkLocalMulticastRouterAdr.ipv6Adr[0] := 0FFX;
nodeLocalMulticastNodeAdr.ipv6Adr[1] := 1X;
nodeLocalMulticastRouterAdr.ipv6Adr[1] :=1X;
linkLocalMulticastNodeAdr.ipv6Adr[1] := 2X;
linkLocalMulticastRouterAdr.ipv6Adr[1] := 2X;
nodeLocalMulticastNodeAdr.ipv6Adr[15] := 1X;
nodeLocalMulticastRouterAdr.ipv6Adr[15] :=2X;
linkLocalMulticastNodeAdr.ipv6Adr[15] := 1X;
linkLocalMulticastRouterAdr.ipv6Adr[15] := 2X;
linkMulticastAllNodesAdr[0] := 33X;
linkMulticastAllNodesAdr[1] := 33X;
linkMulticastAllNodesAdr[2] := 0X;
linkMulticastAllNodesAdr[3] := 0X;
linkMulticastAllNodesAdr[4] := 0X;
linkMulticastAllNodesAdr[5] := 1X;
linkMulticastAllNodesAdr[6] := 0X;
linkMulticastAllNodesAdr[7] := 0X;
linkMulticastAllRoutersAdr[0] := 33X;
linkMulticastAllRoutersAdr[1] := 33X;
linkMulticastAllRoutersAdr[2] := 0X;
linkMulticastAllRoutersAdr[3] := 0X;
linkMulticastAllRoutersAdr[4] := 0X;
linkMulticastAllRoutersAdr[5] := 2X;
linkMulticastAllRoutersAdr[6] := 0X;
linkMulticastAllRoutersAdr[7] := 0X;
randomZ := Kernel.GetTicks();
devList := NIL;
NEW(localAdrCache);
IP.v6InterfaceByDstIP := V6InterfaceByDstIP;
IP.InstallReceiver(IPv6RoutingHdrType, RoutingExtHeader);
IP.InstallReceiver(IPv6HopByHopHdrType, HopByHopExtHeader);
IP.InstallReceiver(IPv6DestinationHdrType, DestinationExtHeader);
Modules.InstallTermHandler(Cleanup);
END IPv6.
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.
07.2005 eb Cache