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