12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404 |
- MODULE IPv6; (** AUTHOR "Erwin Betschart"; PURPOSE "IP protocol version 6"; *)
- IMPORT SYSTEM, Machine, Kernel, Objects, Modules, Strings, KernelLog, Network, IP, Plugins;
- CONST
- (* DEBUG *)
- DEBUG = TRUE;
- (* IP *)
- EtherTypeIP* = 86DDH;
- MinIPHdrLen*= 40;
- MaxIPHdrLen* = 40;
- MaxFragPacketSize* = 65536; (* Maximal size of a packet, which can be fragmented *)
- (* Interface *)
- V6RouterIntName = "v6Router";
- V6OwnRouterIntName = "v6OwnRouter";
- V6DHCPIntName = "v6DHCP";
- (* Neighbor etc. cache *)
- CacheSize = 256;
- (* Neighbor cache reachablility states *)
- Incomplete = 0;
- Reachable = 1;
- Stale = 2;
- Delay = 3;
- Probe = 4;
- ReachableTime = 30000;
- (* autoconfig states *)
- TentativeInterface = 0;
- PreferredInterface = 1;
- DepricatedInterface = 2;
- InvalidInterface = 3;
- (* Next header types *)
- IPv6FragmentType = 44;
- IPv6RoutingHdrType = 43;
- IPv6HopByHopHdrType = 0;
- IPv6DestinationHdrType = 60;
- ICMPv6Type = 58;
- (* Header / Options Lengths *)
- NeighborHdrLen* = 20;
- RouterSolHdrLen* = 4;
- RouterAdvHdrLen = 12;
- LLAdrOptionLen* = 8; (* Source or Target Link-Layer address option len *)
- FragmentHdrLen = 8; (* Fragmentation header length *)
- RoutingHdrLen = 8; (* Routing header length *)
- HopByHopHdrLen = 8; (* Hop-by-hop header length *)
- DestinationHdrLen = 8; (* Destination header length *)
- MaxPrefixOptions = 10;
- (* Timers *)
- ShortTimerTimeout = 3000; (* 3 sec *)
- LongTimerTimeout = 600000; (* 10 min *)
- (* ICMP codes *)
- ICMPv6CodeHopLimitExc* = 0;
- ICMPv6FragmentReassemblyExc* = 3;
- (* router *)
- MaxRtrAdvInterval = 600000; (* milliseconds; default from RFC 2461*)
- MinRtrAdvInterval = 198000; (* milliseconds; default 0.33 * MaxRtrAdvInterval *)
- RouterPrefHigh = 1;
- RouterPrefMedium = 0;
- RouterPrefLow = 3;
- TYPE
- (* List of incoming fragmented packets which should be reassembled *)
- FragmentList = POINTER TO RECORD
- fragmentID: LONGINT;
- nextHeader: LONGINT;
- srcAdr: IP.Adr;
- dstAdr: IP.Adr;
- packets: PacketFragment;
- startedAt: Kernel.MilliTimer;
- fragmentCount: LONGINT;
- next: FragmentList;
- END;
- (* List of a packet which was fragmented *)
- PacketFragment = POINTER TO RECORD
- buffer: Network.Buffer;
- fragmentOffset: LONGINT;
- moreFragments: BOOLEAN;
- next: PacketFragment;
- prev: PacketFragment;
- END;
- (* List of devices *)
- DeviceList = POINTER TO RECORD
- device: Network.LinkDevice;
- linkLocalInterface: Interface;
- next: DeviceList;
- END;
- (* Router config *)
- RouterConfig* = POINTER TO RECORD
- Device*: Plugins.Name;
- SendRouterAdvertisements*: BOOLEAN;
- ManagedAddressConfig*: BOOLEAN;
- OtherStatefulConfig*: BOOLEAN;
- LinkMTU*: LONGINT;
- ReachableTime*: LONGINT; (* in seconds *)
- RetransTimer*: LONGINT; (* in seconds *)
- CurrentHopLimit*: LONGINT;
- Lifetime*: LONGINT; (* in seconds *)
- Prefixes*: PrefixConfig;
- next*: RouterConfig;
- END;
- (* Prefix config for router config *)
- PrefixConfig* = POINTER TO RECORD
- Prefix*: IP.Adr;
- IsSitePrefix*: BOOLEAN;
- ValidLifetime*: LONGINT; (* in seconds *)
- OnLink*: BOOLEAN;
- PreferredLifetime*: LONGINT;(* in seconds *)
- Autonomous*: BOOLEAN;
- next*: PrefixConfig;
- END;
- (* A queue of packets used in neighbor cache to store pending packets *)
- 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;
- (* Entry in the neighbor cache *)
- NeighborCacheEntry* = POINTER TO RECORD
- next: NeighborCacheEntry;
- neighborIP: IP.Adr;
- linkAdr: Network.LinkAdr;
- reachability: LONGINT; (* either Incomplete, Reachable, Stale, Delay or Probe *)
- isRouter: BOOLEAN;
- queuedPackets: PacketQueue;
- probes: LONGINT; (* number of unanswered probes *)
- lastConfirmation: Kernel.MilliTimer;
- END;
- (* Entry in the destination cache *)
- DestCacheEntry = POINTER TO RECORD
- next: DestCacheEntry;
- dest: IP.Adr;
- nextHop: IP.Adr;
- pmtu: LONGINT;
- END;
- (* Entry in the prefix list *)
- PrefixesEntry = POINTER TO RECORD
- next: PrefixesEntry;
- prefix: IP.Adr;
- lifetime: Kernel.MilliTimer; (* time, when a prefix becomes invalid *)
- END;
- (* Entry in the default router list *)
- RoutersEntry = POINTER TO RECORD
- next: RoutersEntry;
- router: NeighborCacheEntry;
- routerLifetime: Kernel.MilliTimer;
- END;
- (* Entry in the local address cache *)
- LocalAdrCacheEntry = POINTER TO RECORD
- next: LocalAdrCacheEntry;
- localAdr: IP.Adr;
- interface: Interface;
- created: Kernel.MilliTimer;
- END;
- TYPE
- (** Destination cache *)
- DestCache = OBJECT
- VAR
- (* Array which holds linked lists of destination cache entries. The last byte of the destination address
- is the key to find a entry in this array *)
- destArray: ARRAY CacheSize OF DestCacheEntry;
- interface: Interface; (* Interface on which this cache operates *)
- (** Constructor: Initializes destinations array.*)
- PROCEDURE &Constr*(int: Interface; prefixes: Prefixes);
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO 255 DO
- destArray[i] := NIL;
- END;
- interface := int;
- END Constr;
- (** Add a new dest entry *)
- PROCEDURE Add(destAdr, nextHop: IP.Adr);
- VAR
- newDestItem: DestCacheEntry;
- destItem: DestCacheEntry;
- BEGIN {EXCLUSIVE}
- (* look if entry already exists *)
- destItem := destArray[ORD(destAdr.ipv6Adr[15])];
- WHILE (destItem # NIL) & (~IP.AdrsEqual(destItem.dest, destAdr)) DO
- destItem := destItem.next;
- END;
- IF destItem = NIL THEN
- (* Add new entry *)
- NEW(newDestItem);
- newDestItem.next := NIL;
- newDestItem.dest := destAdr;
- newDestItem.nextHop := nextHop;
- newDestItem.pmtu := interface.linkMTU;
- (* put in array *)
- destItem := destArray[ORD(destAdr.ipv6Adr[15])];
- IF destItem = NIL THEN
- (* first element *)
- destArray[ORD(destAdr.ipv6Adr[15])] := newDestItem;
- ELSE
- WHILE destItem.next # NIL DO
- destItem := destItem.next;
- END;
- destItem.next := newDestItem;
- END;
- END;
- END Add;
- (** Remove a destination entry *)
- 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
- (* remove first element *)
- destArray[ORD(destAdr.ipv6Adr[15])] := destItem.next;
- ELSIF destItem.next # NIL THEN
- (* search for elem *)
- WHILE (destItem.next.next # NIL) & (~IP.AdrsEqual(destItem.next.dest, destAdr)) DO
- destItem := destItem.next;
- END;
- IF destItem.next # NIL THEN
- (* found the right elem *)
- destItem.next := destItem.next.next;
- END;
- END;
- END;
- END Remove;
- (* Changes a PMTU of a cache entry *)
- PROCEDURE ChangePMTU(adr: IP.Adr; newPMTU: LONGINT);
- VAR
- destItem: DestCacheEntry;
- BEGIN
- destItem := destArray[ORD(adr.ipv6Adr[15])];
- IF destItem # NIL THEN
- (* search for right element *)
- WHILE (destItem # NIL) & (~IP.AdrsEqual(destItem.dest, adr)) DO
- destItem := destItem.next;
- END;
- IF destItem # NIL THEN
- destItem.pmtu := newPMTU;
- END;
- END;
- END ChangePMTU;
- (** Get next hop address *)
- PROCEDURE GetNextHop(destAdr: IP.Adr): IP.Adr;
- VAR
- nextHop: IP.Adr;
- destItem: DestCacheEntry;
- BEGIN
- IF interface.IsMulticast(destAdr) THEN
- (* Multicast packets are considered to be on-link *)
- 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
- (* assume destination is link-local *)
- nextHop := destAdr;
- END;
- (* Save results of NextHopDetermination *)
- Add(destAdr, nextHop);
- END;
- END;
- RETURN nextHop;
- END GetNextHop;
- (** Get PMTU of a address *)
- 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;
- (** Next hop determination *)
- PROCEDURE NextHopDetermination(destAdr: IP.Adr): IP.Adr;
- VAR
- longestPrefix: PrefixesEntry;
- nextHop: IP.Adr;
- BEGIN
- (* perform longest prefix match against prefix list *)
- longestPrefix := interface.prefixes.FindLongestMatch(destAdr);
- IF longestPrefix = NIL THEN
- (* select a router from the Default Router list *)
- nextHop := interface.routers.GetRouter();
- IF IP.IsNilAdr(nextHop) THEN
- (* no default router is found assume destAdr is on-link, therefore
- next hop = destination address *)
- nextHop := destAdr;
- END;
- ELSE
- (* destination is on-link: nextHop is same as destination *)
- nextHop := destAdr;
- END;
- RETURN nextHop;
- END NextHopDetermination;
- (** When a router become invalid update all affected entries *)
- 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;
- (** Clears the destination cache *)
- PROCEDURE Clear;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO CacheSize - 1 DO
- destArray[i] := NIL;
- END;
- END Clear;
- END DestCache;
- TYPE
- (** Neighbor cache. *)
- NeighborCache = OBJECT
- VAR
- neighbors: ARRAY CacheSize OF NeighborCacheEntry;
- (* Array which holds all neighbor entries. The last byte of the neighbor IP is the index
- of the array *)
- interface: Interface; (* Interface the neighbor cache operates on *)
- (** Constructor: Initializes neighbor array.*)
- PROCEDURE &Constr *(int: Interface);
- VAR
- i: LONGINT;
- BEGIN
- interface := int;
- FOR i := 0 TO (CacheSize - 1) DO
- neighbors[i] := NIL;
- END;
- END Constr;
- (** Add an IP to the neighbor cache *)
- PROCEDURE Add(neighborIP: IP.Adr);
- VAR
- newNeighborEntry: NeighborCacheEntry;
- neighborItem: NeighborCacheEntry;
- BEGIN {EXCLUSIVE}
- (* look if already an entry exists *)
- newNeighborEntry := Get(neighborIP);
- IF newNeighborEntry = NIL THEN
- NEW(newNeighborEntry);
- (* initialize neighbor cache entry to incomplete*)
- newNeighborEntry.next := NIL;
- newNeighborEntry.neighborIP := neighborIP;
- newNeighborEntry.reachability := Incomplete;
- newNeighborEntry.isRouter := FALSE;
- newNeighborEntry.queuedPackets := NIL;
- newNeighborEntry.probes := 0;
- Kernel.SetTimer(newNeighborEntry.lastConfirmation, 0);
- (* put into neighbor cache *)
- 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;
- (* Remove *)
- PROCEDURE Remove(neighborIP: IP.Adr);
- VAR
- neighborItem: NeighborCacheEntry;
- BEGIN {EXCLUSIVE}
- neighborItem := neighbors[ORD(neighborIP.ipv6Adr[15])];
- (* first element *)
- 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
- (* found *)
- neighborItem.next := neighborItem.next.next;
- END;
- END;
- END Remove;
- (** Delete expired neighbor entries *)
- 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
- (* first item *)
- 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;
- (* Deliver a neighbor cache entry *)
- 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;
- (* Return link-layer address of a IP address *)
- 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
- (* check timers *)
- IF Kernel.Expired(neighborItem.lastConfirmation) THEN
- (* Send a Neighbor Solicitation message *)
- sendNeighborSolicitation(interface, neighborItem.linkAdr, adr, FALSE);
- END;
- linkAdr := neighborItem.linkAdr;
- found := TRUE;
- ELSE
- found := FALSE;
- END;
- RETURN found;
- END GetLinkLayerAdr;
- (* Initiate address resolution *)
- PROCEDURE AddressResolution(neighborIP: IP.Adr; CONST l3hdr, l4hdr, data: ARRAY OF CHAR; h3len, h4len, dofs, dlen: LONGINT);
- VAR
- neighborEntry: NeighborCacheEntry;
- packetQueue: PacketQueue;
- packetQueueItem: PacketQueue;
- linkDst: Network.LinkAdr;
- i: LONGINT;
- BEGIN
- (* create a new neighbor cache entry *)
- Add(neighborIP);
- neighborEntry := Get(neighborIP);
- IF neighborEntry # NIL THEN
- (* Queue packet *)
- 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;
- (* link and IP destination addresses are the solicited node addresses *)
- linkDst := linkMulticastAllNodesAdr;
- linkDst[2] := 0FFX;
- linkDst[3] := neighborIP.ipv6Adr[13];
- linkDst[4] := neighborIP.ipv6Adr[14];
- linkDst[5] := neighborIP.ipv6Adr[15];
- (* Send a Neighbor Solicitation message *)
- sendNeighborSolicitation(interface, linkDst, neighborIP, TRUE);
- END;
- END AddressResolution;
- (* Send queued Packets *)
- 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
- (* fragment packet *)
- 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
- (* Prefix list *)
- Prefixes = OBJECT
- VAR
- prefixes: PrefixesEntry;
- (* Constructor: Initializes prefixes.*)
- PROCEDURE &Constr*;
- BEGIN
- prefixes := NIL;
- END Constr;
- (* Add a prefix. Lifetime in seconds *)
- PROCEDURE Add(prefix: IP.Adr; lifetime: LONGINT);
- VAR
- prefixItem: PrefixesEntry;
- BEGIN {EXCLUSIVE}
- NEW(prefixItem);
- prefixItem.prefix := prefix;
- Kernel.SetTimer(prefixItem.lifetime, lifetime * 1000); (* Milliseconds *)
- prefixItem.next := prefixes;
- prefixes := prefixItem;
- END Add;
- (* Remove a prefix *)
- PROCEDURE Remove(prefix: IP.Adr);
- VAR
- prefixItem: PrefixesEntry;
- BEGIN {EXCLUSIVE}
- prefixItem := prefixes;
- IF prefixItem # NIL THEN
- (* first element? *)
- 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
- (* remove item from list *)
- prefixItem.next := prefixItem.next.next;
- END;
- END;
- END;
- END Remove;
- (** Delete expired prefixes *)
- 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
- (* first item *)
- 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;
- (* Deliver a specific prefix entry *)
- 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;
- (* Is there a prefix which matches adr *)
- 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
- (* Default Router List *)
- Routers = OBJECT
- VAR
- routers: RoutersEntry;
- lastRobinRouter: RoutersEntry; (* last choosen Router with round robin *)
- interface: Interface;
- (* Constructor: Initializes routers.*)
- PROCEDURE &Constr*(int: Interface);
- BEGIN
- routers := NIL;
- lastRobinRouter := routers;
- interface := int;
- END Constr;
- (* Add a default router *)
- PROCEDURE Add(routerIP: IP.Adr; routerLinkAdr: Network.LinkAdr; lifetime: LONGINT): RoutersEntry;
- VAR
- router: RoutersEntry;
- neighbor: NeighborCacheEntry;
- BEGIN {EXCLUSIVE}
- lifetime := lifetime * 1000; (* lifetime in milliseconds *)
- router := Get(routerIP);
- IF router = NIL THEN
- (* default routers does not exist *)
- 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;
- (* Remove a default router *)
- 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
- (* first element *)
- routers := routerItem.next;
- ELSE
- routerItemPrev.next := routerItem.next;
- END;
- END;
- END Remove;
- (* Deliver a specific router *)
- 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;
- (* Deliver a default router *)
- PROCEDURE GetRouter(): IP.Adr;
- VAR
- routersItem: RoutersEntry;
- routerAdr: IP.Adr;
- searchReachable: BOOLEAN;
- BEGIN
- (* deliver router: first searched for REACHABLES then other in round robin fashion *)
- routerAdr := IP.NilAdr;
- IF routers # NIL THEN
- IF lastRobinRouter = NIL THEN
- lastRobinRouter := routers;
- END;
- routersItem := lastRobinRouter.next;
- IF routersItem = NIL THEN
- (* start from begin *)
- routersItem := routers.next;
- END;
- searchReachable := TRUE;
- LOOP
- IF routersItem = NIL THEN
- (* start from begin *)
- routersItem := routers;
- END;
- IF (routersItem = lastRobinRouter) & ~searchReachable THEN
- IF routersItem.router.reachability # Incomplete THEN
- routerAdr := routersItem.router.neighborIP;
- ELSE
- (* searched for reachable and other found nothing *)
- lastRobinRouter := NIL;
- routerAdr := IP.NilAdr;
- EXIT;
- END;
- END;
- IF (routersItem = lastRobinRouter) & searchReachable THEN
- (* searched for reachable found nothing *)
- searchReachable := FALSE;
- IF routersItem.router.reachability = Reachable THEN
- (* only a single reachable router *)
- EXIT;
- END;
- routersItem := routersItem.next;
- IF routersItem = NIL THEN
- routersItem := routers;
- END;
- END;
- IF searchReachable & (routersItem.router.reachability = Reachable) THEN
- (* found a reachable router *)
- routerAdr := routersItem.router.neighborIP;
- lastRobinRouter := routersItem;
- EXIT;
- END;
- IF ~searchReachable & (routersItem.router.reachability # Incomplete) THEN
- (* found a stale, delay or probe router *)
- routerAdr := routersItem.router.neighborIP;
- lastRobinRouter := routersItem;
- EXIT;
- END;
- routersItem := routersItem.next;
- END;
- END;
- RETURN routerAdr;
- END GetRouter;
- (** Delete expired routers *)
- 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
- (* first item *)
- 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;
- (** Writes all default routers *)
- 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
- (** When multiple network devices are present the IPv6 implementation is unable to know on which interface
- a local address is reachable. To prevent sending a lot of neighbor discovery messages this cache is created. *)
- LocalAdrCache = OBJECT
- VAR
- localAdrs: ARRAY CacheSize OF LocalAdrCacheEntry;
- (* Array which holds all local address entries. The last byte of the neighbor IP is the index
- of the array *)
- PROCEDURE &Constr*;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO (CacheSize - 1) DO
- localAdrs[i] := NIL;
- END;
- END Constr;
- (** Add an IP to the neighbor cache *)
- PROCEDURE Add(localIP: IP.Adr; interface: Interface);
- VAR
- newLocalAdrEntry: LocalAdrCacheEntry;
- localAdrItem: LocalAdrCacheEntry;
- BEGIN {EXCLUSIVE}
- (* look if already an entry exists *)
- newLocalAdrEntry := Get(localIP);
- IF newLocalAdrEntry = NIL THEN
- NEW(newLocalAdrEntry);
- (* initialize local adr cache entry *)
- newLocalAdrEntry.next := NIL;
- newLocalAdrEntry.localAdr := localIP;
- newLocalAdrEntry.interface := interface;
- Kernel.SetTimer(newLocalAdrEntry.created, LongTimerTimeout);
- (* put into local address cache *)
- 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;
- (* Remove *)
- PROCEDURE Remove(localIP: IP.Adr);
- VAR
- localAdrItem: LocalAdrCacheEntry;
- BEGIN {EXCLUSIVE}
- localAdrItem := localAdrs[ORD(localIP.ipv6Adr[15])];
- (* first element *)
- 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
- (* found *)
- localAdrItem.next := localAdrItem.next.next;
- END;
- END;
- END Remove;
- (** Delete expired local address entries *)
- 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
- (* first item *)
- 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;
- (* Deliver a local address cache entry *)
- 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;
- (* Deliver the interface according to a local address *)
- 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;
- (* Autoconfiguration *)
- autoconfigurated*: BOOLEAN;
- autoconfigState: LONGINT;
- createStatelessInterface*: BOOLEAN;
- createStatefulInterface: BOOLEAN;
- routerSolCount: LONGINT;
- (* Timers *)
- shortTimer: Kernel.Timer;
- longTimer: Kernel.MilliTimer;
- duplicateTimer: Kernel.MilliTimer;
- intName: IP.Name;
- intv6: Interface;
- int: IP.Interface;
- res: WORD;
- fragmentList: FragmentList;
- (* router *)
- isRouter*: BOOLEAN;
- routerConfig: RouterConfig;
- nextRtrAdvertisement: LONGINT; (* When should the next unsolicited router advertisement be sent; in numbers of shortTimer *)
- (** Constructor - Open an IPv6 interface and add it to the IP configuration.
- "name" must be a unique name for this interface (tested in "AddInterface").
- "dev" must be a Network.LinkDevice that can be used in other interfaces => multiple IP addresses on the
- same interface. *)
- PROCEDURE &Constr*(name: IP.Name; dev: Network.LinkDevice; VAR res: WORD);
- 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;
- (* create caches *)
- NEW(prefixes);
- NEW(routers, SELF);
- NEW(destCache, SELF, prefixes);
- NEW(neighborCache, SELF);
- (* set name *)
- IF name = "" THEN
- res := IP.NoInterfaceName;
- RETURN;
- END;
- COPY(name, SELF.name);
- (* init addresses *)
- localAdr := IP.NilAdr;
- maskAdr := IP.NilAdr;
- gatewayAdr := IP.NilAdr;
- subnetAdr := IP.NilAdr;
- linkLocalSolicitedNodeAdr := IP.NilAdr;
- (* broadAdr is Link-local multicast address *)
- broadAdr := IP.NilAdr;
- broadAdr.usedProtocol := IP.IPv6;
- broadAdr.ipv6Adr[0] := 0FFX;
- broadAdr.ipv6Adr[1] := 2X;
- broadAdr.ipv6Adr[15] := 1X;
- broadAdr.data := 0;
- (* init DNS *)
- DNScount := 0;
- closed := FALSE;
- IP.AddInterface(SELF, res);
- IF res = IP.Ok THEN
- (* install receivers *)
- dev.InstallReceiver(SELF, EtherTypeIP, IPInput, IsPacketValid, IsPacketForSingleInt, IsPacketAccepted
- , IP.IPForwarding); (* IPv6 *)
- (* Update list of devices *)
- 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;
- (** Close and deactivate the interface, i.e. remove it from the configuration. *)
- PROCEDURE Close*;
- VAR
- i: LONGINT;
- BEGIN {EXCLUSIVE}
- ASSERT(~closed);
- dev.RemoveReceiver(SELF, EtherTypeIP);
- closed := TRUE;
- shortTimer.Wakeup;
- (* To be "sure" that the active body is terminated *)
- FOR i := 0 TO 9999 DO
- Objects.Yield;
- END;
- IP.RemoveInterface(SELF);
- END Close;
- (** Set addresses. Is normally called just after instanciation, but can also be called later, e.g. by DHCP.
- If "gatewayAdr" is not "NilAdr", it will be added to the default router list. *)
- PROCEDURE SetAdrs*(localAdr, prefixAdr, defaultRouterAdr: IP.Adr; VAR res: WORD);
- 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
- (* prefix has to be set! *)
- res := IP.PrefixNotSet;
- RETURN;
- END;
- (* Check if addresses are of same protocol as interface *)
- 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;
- (* set addresses *)
- 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
- (* Duplicate Address Detection *)
- Kernel.SetTimer(duplicateTimer, ShortTimerTimeout);
- sendNeighborSolicitation(SELF, linkMulticastSolicited, linkLocalSolicitedNodeAdr, FALSE);
- END;
- res := IP.Ok;
- (* When this interface a link-local interface is update devList *)
- IF IsLinkLocalAdr(localAdr) THEN
- devListItem := devList;
- WHILE (devListItem # NIL) & (devListItem.device # dev) DO
- devListItem := devListItem.next;
- END;
- devListItem.linkLocalInterface := SELF;
- END;
- ELSE
- (* make nothing *)
- END;
- END SetAdrs;
- (* Receive an IP packet *)
- 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; (* not correct but otherwise fragmented packet are not accepted *)
- END;
- IF ((payloadLength + MinIPHdrLen) <= buffer.len) THEN
- (* payloadLength = 0: Jumbo-Payload *)
- srcAdr := ReadSrcAdr (buffer);
- dstAdr := ReadDestAdr (buffer);
- IF (nextHeader = IPv6FragmentType) & (buffer.nextFragment = NIL) THEN
- (* a fragmented packet try to reassemble it *)
- INC(buffer.ofs, MinIPHdrLen);
- DEC(buffer.len, MinIPHdrLen);
- AddToFragmentList(srcAdr, dstAdr, buffer);
- incomingFragment := TRUE;
- END;
- IF ~IsMulticast(srcAdr) & ~incomingFragment THEN
- IF ~IsMulticast(dstAdr) THEN
- (* unicast *)
- IF (IP.AdrsEqual(dstAdr, localAdr)) THEN
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- buffer.l3ofs := buffer.ofs;
- IF buffer.nextFragment # NIL THEN
- (* adjust offset when a packet is fragmented*)
- 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);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Machine.AtomicInc(IP.NIPNoReceiver);
- END;
- ELSIF IP.IPForwarding THEN
- (* forward packet *)
- (* look if there is a routing header *)
- 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
- (* only forward packets with hop limit > zero *)
- IF ORD(forwardBuffer.data[7]) > 0 THEN
- (* Decrement hop limit *)
- 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
- (* do receiver upcall *)
- buffer.l3ofs := buffer.ofs;
- IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
- (* adjust offset when a packet is fragmented*)
- 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);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Machine.AtomicInc(IP.NIPNoReceiver);
- END;
- ELSIF ORD(dstAdr.ipv6Adr[15]) = 1 THEN
- (* multicast to node *)
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- buffer.l3ofs := buffer.ofs;
- IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
- (* adjust offset when a packet is fragmented*)
- 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);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Machine.AtomicInc(IP.NIPNoReceiver);
- END;
- ELSIF IsMulticast(dstAdr) & (isRouter) & (ORD(dstAdr.ipv6Adr[15]) = 2) THEN
- (* multicast packet for router; to capture these packets IPForwarding must be
- turned on *)
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- buffer.l3ofs := buffer.ofs;
- IF (buffer.nextFragment # NIL) & (nextHeader = IPv6FragmentType) THEN
- (* adjust offset when a packet is fragmented*)
- 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);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- 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;
- (* Exit and return buffer here because it is no longer used *)
- IF ~incomingFragment THEN
- Network.ReturnBuffer(buffer);
- END;
- END IPInput;
- (** Send an IP packet on this interface. Send it directly without lookup of destination cache, etc... *)
- 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; (* just in case of concurrent Send/Close *)
- (* set IP header *)
- l3hdr[0] := CHR(IP.IPv6*10H); (* IP version and first part of traffic class *)
- l3hdr[1] := 0X; (* second part of traffic class and first part of flow label *)
- Network.Put2(l3hdr, 2, 0); (* second part of flow label *)
- Network.PutNet2(l3hdr, 4, h4len+dlen); (* Payload length *)
- l3hdr[6] := CHR(nextHeader); (* next header *)
- l3hdr[7] := CHR(hopLimit); (* Hop limit *)
- (* set local address *)
- FOR i := 0 TO 15 DO
- l3hdr[i+8] := localAdr.ipv6Adr[i];
- END;
- (* set foreign address *)
- FOR i := 0 TO 15 DO
- l3hdr[i+24] := destAdr.ipv6Adr[i];
- END;
- (* perform sending *)
- DoSendDirectly(linkDst, destAdr, l3hdr, l4hdr, data, MinIPHdrLen, h4len, dofs, dlen);
- END SendDirectly;
- (* Internal procedure to perform the rest of the send operation. Without destination cache lookup etc...,
- fragmentation is not supported! *)
- 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
- (* send local loopback. If destAdr is a node local adr packet sould only be received from
- the same interfaces as it was sent *)
- 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
- (* Network.TypePointToPoint *)
- Machine.AtomicInc(IP.NIPSentPointToPoint);
- dev.Send(linkDst,
- EtherTypeIP,
- l3hdr,
- l4hdr,
- data,
- h3len,
- h4len,
- dofs,
- dlen,
- IP.AdrsEqual (destAdr, localAdr));
- END;
- END;
- END DoSendDirectly;
- (** Send an IP packet on this interface. *)
- PROCEDURE Send*(nextHeader: LONGINT; destAdr: IP.Adr; CONST 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; (* just in case of concurrent Send/Close *)
- (* set IP header *)
- l3hdr[0] := CHR(IP.IPv6*10H); (* IP version and first part of traffic class *)
- l3hdr[1] := 0X; (* second part of traffic class and first part of flow label *)
- Network.Put2(l3hdr, 2, 0); (* second part of flow label *)
- Network.PutNet2(l3hdr, 4, h4len+dlen); (* Payload length *)
- l3hdr[6] := CHR(nextHeader); (* next header *)
- l3hdr[7] := CHR(hopLimit); (* Hop limit *)
- (* set local address *)
- FOR i := 0 TO 15 DO
- l3hdr[i+8] := localAdr.ipv6Adr[i];
- END;
- (* set foreign address *)
- FOR i := 0 TO 15 DO
- l3hdr[i+24] := destAdr.ipv6Adr[i];
- END;
- (* perform sending *)
- DoSend(destAdr, l3hdr, l4hdr, data, MinIPHdrLen, h4len, dofs, dlen);
- END Send;
- (* Internal procedure to perform the rest of the send operation. Used by "Send" and for IP forwarding. *)
- PROCEDURE DoSend*(destAdr: IP.Adr; CONST 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;
- (* Get Path Maximum transmission unit *)
- pmtu := destCache.GetPMTU(destAdr);
- pmtu := MIN(pmtu, linkMTU);
- pmtu := MIN(pmtu, dev.mtu);
- IF h3len+h4len+dlen > pmtu THEN
- (* fragment packet *)
- toFragment := TRUE;
- END;
- IF dev.type = Network.TypeEthernet THEN
- IF IsNodeLocalAdr(destAdr) OR IsLinkLocalMulticastAdr(destAdr) OR IP.AdrsEqual(destAdr, localAdr) THEN
- (* send local loopback. If destAdr is a node local adr packet sould only be received from
- the same interfaces as it was sent *)
- Machine.AtomicInc(IP.NIPSentLocalLoopback);
- dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdr, data, h3len, h4len, dofs, dlen, TRUE);
- ELSE
- (* check destination cache for next-hop *)
- nextHop := destCache.GetNextHop(destAdr);
- (* Neighbor cache lookup for link-layer address of next hop *)
- IF ~neighborCache.GetLinkLayerAdr(nextHop, linkDst) THEN
- (* no link-layer address found initiate address resolution packet will be queued*)
- 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
- (* Network.TypePointToPoint *)
- Machine.AtomicInc(IP.NIPSentPointToPoint);
- dev.Send(linkDst,
- EtherTypeIP,
- l3hdr,
- l4hdr,
- data,
- h3len,
- h4len,
- dofs,
- dlen,
- IP.AdrsEqual (destAdr, localAdr));
- END;
- END DoSend;
- (** Fragment packets and send them *)
- 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; (* fragment header *)
- dataFragment: POINTER TO ARRAY OF CHAR; (* fragment data *)
- fragmentHdrSet: SET;
- fragID: LONGINT;
- i: LONGINT;
- BEGIN
- fragID := GetFragmentID();
- (* do fragmentation *)
- maxDataLen := pmtu - MinIPHdrLen - FragmentHdrLen;
- DEC(maxDataLen, maxDataLen MOD 8); (* 64-bit boundary *)
- fragmentOffset := 0;
- (* change IP header *)
- oldNextHeader := ORD(l3hdr[6]); (* next header *)
- l3hdr[6] := CHR(IPv6FragmentType);
- (* build fragment header *)
- NEW(l4hdrFragment, FragmentHdrLen);
- fragmentHdrSet := {};
- fragmentHdrSet := fragmentHdrSet + {0};
- Network.PutNet4(l4hdrFragment^, 0, SYSTEM.VAL(LONGINT, fragmentHdrSet));
- l4hdrFragment^[0] := CHR(oldNextHeader);
- Network.PutNet4(l4hdrFragment^, 4, fragID);
- (* fragment data *)
- 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);
- (* adjust payload length *)
- Network.PutNet2(l3hdr, 4, maxDataLen + FragmentHdrLen);
- (* first packet *)
- dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdrFragment^, dataFragment^, h3len, FragmentHdrLen, 0, maxDataLen, FALSE);
- WHILE fragmentOffset < h4len + dlen DO
- IF fragmentOffset + maxDataLen > h4len + dlen THEN
- (* last fragment *)
- fragmentHdrSet := SYSTEM.VAL(SET, 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);
- (* fragment data *)
- FOR i := 0 TO dlen - fragmentOffset - 1 DO
- dataFragment^[i] := data[i + fragmentOffset];
- END;
- (* adjust payload length *)
- Network.PutNet2(l3hdr, 4, dlen - fragmentOffset + FragmentHdrLen);
- dev.Send(linkDst, EtherTypeIP, l3hdr, l4hdrFragment^, dataFragment^, h3len, FragmentHdrLen, 0, dlen - fragmentOffset, FALSE);
- INC(fragmentOffset, maxDataLen);
- ELSE
- (* fragment in the middle *)
- fragmentHdrSet := SYSTEM.VAL(SET, 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);
- (* fragment data *)
- 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;
- (** Enumerate all ARP table entries. In IPv6 Enumerate the Neighbors*)
- PROCEDURE ARPEnumerate*(handle: IP.ARPHandler);
- (* This procedure has to be inherited but is ignored because in IPv6 ARP is not used *)
- END ARPEnumerate;
- (** Performs a check for Network if a packet is accepted by this interface *)
- PROCEDURE IsPacketAccepted(buffer: Network.Buffer): BOOLEAN;
- VAR
- i: LONGINT;
- isAccepted: BOOLEAN;
- BEGIN
- isAccepted := TRUE;
- IF ~IP.IsNilAdr(localAdr) THEN
- (* When interface is not yet configurated take all packets *)
- (* If it is a link-local interface take link-local multicast packets *)
- 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;
- (** Checks if an IPv6 address is a multicast address in IPv6 there are no broadcasts *)
- PROCEDURE IsBroadcast*(adr: IP.Adr) : BOOLEAN;
- BEGIN
- RETURN IsMulticast (adr);
- END IsBroadcast;
- (** Check if adr is a local multicast address *)
- PROCEDURE IsMulticast*(adr: IP.Adr) : BOOLEAN;
- BEGIN
- IF adr.ipv6Adr[0] = 0FFX THEN
- RETURN TRUE;
- ELSE
- RETURN FALSE;
- END;
- END IsMulticast;
- (* Checks if adr is a solicited node address *)
- 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;
- (* Check if adr is a node-local adr: localAdr, nodeLocalMulticastAdr *)
- 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;
- (* Reads the source address of a IP packet buffer *)
- 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;
- (* Reads the destination address of a IP packet buffer *)
- 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;
- (* writes the interface ID to a IPv6 address (last 64 bits) *)
- PROCEDURE SetInterfaceID*(VAR ip: IP.Adr);
- VAR
- bitSet: SET;
- BEGIN
- (* IEEE 802 Address to IPv6 Interface Identifier:
- cccccc00 cccccccc cccccccc xxxxxxxx xxxxxxxx xxxxxxxx
- IEEE 802 Address
- ccccccc00 cccccccc cccccccc 11111111 11111110 xxxxxxxx xxxxxxxx xxxxxxxx
- EUI-64 address
- cccccc10 cccccccc cccccccc 11111111 11111110 xxxxxxxx xxxxxxxx xxxxxxxx
- *)
- 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]);
- (* toggle second bit *)
- IF 1 IN bitSet THEN
- bitSet := bitSet - {1};
- ELSE
- bitSet := bitSet + {1};
- END;
- ip.ipv6Adr[8] := SYSTEM.VAL(CHAR, bitSet);
- END SetInterfaceID;
- (** Creates a pseudo-header for checksum calculation (TCP/UDP) and returns the length of this header *)
- PROCEDURE WritePseudoHeader*(VAR pseudoHdr: ARRAY OF CHAR;
- src, dst: IP.Adr;
- nextHeader, pktLengthUpperLayer: LONGINT): LONGINT;
- VAR
- i: LONGINT;
- tmpAdr: ARRAY 4 OF LONGINT;
- BEGIN
- (* UDP/TCP Pseudo-header (for checksum calculation)
- 00 128 source address
- 16 128 destination address
- 32 32 Upper Layer Packet Length
- 36 24 zero = 0
- 39 8 Next header *)
- IF DEBUG THEN
- ASSERT (IP.IsNilAdr(src) OR (src.usedProtocol = IP.IPv6));
- ASSERT (IP.IsNilAdr(dst) OR (dst.usedProtocol = IP.IPv6));
- END;
- (* cast src adr to LONGINT array *)
- 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]); (* local IP address *)
- END;
- (* cast dst adr to LONGINT array *)
- 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]); (* foreign IP address *)
- END;
- (* Upper Layer Packet Length *)
- Network.PutNet4(pseudoHdr, 32, pktLengthUpperLayer);
- (* Zero and next header *)
- Network.PutNet4(pseudoHdr, 36, nextHeader);
- RETURN 40; (* IPv6 pseudo header length *)
- END WritePseudoHeader;
- (* Received a neighbor solicitation message *)
- 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
- (* send a soliciated neighbor advertisement message *)
- sendNeighborAdvertisement(int(Interface), buffer.src, srcAdr, TRUE);
- END;
- Network.ReturnBuffer(buffer);
- END ReceiveNeighborSolicitation;
- (* Received a neighbor advertisement message *)
- PROCEDURE ReceiveNeighborAdvertisement* (srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
- VAR
- neighborEntry: NeighborCacheEntry;
- flags: SET;
- routerFlag: BOOLEAN;
- solicitedFlag: BOOLEAN;
- overrideFlag: BOOLEAN;
- linkAdrsEqual: BOOLEAN; (* Are both link-addresses equal (in neighbor advertisement and cache *)
- hasTargetLinkOption: BOOLEAN;
- targetLinkAdr: Network.LinkAdr;
- newRouter: IP.Adr;
- BEGIN
- (* Check for duplicated address *)
- 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
- (* make a new entry. According to RFC 2461 entry should not be added. But because of V6InterfaceByDstIP
- unsolicited neigbor advertisements have to be accepted *)
- neighborCache.Add(srcAdr);
- neighborEntry := neighborCache.Get(srcAdr);
- END;
- (* read flags *)
- 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
- (* save link address *)
- 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
- (* reachability is not incomplete *)
- IF (buffer.len - buffer.ofs) > (MinIPHdrLen + IP.ICMPHdrLen + NeighborHdrLen) THEN
- (* Option is available *)
- IF (buffer.data[buffer.ofs + NeighborHdrLen] = 2X) & (buffer.data[buffer.ofs + NeighborHdrLen + 1] = 1X) THEN
- (* Target link-layer address option *)
- 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
- (* Update neighbor cache *)
- 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
- (* changed from a router to normal host *)
- routers.Remove(neighborEntry.neighborIP);
- newRouter := routers.GetRouter();
- destCache.ChangeDests(neighborEntry.neighborIP, newRouter);
- END;
- neighborEntry.isRouter := routerFlag;
- END;
- END;
- END;
- Network.ReturnBuffer(buffer);
- END ReceiveNeighborAdvertisement;
- (* initiate a router solicitation *)
- PROCEDURE RouterSolicitation*;
- BEGIN
- sendRouterSolicitation(SELF);
- INC(routerSolCount);
- END RouterSolicitation;
- (* Receive a Router Advertisement message *)
- 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: WORD;
- tmpStr: ARRAY 8 OF CHAR;
- (* Parse options of a router advertisement message return FALSE on error *)
- PROCEDURE ParseRouterAdvOptions(): BOOLEAN;
- BEGIN
- WHILE buffer.len > 0 DO
- (* Options are available *)
- CASE ORD(buffer.data[buffer.ofs]) OF
- IP.ICMPSrcLLAdrOptionType:
- (* Check length field *)
- IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
- RETURN FALSE;
- END;
- hasSrcLinkLayerOption := TRUE;
- icmpLinkLayerAdrOption(buffer, linkAdr);
- |IP.ICMPPrefixInfoOptionType:
- (* Check length field *)
- 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:
- (* Check length field *)
- IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
- RETURN FALSE;
- END;
- hasMTUOption := TRUE;
- icmpMTUOption(buffer, mtu);
- mtu := MIN(mtu, linkMTU);
- mtu := MIN(mtu, dev.mtu);
- |IP.ICMPAdvIntOptionType:
- (* Check length field *)
- IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
- RETURN FALSE;
- END;
- icmpAdvIntervalOption(buffer);
- |IP.ICMPHomeAgOptionType:
- (* Check length field *)
- IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
- RETURN FALSE;
- END;
- icmpHomeAgentInfoOption(buffer);
- |IP.ICMPRouteOption:
- (* Check length field *)
- IF ORD(buffer.data[buffer.ofs + 1]) <= 0 THEN
- RETURN FALSE;
- END;
- icmpRouteInfoOption(buffer);
- ELSE
- (* packet is not well-formed *)
- IF DEBUG THEN
- ASSERT(TRUE);
- END;
- RETURN FALSE;
- END;
- END;
- RETURN TRUE; (* no error occured *)
- END ParseRouterAdvOptions;
- (* create IPv6-interfaces if necessary *)
- PROCEDURE createInterfaces;
- VAR
- i: LONGINT;
- currentPrefix: LONGINT;
- BEGIN
- (* autoconfiguration of interfaces *)
- IF autoconfigurated THEN
- IF createStatelessInterface THEN
- (* FOR i := 0 TO (nbrOfPrefixOpt - 1) DO if this for loop is used programm crashes *)
- 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;
- (* set available DNS *)
- FOR i := 0 TO DNScount - 1 DO
- int.DNSAdd(DNS[i]);
- END;
- (* use the same caches for interfaces on the same device *)
- 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
- (* (* 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;
- *) END;
- END;
- END createInterfaces;
- BEGIN
- hasSrcLinkLayerOption := FALSE;
- hasMTUOption := FALSE;
- nbrOfPrefixOpt := 0;
- (* Checks if a router advertisement message is valid *)
- (* Accept only link-local packets *)
- IF ~AdrsPartEqual(srcAdr, linkLocalPrefix, 0, (linkLocalPrefix.data DIV 8) - 1 (* number of bytes *)) THEN
- Network.ReturnBuffer(buffer);
- RETURN;
- END;
- (* Hop limit = 255 *)
- IF buffer.data[7] # 0FFX THEN
- RETURN
- END;
- (* ICMP Code field = 0 *)
- IF buffer.data[buffer.ofs - 3] # 0X THEN
- RETURN;
- END;
- (* read packet contents *)
- hopLimit := ORD(buffer.data[buffer.ofs]);
- (* read flags *)
- 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);
- (* Parse available options *)
- IF ~ ParseRouterAdvOptions() THEN
- Network.ReturnBuffer(buffer);
- RETURN;
- END;
- (* Update default router list *)
- router := routers.Get(srcAdr);
- IF (router = NIL) & (routerLifetime # 0) THEN
- (* Add a new default router *)
- 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
- (* update destination cache for destinations using this router *)
- 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;
- (* go through all prefix options and update them *)
- 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
- (* timeout prefix *)
- prefixes.Remove(localPrefix[i]);
- ELSE
- Kernel.SetTimer(prefixItem.lifetime, validLifetime[i] * 1000); (* milliseconds *)
- END;
- END;
- END;
- END;
- IF managedFlag OR otherStatefulFlag THEN
- createStatefulInterface := TRUE;
- END;
- (* create necessary IPv6-interfaces *)
- createInterfaces;
- Network.ReturnBuffer(buffer);
- END ReceiveRouterAdvertisement;
- (** Receive a router solicitation message *)
- PROCEDURE ReceiveRouterSolicitation*;
- BEGIN
- IF isRouter THEN
- (* send a solicited router advertisement *)
- sendRouterAdvertisement(SELF, linkLocalMulticastNodeAdr, linkMulticastAllNodesAdr, routerConfig);
- END;
- END ReceiveRouterSolicitation;
- (* Receive a packet too big ICMP message *)
- PROCEDURE ReceivePacketTooBig*(from: IP.Adr; buffer: Network.Buffer);
- VAR
- newPMTU: LONGINT;
- BEGIN
- (* ICMP Code field = 0 *)
- IF buffer.data[buffer.ofs - 3] = 0X THEN
- newPMTU := Network.GetNet4(buffer.data, 0);
- destCache.ChangePMTU(from, newPMTU);
- END;
- Network.ReturnBuffer(buffer);
- END ReceivePacketTooBig;
- (** Configurate this interface as a router *)
- PROCEDURE ConfigAsRouter*(newRouterConfig: RouterConfig);
- VAR
- prefixConfigItem: PrefixConfig;
- intv6: Interface;
- count: LONGINT;
- tmpStr: ARRAY 8 OF CHAR;
- newLocalAdr: IP.Adr;
- res: WORD;
- 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;
- (* create an interface according to the router configuration *)
- 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;
- (* set available DNS *)
- FOR i := 0 TO DNScount - 1 DO
- intv6.DNSAdd(DNS[i]);
- END;
- (* use the same caches for interfaces on the same device *)
- intv6.routers := routers;
- intv6.prefixes := prefixes;
- intv6.neighborCache := neighborCache;
- intv6.destCache := destCache;
- END;
- END;
- INC(count);
- END;
- prefixConfigItem := prefixConfigItem.next;
- END;
- END ConfigAsRouter;
- (** Adds a packet to the fragment list *)
- PROCEDURE AddToFragmentList(srcAdr, dstAdr: IP.Adr; buffer: Network.Buffer);
- VAR
- fragmentListItem: FragmentList;
- newPacketFragmentItem: PacketFragment;
- packetFragmentItem: PacketFragment;
- fragmentID: LONGINT;
- (** Ad new fragmentItem *)
- 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); (* 60 seconds *)
- fragmentListItem.fragmentCount := 1;
- NEW(newPacketFragmentItem);
- newPacketFragmentItem.buffer := buffer;
- (* calculate fragment offset & more fragments flag *)
- buffer.data[buffer.ofs] := 0X;
- newPacketFragmentItem.fragmentOffset := Network.GetNet4(buffer.data, buffer.ofs);
- (* more fragments flag *)
- newPacketFragmentItem.moreFragments := 0 IN SYSTEM.VAL(SET, newPacketFragmentItem.fragmentOffset);
- newPacketFragmentItem.fragmentOffset := 8 * (newPacketFragmentItem.fragmentOffset DIV 8); (* shift 3 right times 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);
- (* Does already a entry exist *)
- 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
- (* insert fragmented packet into right position *)
- INC(fragmentListItem.fragmentCount);
- NEW(newPacketFragmentItem);
- newPacketFragmentItem.buffer := buffer;
- (* calculate fragment offset *)
- buffer.data[buffer.ofs] := 0X;
- newPacketFragmentItem.fragmentOffset := Network.GetNet4(buffer.data, buffer.ofs);
- (* more fragments flag *)
- newPacketFragmentItem.moreFragments := 0 IN SYSTEM.VAL(SET, newPacketFragmentItem.fragmentOffset);
- newPacketFragmentItem.fragmentOffset := 8 * (newPacketFragmentItem.fragmentOffset DIV 8);(* shift 3 right times 8 *)
- buffer.data[buffer.ofs] := CHR(fragmentListItem.nextHeader);
- packetFragmentItem := fragmentListItem.packets;
- LOOP
- IF (packetFragmentItem.next = NIL) & (packetFragmentItem.fragmentOffset <= newPacketFragmentItem.fragmentOffset) THEN
- (* last item *)
- 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
- (* new first elem *)
- fragmentListItem.packets := newPacketFragmentItem;
- ELSE
- (* elem in the middle *)
- newPacketFragmentItem.prev.next := newPacketFragmentItem;
- END;
- EXIT;
- END;
- packetFragmentItem := packetFragmentItem.next;
- END;
- (* Reassemble packets *)
- ReassembleFragments(fragmentListItem);
- END;
- END AddToFragmentList;
- (** Reassemble fragmented packets *)
- PROCEDURE ReassembleFragments(fragmentListItem: FragmentList);
- VAR
- packetFragmentItem: PacketFragment;
- currentFragmentOffset: LONGINT;
- lastPacketOk: BOOLEAN;
- lastFragment: PacketFragment;
- BEGIN
- (* 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);
- ELSE
- (* Check if all fragments are present *)
- packetFragmentItem := fragmentListItem.packets;
- currentFragmentOffset := 0;
- lastPacketOk := FALSE;
- WHILE (packetFragmentItem # NIL) & (currentFragmentOffset = packetFragmentItem.fragmentOffset) DO
- IF packetFragmentItem.next = NIL THEN
- (* last packet: no more fragments *)
- lastPacketOk := ~packetFragmentItem.moreFragments;
- lastFragment := packetFragmentItem;
- END;
- INC(currentFragmentOffset, packetFragmentItem.buffer.len - FragmentHdrLen);
- packetFragmentItem := packetFragmentItem.next;
- END;
- IF (packetFragmentItem = NIL) & lastPacketOk THEN
- (* Reassemble packet *)
- (* connect packets through nextFragment *)
- packetFragmentItem := fragmentListItem.packets;
- WHILE packetFragmentItem.next # NIL DO
- packetFragmentItem.buffer.nextFragment := packetFragmentItem.next.buffer;
- (* adjust offset *)
- 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;
- (** Delete a entry in the fragmentation list *)
- PROCEDURE DelFragmentListEntry(fragmentListEntry: FragmentList; returnBuffers: BOOLEAN);
- VAR
- fragmentListFind: FragmentList;
- BEGIN
- (* discard the fragmented packets *)
- IF returnBuffers THEN
- Network.ReturnBuffer(fragmentListEntry.packets.buffer);
- END;
- (* delete fragment list entry *)
- IF fragmentList = fragmentListEntry THEN
- (* delete first entry in fragment list *)
- fragmentList := fragmentListEntry.next;
- ELSE
- (* delete entry in the middle or at the end *)
- fragmentListFind := fragmentList;
- WHILE (fragmentListFind.next # NIL) & (fragmentListFind.next # fragmentListEntry) DO
- fragmentListFind := fragmentListFind.next;
- END;
- fragmentListFind.next := fragmentListFind.next.next;
- END;
- END DelFragmentListEntry;
- (** Writes the configuration of this interface *)
- 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
- (* Delegates *)
- 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;
- (* Link-Local prefix *)
- linkLocalPrefix: IP.Adr;
- (* Multicast addresses *)
- nodeLocalMulticastNodeAdr: IP.Adr;
- nodeLocalMulticastRouterAdr: IP.Adr;
- linkLocalMulticastNodeAdr*: IP.Adr;
- linkLocalMulticastRouterAdr*: IP.Adr;
- (* Ethernet multicast addresses *)
- linkMulticastAllNodesAdr*: Network.LinkAdr;
- linkMulticastAllRoutersAdr*: Network.LinkAdr;
- (* list of devices *)
- devList: DeviceList;
- (* local address cache *)
- localAdrCache: LocalAdrCache;
- (* fragmentation *)
- fragmentationID: LONGINT;
- fragmentListItem: FragmentList;
- (* random generator *)
- randomZ: LONGINT;
- (* Checks if a part of two addresses is equal *)
- 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;
- (** Checks if a buffer contains a valid IPv6 packet; this check is performed for Network *)
- PROCEDURE IsPacketValid(VAR buffer: Network.Buffer): BOOLEAN;
- VAR
- isValid: BOOLEAN;
- BEGIN
- isValid := FALSE;
- Machine.AtomicInc(IP.NIPRcvTotal);
- IF buffer.len >= MinIPHdrLen THEN
- IF 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;
- (** Performs a check for Network if a packet is for a single interface *)
- PROCEDURE IsPacketForSingleInt(buffer: Network.Buffer): BOOLEAN;
- BEGIN
- (* All IPv6 packets are delivered to only one interface *)
- RETURN TRUE;
- END IsPacketForSingleInt;
- (* Check if adr is a link-local multicast adr: linkLocalMulticastAdr *)
- 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;
- (* Check if adr is a link-local adr: FE80::/64 prefix *)
- 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;
- (** Delivers the right interface for a specific destination *)
- PROCEDURE V6InterfaceByDstIP(dstAdr: IP.Adr): IP.Interface;
- VAR
- retInt: Interface;
- devListItem: DeviceList;
- linkLocalInt: Interface;
- neighborCacheItem: NeighborCacheEntry;
- sleepTimer: Kernel.Timer;
- sleepCounter: LONGINT; (* 5 times 100 ms *)
- normalCase: BOOLEAN;
- intItem: IP.Interface;
- gw: IP.Interface;
- linkDst: Network.LinkAdr;
- devCount: LONGINT;
- BEGIN
- (* Problem: When two network devices are available it is impossible to know on
- which device a link-local address is. Therefore neigbor solicitations are sent on
- both devices. The procedure has then to wait until the neighbor advertisement
- arrives. *)
- retInt := NIL;
- devListItem := devList;
- NEW(sleepTimer);
- sleepCounter := 0;
- normalCase := TRUE;
- (* Look if an address is a link-local address *)
- IF IsLinkLocalAdr(dstAdr) THEN
- (* Are there multiple devices present *)
- 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
- (* search in neighbor cache *)
- devListItem := devList;
- WHILE devListItem # NIL DO
- linkLocalInt := devListItem.linkLocalInterface;
- IF linkLocalInt # NIL THEN
- (* search neighbor cache *)
- neighborCacheItem := linkLocalInt.neighborCache.Get(dstAdr);
- IF neighborCacheItem # NIL THEN
- retInt := linkLocalInt;
- END;
- (* look if the dstAdr is equal a local address *)
- IF IP.AdrsEqual(dstAdr, linkLocalInt.localAdr) THEN
- retInt := linkLocalInt;
- END;
- END;
- devListItem := devListItem.next;
- END;
- IF retInt = NIL THEN
- (* send neigbor solicitations on all devices *)
- devListItem := devList;
- WHILE devListItem # NIL DO
- IF (devListItem.linkLocalInterface # NIL) &
- (devListItem.linkLocalInterface IS Interface) &
- (devListItem.linkLocalInterface.dev.Linked() # Network.LinkNotLinked) THEN
- (* link and IP destination addresses are the solicited node addresses *)
- linkDst := linkMulticastAllNodesAdr;
- linkDst[2] := 0FFX;
- linkDst[3] := dstAdr.ipv6Adr[13];
- linkDst[4] := dstAdr.ipv6Adr[14];
- linkDst[5] := dstAdr.ipv6Adr[15];
- (* Send a Neighbor Solicitation message *)
- sendNeighborSolicitation(devListItem.linkLocalInterface(Interface), linkDst, dstAdr, TRUE);
- END;
- devListItem := devListItem.next;
- END;
- END;
- sleepTimer.Sleep(200);
- INC(sleepCounter);
- END;
- IF retInt # NIL THEN
- (* store interface in local address cache *)
- localAdrCache.Add(dstAdr, retInt);
- END;
- END;
- END;
- (* Normal case *)
- 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;
- (*
- (** Deliver the link-local interface of a certain device *)
- PROCEDURE GetLinkLocalInterface(dev: Network.LinkDevice): Interface;
- VAR
- devListItem: DeviceList;
- BEGIN
- devListItem := devList;
- WHILE (devListItem # NIL) & (devListItem.device # dev) DO
- devListItem := devListItem.next;
- END;
- IF devListItem # NIL THEN
- RETURN devListItem.linkLocalInterface;
- ELSE
- RETURN NIL;
- END;
- END GetLinkLocalInterface;
- *)
- (** Deliver a ID for packet fragmentation *)
- PROCEDURE GetFragmentID(): LONGINT;
- BEGIN {EXCLUSIVE}
- INC(fragmentationID);
- RETURN fragmentationID;
- END GetFragmentID;
- (** Parses the routing header extension *)
- 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);
- (* read values *)
- 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
- (* process next header *)
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- INC(buffer.ofs, hdrExtLen * 8 + RoutingHdrLen);
- DEC(buffer.len, hdrExtLen * 8 + RoutingHdrLen);
- receiver(int, nextHeader, srcAdr, dstAdr, buffer);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Network.ReturnBuffer(buffer);
- END;
- ELSIF IP.IPForwarding THEN
- IF hdrExtLen MOD 2 = 1 THEN
- (* odd header extension length *)
- sendICMPv6ParamProb(intv6, buffer, srcAdr, MinIPHdrLen + 2, 0);
- Network.ReturnBuffer(buffer);
- ELSE
- (* segments left not correct *)
- 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;
- (* swap dest adr and ith address *)
- 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);
- (* For forwarding set offset to IP level *)
- INC(buffer.len, buffer.ofs);
- buffer.ofs := 0;
- END;
- END;
- ELSE
- Network.ReturnBuffer(buffer);
- END;
- END;
- END RoutingExtHeader;
- (** Parses the hop-by-hop header extension, which is ignored up to now *)
- 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]);
- (* process next header *)
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- INC(buffer.ofs, hdrExtLen * 8 + HopByHopHdrLen);
- DEC(buffer.len, hdrExtLen * 8 + HopByHopHdrLen);
- receiver(intv6, nextHeader, srcAdr, dstAdr, buffer);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Network.ReturnBuffer(buffer);
- END;
- END HopByHopExtHeader;
- (** Parses the destination header extension, which is ignored up to now *)
- 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]);
- (* process next header *)
- receiver := IP.receivers[nextHeader];
- IF receiver # NIL THEN
- (* do receiver upcall *)
- INC(buffer.ofs, hdrExtLen * 8 + DestinationHdrLen);
- DEC(buffer.len, hdrExtLen * 8 + DestinationHdrLen);
- receiver(intv6, nextHeader, srcAdr, dstAdr, buffer);
- (* Exit here w/o returning buffer because it is passed to a receiver *)
- RETURN;
- ELSE
- Network.ReturnBuffer(buffer);
- END;
- END DestinationExtHeader;
- (** Deliver a random number between 0 and limit *)
- 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); (* must compute this in double precision, e.g. (m-1)/m *)
- END RandomNumber;
- PROCEDURE Cleanup;
- BEGIN
- (* Remove all interfaces *)
- WHILE IP.interfaces # NIL DO
- IP.interfaces.Close();
- END;
- END Cleanup;
- BEGIN
- (* link-local prefix *)
- linkLocalPrefix := IP.NilAdr;
- linkLocalPrefix.usedProtocol := IP.IPv6;
- linkLocalPrefix.ipv6Adr[0] := 0FEX;
- linkLocalPrefix.ipv6Adr[1] := 80X;
- linkLocalPrefix.data := 64;
- (* init multicast addresses *)
- 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;
- (* Init Ethernet Multicast addresses *)
- 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;
- (* random generator initialization *)
- 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:
- System.Free TraceRoute VNC Ping WMFTPClient FTPClient WebFTPServer TCPServices TLS InitNetwork Ping DHCP TCP DNS UDP ICMP IPv4 IPv6 IP~
- Start:
- InitNetwork.Init
- Compile:
- PC.Compile \s IP.Mod IPv4.Mod IPv6.Mod ICMP.Mod UDP.Mod DNS.Mod TCP.Mod DHCP.Mod InitNetwork.Mod WebFTPServer.Mod FTPClient.Mod WMFTPClient.Mod Ping.Mod VNC.Mod TraceRoute.Mod~
- History:
- 02.05.2005 eb Created.
- 07.2005 eb Cache added
|