12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173 |
- /** @file
- Implementation of Neighbor Discovery support routines.
- Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Ip6Impl.h"
- EFI_MAC_ADDRESS mZeroMacAddress;
- /**
- Update the ReachableTime in IP6 service binding instance data, in milliseconds.
- @param[in, out] IpSb Points to the IP6_SERVICE.
- **/
- VOID
- Ip6UpdateReachableTime (
- IN OUT IP6_SERVICE *IpSb
- )
- {
- UINT32 Random;
- Random = (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE;
- Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED;
- IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE;
- }
- /**
- Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
- of EFI_IP6_NEIGHBOR_CACHE is also returned.
- @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
- @param[out] NeighborCount The number of returned neighbor cache entries.
- @param[out] NeighborCache The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
- @retval EFI_SUCCESS The EFI_IP6_NEIGHBOR_CACHE successfully built.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
- **/
- EFI_STATUS
- Ip6BuildEfiNeighborCache (
- IN IP6_PROTOCOL *IpInstance,
- OUT UINT32 *NeighborCount,
- OUT EFI_IP6_NEIGHBOR_CACHE **NeighborCache
- )
- {
- IP6_NEIGHBOR_ENTRY *Neighbor;
- LIST_ENTRY *Entry;
- IP6_SERVICE *IpSb;
- UINT32 Count;
- EFI_IP6_NEIGHBOR_CACHE *EfiNeighborCache;
- EFI_IP6_NEIGHBOR_CACHE *NeighborCacheTmp;
- NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
- ASSERT (NeighborCount != NULL && NeighborCache != NULL);
- IpSb = IpInstance->Service;
- Count = 0;
- NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
- Count++;
- }
- if (Count == 0) {
- return EFI_SUCCESS;
- }
- NeighborCacheTmp = AllocatePool (Count * sizeof (EFI_IP6_NEIGHBOR_CACHE));
- if (NeighborCacheTmp == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- *NeighborCount = Count;
- Count = 0;
- NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
- Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
- EfiNeighborCache = NeighborCacheTmp + Count;
- EfiNeighborCache->State = Neighbor->State;
- IP6_COPY_ADDRESS (&EfiNeighborCache->Neighbor, &Neighbor->Neighbor);
- IP6_COPY_LINK_ADDRESS (&EfiNeighborCache->LinkAddress, &Neighbor->LinkAddress);
- Count++;
- }
- ASSERT (*NeighborCount == Count);
- *NeighborCache = NeighborCacheTmp;
- return EFI_SUCCESS;
- }
- /**
- Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
- of prefix entries is also returned.
- @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
- @param[out] PrefixCount The number of returned prefix entries.
- @param[out] PrefixTable The pointer to the array of PrefixTable.
- @retval EFI_SUCCESS The prefix table successfully built.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the prefix table.
- **/
- EFI_STATUS
- Ip6BuildPrefixTable (
- IN IP6_PROTOCOL *IpInstance,
- OUT UINT32 *PrefixCount,
- OUT EFI_IP6_ADDRESS_INFO **PrefixTable
- )
- {
- LIST_ENTRY *Entry;
- IP6_SERVICE *IpSb;
- UINT32 Count;
- IP6_PREFIX_LIST_ENTRY *PrefixList;
- EFI_IP6_ADDRESS_INFO *EfiPrefix;
- EFI_IP6_ADDRESS_INFO *PrefixTableTmp;
- NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
- ASSERT (PrefixCount != NULL && PrefixTable != NULL);
- IpSb = IpInstance->Service;
- Count = 0;
- NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
- Count++;
- }
- if (Count == 0) {
- return EFI_SUCCESS;
- }
- PrefixTableTmp = AllocatePool (Count * sizeof (EFI_IP6_ADDRESS_INFO));
- if (PrefixTableTmp == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- *PrefixCount = Count;
- Count = 0;
- NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
- PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
- EfiPrefix = PrefixTableTmp + Count;
- IP6_COPY_ADDRESS (&EfiPrefix->Address, &PrefixList->Prefix);
- EfiPrefix->PrefixLength = PrefixList->PrefixLength;
- Count++;
- }
- ASSERT (*PrefixCount == Count);
- *PrefixTable = PrefixTableTmp;
- return EFI_SUCCESS;
- }
- /**
- Allocate and initialize a IP6 prefix list entry.
- @param[in] IpSb The pointer to IP6_SERVICE instance.
- @param[in] OnLinkOrAuto If TRUE, the entry is created for the on link prefix list.
- Otherwise, it is created for the autoconfiguration prefix list.
- @param[in] ValidLifetime The length of time in seconds that the prefix
- is valid for the purpose of on-link determination.
- @param[in] PreferredLifetime The length of time in seconds that addresses
- generated from the prefix via stateless address
- autoconfiguration remain preferred.
- @param[in] PrefixLength The prefix length of the Prefix.
- @param[in] Prefix The prefix address.
- @return NULL if it failed to allocate memory for the prefix node. Otherwise, point
- to the created or existing prefix list entry.
- **/
- IP6_PREFIX_LIST_ENTRY *
- Ip6CreatePrefixListEntry (
- IN IP6_SERVICE *IpSb,
- IN BOOLEAN OnLinkOrAuto,
- IN UINT32 ValidLifetime,
- IN UINT32 PreferredLifetime,
- IN UINT8 PrefixLength,
- IN EFI_IPv6_ADDRESS *Prefix
- )
- {
- IP6_PREFIX_LIST_ENTRY *PrefixEntry;
- IP6_ROUTE_ENTRY *RtEntry;
- LIST_ENTRY *ListHead;
- LIST_ENTRY *Entry;
- IP6_PREFIX_LIST_ENTRY *TmpPrefixEntry;
- if ((Prefix == NULL) || (PreferredLifetime > ValidLifetime) || (PrefixLength > IP6_PREFIX_MAX)) {
- return NULL;
- }
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- PrefixEntry = Ip6FindPrefixListEntry (
- IpSb,
- OnLinkOrAuto,
- PrefixLength,
- Prefix
- );
- if (PrefixEntry != NULL) {
- PrefixEntry->RefCnt++;
- return PrefixEntry;
- }
- PrefixEntry = AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY));
- if (PrefixEntry == NULL) {
- return NULL;
- }
- PrefixEntry->RefCnt = 1;
- PrefixEntry->ValidLifetime = ValidLifetime;
- PrefixEntry->PreferredLifetime = PreferredLifetime;
- PrefixEntry->PrefixLength = PrefixLength;
- IP6_COPY_ADDRESS (&PrefixEntry->Prefix, Prefix);
- ListHead = OnLinkOrAuto ? &IpSb->OnlinkPrefix : &IpSb->AutonomousPrefix;
- //
- // Create a direct route entry for on-link prefix and insert to route area.
- //
- if (OnLinkOrAuto) {
- RtEntry = Ip6CreateRouteEntry (Prefix, PrefixLength, NULL);
- if (RtEntry == NULL) {
- FreePool (PrefixEntry);
- return NULL;
- }
- RtEntry->Flag = IP6_DIRECT_ROUTE;
- InsertHeadList (&IpSb->RouteTable->RouteArea[PrefixLength], &RtEntry->Link);
- IpSb->RouteTable->TotalNum++;
- }
- //
- // Insert the prefix entry in the order that a prefix with longer prefix length
- // is put ahead in the list.
- //
- NET_LIST_FOR_EACH (Entry, ListHead) {
- TmpPrefixEntry = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
- if (TmpPrefixEntry->PrefixLength < PrefixEntry->PrefixLength) {
- break;
- }
- }
- NetListInsertBefore (Entry, &PrefixEntry->Link);
- return PrefixEntry;
- }
- /**
- Destroy a IP6 prefix list entry.
- @param[in] IpSb The pointer to IP6_SERVICE instance.
- @param[in] PrefixEntry The to be destroyed prefix list entry.
- @param[in] OnLinkOrAuto If TRUE, the entry is removed from on link prefix list.
- Otherwise remove from autoconfiguration prefix list.
- @param[in] ImmediateDelete If TRUE, remove the entry directly.
- Otherwise, check the reference count to see whether
- it should be removed.
- **/
- VOID
- Ip6DestroyPrefixListEntry (
- IN IP6_SERVICE *IpSb,
- IN IP6_PREFIX_LIST_ENTRY *PrefixEntry,
- IN BOOLEAN OnLinkOrAuto,
- IN BOOLEAN ImmediateDelete
- )
- {
- LIST_ENTRY *Entry;
- IP6_INTERFACE *IpIf;
- EFI_STATUS Status;
- if ((!ImmediateDelete) && (PrefixEntry->RefCnt > 0) && ((--PrefixEntry->RefCnt) > 0)) {
- return;
- }
- if (OnLinkOrAuto) {
- //
- // Remove the direct route for onlink prefix from route table.
- //
- do {
- Status = Ip6DelRoute (
- IpSb->RouteTable,
- &PrefixEntry->Prefix,
- PrefixEntry->PrefixLength,
- NULL
- );
- } while (Status != EFI_NOT_FOUND);
- } else {
- //
- // Remove the corresponding addresses generated from this autonomous prefix.
- //
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
- Ip6RemoveAddr (IpSb, &IpIf->AddressList, &IpIf->AddressCount, &PrefixEntry->Prefix, PrefixEntry->PrefixLength);
- }
- }
- RemoveEntryList (&PrefixEntry->Link);
- FreePool (PrefixEntry);
- }
- /**
- Search the list array to find an IP6 prefix list entry.
- @param[in] IpSb The pointer to IP6_SERVICE instance.
- @param[in] OnLinkOrAuto If TRUE, the search the link prefix list,
- Otherwise search the autoconfiguration prefix list.
- @param[in] PrefixLength The prefix length of the Prefix
- @param[in] Prefix The prefix address.
- @return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
- pointer to the IP6 prefix list entry.
- **/
- IP6_PREFIX_LIST_ENTRY *
- Ip6FindPrefixListEntry (
- IN IP6_SERVICE *IpSb,
- IN BOOLEAN OnLinkOrAuto,
- IN UINT8 PrefixLength,
- IN EFI_IPv6_ADDRESS *Prefix
- )
- {
- IP6_PREFIX_LIST_ENTRY *PrefixList;
- LIST_ENTRY *Entry;
- LIST_ENTRY *ListHead;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ASSERT (Prefix != NULL);
- if (OnLinkOrAuto) {
- ListHead = &IpSb->OnlinkPrefix;
- } else {
- ListHead = &IpSb->AutonomousPrefix;
- }
- NET_LIST_FOR_EACH (Entry, ListHead) {
- PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
- if (PrefixLength != 255) {
- //
- // Perform exactly prefix match.
- //
- if ((PrefixList->PrefixLength == PrefixLength) &&
- NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixLength))
- {
- return PrefixList;
- }
- } else {
- //
- // Perform the longest prefix match. The list is already sorted with
- // the longest length prefix put at the head of the list.
- //
- if (NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixList->PrefixLength)) {
- return PrefixList;
- }
- }
- }
- return NULL;
- }
- /**
- Release the resource in the prefix list table, and destroy the list entry and
- corresponding addresses or route entries.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] ListHead The list entry head of the prefix list table.
- **/
- VOID
- Ip6CleanPrefixListTable (
- IN IP6_SERVICE *IpSb,
- IN LIST_ENTRY *ListHead
- )
- {
- IP6_PREFIX_LIST_ENTRY *PrefixList;
- BOOLEAN OnLink;
- OnLink = (BOOLEAN)(ListHead == &IpSb->OnlinkPrefix);
- while (!IsListEmpty (ListHead)) {
- PrefixList = NET_LIST_HEAD (ListHead, IP6_PREFIX_LIST_ENTRY, Link);
- Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
- }
- }
- /**
- Callback function when address resolution is finished. It will cancel
- all the queued frames if the address resolution failed, or transmit them
- if the request succeeded.
- @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
- **/
- VOID
- Ip6OnArpResolved (
- IN VOID *Context
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_NEIGHBOR_ENTRY *ArpQue;
- IP6_SERVICE *IpSb;
- IP6_LINK_TX_TOKEN *Token;
- EFI_STATUS Status;
- BOOLEAN Sent;
- ArpQue = (IP6_NEIGHBOR_ENTRY *)Context;
- if ((ArpQue == NULL) || (ArpQue->Interface == NULL)) {
- return;
- }
- IpSb = ArpQue->Interface->Service;
- if ((IpSb == NULL) || (IpSb->Signature != IP6_SERVICE_SIGNATURE)) {
- return;
- }
- //
- // ARP resolve failed for some reason. Release all the frame
- // and ARP queue itself. Ip6FreeArpQue will call the frame's
- // owner back.
- //
- if (NET_MAC_EQUAL (&ArpQue->LinkAddress, &mZeroMacAddress, IpSb->SnpMode.HwAddressSize)) {
- Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, TRUE, EFI_NO_MAPPING, NULL, NULL);
- return;
- }
- //
- // ARP resolve succeeded, Transmit all the frame.
- //
- Sent = FALSE;
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
- RemoveEntryList (Entry);
- Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
- IP6_COPY_LINK_ADDRESS (&Token->DstMac, &ArpQue->LinkAddress);
- //
- // Insert the tx token before transmitting it via MNP as the FrameSentDpc
- // may be called before Mnp->Transmit returns which will remove this tx
- // token from the SentFrames list. Remove it from the list if the returned
- // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
- // FrameSentDpc won't be queued.
- //
- InsertTailList (&ArpQue->Interface->SentFrames, &Token->Link);
- Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
- if (EFI_ERROR (Status)) {
- RemoveEntryList (&Token->Link);
- Token->CallBack (Token->Packet, Status, 0, Token->Context);
- Ip6FreeLinkTxToken (Token);
- continue;
- } else {
- Sent = TRUE;
- }
- }
- //
- // Free the ArpQue only but not the whole neighbor entry.
- //
- Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, FALSE, EFI_SUCCESS, NULL, NULL);
- if (Sent && (ArpQue->State == EfiNeighborStale)) {
- ArpQue->State = EfiNeighborDelay;
- ArpQue->Ticks = (UINT32)IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
- }
- }
- /**
- Allocate and initialize an IP6 neighbor cache entry.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] CallBack The callback function to be called when
- address resolution is finished.
- @param[in] Ip6Address Points to the IPv6 address of the neighbor.
- @param[in] LinkAddress Points to the MAC address of the neighbor.
- Ignored if NULL.
- @return NULL if failed to allocate memory for the neighbor cache entry.
- Otherwise, point to the created neighbor cache entry.
- **/
- IP6_NEIGHBOR_ENTRY *
- Ip6CreateNeighborEntry (
- IN IP6_SERVICE *IpSb,
- IN IP6_ARP_CALLBACK CallBack,
- IN EFI_IPv6_ADDRESS *Ip6Address,
- IN EFI_MAC_ADDRESS *LinkAddress OPTIONAL
- )
- {
- IP6_NEIGHBOR_ENTRY *Entry;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ASSERT (Ip6Address != NULL);
- Entry = AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY));
- if (Entry == NULL) {
- return NULL;
- }
- Entry->RefCnt = 1;
- Entry->IsRouter = FALSE;
- Entry->ArpFree = FALSE;
- Entry->Dynamic = FALSE;
- Entry->State = EfiNeighborInComplete;
- Entry->Transmit = IP6_MAX_MULTICAST_SOLICIT + 1;
- Entry->CallBack = CallBack;
- Entry->Interface = NULL;
- InitializeListHead (&Entry->Frames);
- IP6_COPY_ADDRESS (&Entry->Neighbor, Ip6Address);
- if (LinkAddress != NULL) {
- IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, LinkAddress);
- } else {
- IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, &mZeroMacAddress);
- }
- InsertHeadList (&IpSb->NeighborTable, &Entry->Link);
- //
- // If corresponding default router entry exists, establish the relationship.
- //
- DefaultRouter = Ip6FindDefaultRouter (IpSb, Ip6Address);
- if (DefaultRouter != NULL) {
- DefaultRouter->NeighborCache = Entry;
- }
- return Entry;
- }
- /**
- Search a IP6 neighbor cache entry.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] Ip6Address Points to the IPv6 address of the neighbor.
- @return NULL if it failed to find the matching neighbor cache entry.
- Otherwise, point to the found neighbor cache entry.
- **/
- IP6_NEIGHBOR_ENTRY *
- Ip6FindNeighborEntry (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Ip6Address
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_NEIGHBOR_ENTRY *Neighbor;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ASSERT (Ip6Address != NULL);
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
- Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
- if (EFI_IP6_EQUAL (Ip6Address, &Neighbor->Neighbor)) {
- RemoveEntryList (Entry);
- InsertHeadList (&IpSb->NeighborTable, Entry);
- return Neighbor;
- }
- }
- return NULL;
- }
- /**
- Free a IP6 neighbor cache entry and remove all the frames on the address
- resolution queue that pass the FrameToCancel. That is, either FrameToCancel
- is NULL, or it returns true for the frame.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] NeighborCache The to be free neighbor cache entry.
- @param[in] SendIcmpError If TRUE, send out ICMP error.
- @param[in] FullFree If TRUE, remove the neighbor cache entry.
- Otherwise remove the pending frames.
- @param[in] IoStatus The status returned to the cancelled frames'
- callback function.
- @param[in] FrameToCancel Function to select which frame to cancel.
- This is an optional parameter that may be NULL.
- @param[in] Context Opaque parameter to the FrameToCancel.
- Ignored if FrameToCancel is NULL.
- @retval EFI_INVALID_PARAMETER The input parameter is invalid.
- @retval EFI_SUCCESS The operation finished successfully.
- **/
- EFI_STATUS
- Ip6FreeNeighborEntry (
- IN IP6_SERVICE *IpSb,
- IN IP6_NEIGHBOR_ENTRY *NeighborCache,
- IN BOOLEAN SendIcmpError,
- IN BOOLEAN FullFree,
- IN EFI_STATUS IoStatus,
- IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
- IN VOID *Context OPTIONAL
- )
- {
- IP6_LINK_TX_TOKEN *TxToken;
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- //
- // If FrameToCancel fails, the token will not be released.
- // To avoid the memory leak, stop this usage model.
- //
- if (FullFree && (FrameToCancel != NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &NeighborCache->Frames) {
- TxToken = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
- if (SendIcmpError && !IP6_IS_MULTICAST (&TxToken->Packet->Ip.Ip6->DestinationAddress)) {
- Ip6SendIcmpError (
- IpSb,
- TxToken->Packet,
- NULL,
- &TxToken->Packet->Ip.Ip6->SourceAddress,
- ICMP_V6_DEST_UNREACHABLE,
- ICMP_V6_ADDR_UNREACHABLE,
- NULL
- );
- }
- if ((FrameToCancel == NULL) || FrameToCancel (TxToken, Context)) {
- RemoveEntryList (Entry);
- TxToken->CallBack (TxToken->Packet, IoStatus, 0, TxToken->Context);
- Ip6FreeLinkTxToken (TxToken);
- }
- }
- if (NeighborCache->ArpFree && IsListEmpty (&NeighborCache->Frames)) {
- RemoveEntryList (&NeighborCache->ArpList);
- NeighborCache->ArpFree = FALSE;
- }
- if (FullFree) {
- if (NeighborCache->IsRouter) {
- DefaultRouter = Ip6FindDefaultRouter (IpSb, &NeighborCache->Neighbor);
- if (DefaultRouter != NULL) {
- Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
- }
- }
- RemoveEntryList (&NeighborCache->Link);
- FreePool (NeighborCache);
- }
- return EFI_SUCCESS;
- }
- /**
- Allocate and initialize an IP6 default router entry.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] Ip6Address The IPv6 address of the default router.
- @param[in] RouterLifetime The lifetime associated with the default
- router, in units of seconds.
- @return NULL if it failed to allocate memory for the default router node.
- Otherwise, point to the created default router node.
- **/
- IP6_DEFAULT_ROUTER *
- Ip6CreateDefaultRouter (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Ip6Address,
- IN UINT16 RouterLifetime
- )
- {
- IP6_DEFAULT_ROUTER *Entry;
- IP6_ROUTE_ENTRY *RtEntry;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ASSERT (Ip6Address != NULL);
- Entry = AllocatePool (sizeof (IP6_DEFAULT_ROUTER));
- if (Entry == NULL) {
- return NULL;
- }
- Entry->RefCnt = 1;
- Entry->Lifetime = RouterLifetime;
- Entry->NeighborCache = Ip6FindNeighborEntry (IpSb, Ip6Address);
- IP6_COPY_ADDRESS (&Entry->Router, Ip6Address);
- //
- // Add a default route into route table with both Destination and PrefixLength set to zero.
- //
- RtEntry = Ip6CreateRouteEntry (NULL, 0, Ip6Address);
- if (RtEntry == NULL) {
- FreePool (Entry);
- return NULL;
- }
- InsertHeadList (&IpSb->RouteTable->RouteArea[0], &RtEntry->Link);
- IpSb->RouteTable->TotalNum++;
- InsertTailList (&IpSb->DefaultRouterList, &Entry->Link);
- return Entry;
- }
- /**
- Destroy an IP6 default router entry.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
- **/
- VOID
- Ip6DestroyDefaultRouter (
- IN IP6_SERVICE *IpSb,
- IN IP6_DEFAULT_ROUTER *DefaultRouter
- )
- {
- EFI_STATUS Status;
- RemoveEntryList (&DefaultRouter->Link);
- //
- // Update the Destination Cache - all entries using the time-out router as next-hop
- // should perform next-hop determination again.
- //
- do {
- Status = Ip6DelRoute (IpSb->RouteTable, NULL, 0, &DefaultRouter->Router);
- } while (Status != EFI_NOT_FOUND);
- FreePool (DefaultRouter);
- }
- /**
- Clean an IP6 default router list.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- **/
- VOID
- Ip6CleanDefaultRouterList (
- IN IP6_SERVICE *IpSb
- )
- {
- IP6_DEFAULT_ROUTER *DefaultRouter;
- while (!IsListEmpty (&IpSb->DefaultRouterList)) {
- DefaultRouter = NET_LIST_HEAD (&IpSb->DefaultRouterList, IP6_DEFAULT_ROUTER, Link);
- Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
- }
- }
- /**
- Search a default router node from an IP6 default router list.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] Ip6Address The IPv6 address of the to be searched default router node.
- @return NULL if it failed to find the matching default router node.
- Otherwise, point to the found default router node.
- **/
- IP6_DEFAULT_ROUTER *
- Ip6FindDefaultRouter (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Ip6Address
- )
- {
- LIST_ENTRY *Entry;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ASSERT (Ip6Address != NULL);
- NET_LIST_FOR_EACH (Entry, &IpSb->DefaultRouterList) {
- DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
- if (EFI_IP6_EQUAL (Ip6Address, &DefaultRouter->Router)) {
- return DefaultRouter;
- }
- }
- return NULL;
- }
- /**
- The function to be called after DAD (Duplicate Address Detection) is performed.
- @param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
- @param[in] IpIf Points to the IP6_INTERFACE.
- @param[in] DadEntry The DAD entry which already performed DAD.
- **/
- VOID
- Ip6OnDADFinished (
- IN BOOLEAN IsDadPassed,
- IN IP6_INTERFACE *IpIf,
- IN IP6_DAD_ENTRY *DadEntry
- )
- {
- IP6_SERVICE *IpSb;
- IP6_ADDRESS_INFO *AddrInfo;
- EFI_DHCP6_PROTOCOL *Dhcp6;
- UINT16 OptBuf[4];
- EFI_DHCP6_PACKET_OPTION *Oro;
- EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
- EFI_IPv6_ADDRESS AllNodes;
- IpSb = IpIf->Service;
- AddrInfo = DadEntry->AddressInfo;
- if (IsDadPassed) {
- //
- // DAD succeed.
- //
- if (NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
- ASSERT (!IpSb->LinkLocalOk);
- IP6_COPY_ADDRESS (&IpSb->LinkLocalAddr, &AddrInfo->Address);
- IpSb->LinkLocalOk = TRUE;
- IpIf->Configured = TRUE;
- //
- // Check whether DHCP6 need to be started.
- //
- Dhcp6 = IpSb->Ip6ConfigInstance.Dhcp6;
- if (IpSb->Dhcp6NeedStart) {
- Dhcp6->Start (Dhcp6);
- IpSb->Dhcp6NeedStart = FALSE;
- }
- if (IpSb->Dhcp6NeedInfoRequest) {
- //
- // Set the exta options to send. Here we only want the option request option
- // with DNS SERVERS.
- //
- Oro = (EFI_DHCP6_PACKET_OPTION *)OptBuf;
- Oro->OpCode = HTONS (DHCP6_OPT_ORO);
- Oro->OpLen = HTONS (2);
- *((UINT16 *)&Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
- InfoReqReXmit.Irt = 4;
- InfoReqReXmit.Mrc = 64;
- InfoReqReXmit.Mrt = 60;
- InfoReqReXmit.Mrd = 0;
- Dhcp6->InfoRequest (
- Dhcp6,
- TRUE,
- Oro,
- 0,
- NULL,
- &InfoReqReXmit,
- IpSb->Ip6ConfigInstance.Dhcp6Event,
- Ip6ConfigOnDhcp6Reply,
- &IpSb->Ip6ConfigInstance
- );
- }
- //
- // Add an on-link prefix for link-local address.
- //
- Ip6CreatePrefixListEntry (
- IpSb,
- TRUE,
- (UINT32)IP6_INFINIT_LIFETIME,
- (UINT32)IP6_INFINIT_LIFETIME,
- IP6_LINK_LOCAL_PREFIX_LENGTH,
- &IpSb->LinkLocalAddr
- );
- } else {
- //
- // Global scope unicast address.
- //
- Ip6AddAddr (IpIf, AddrInfo);
- //
- // Add an on-link prefix for this address.
- //
- Ip6CreatePrefixListEntry (
- IpSb,
- TRUE,
- AddrInfo->ValidLifetime,
- AddrInfo->PreferredLifetime,
- AddrInfo->PrefixLength,
- &AddrInfo->Address
- );
- IpIf->Configured = TRUE;
- }
- } else {
- //
- // Leave the group we joined before.
- //
- Ip6LeaveGroup (IpSb, &DadEntry->Destination);
- }
- if (DadEntry->Callback != NULL) {
- DadEntry->Callback (IsDadPassed, &AddrInfo->Address, DadEntry->Context);
- }
- if (!IsDadPassed && NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
- FreePool (AddrInfo);
- RemoveEntryList (&DadEntry->Link);
- FreePool (DadEntry);
- //
- // Leave link-scope all-nodes multicast address (FF02::1)
- //
- Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
- Ip6LeaveGroup (IpSb, &AllNodes);
- //
- // Disable IP operation since link-local address is a duplicate address.
- //
- IpSb->LinkLocalDadFail = TRUE;
- IpSb->Mnp->Configure (IpSb->Mnp, NULL);
- gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
- gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
- return;
- }
- if (!IsDadPassed || NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
- //
- // Free the AddressInfo we hold if DAD fails or it is a link-local address.
- //
- FreePool (AddrInfo);
- }
- RemoveEntryList (&DadEntry->Link);
- FreePool (DadEntry);
- }
- /**
- Create a DAD (Duplicate Address Detection) entry and queue it to be performed.
- @param[in] IpIf Points to the IP6_INTERFACE.
- @param[in] AddressInfo The address information which needs DAD performed.
- @param[in] Callback The callback routine that will be called after DAD
- is performed. This is an optional parameter that
- may be NULL.
- @param[in] Context The opaque parameter for a DAD callback routine.
- This is an optional parameter that may be NULL.
- @retval EFI_SUCCESS The DAD entry was created and queued.
- @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory to complete the
- operation.
- **/
- EFI_STATUS
- Ip6InitDADProcess (
- IN IP6_INTERFACE *IpIf,
- IN IP6_ADDRESS_INFO *AddressInfo,
- IN IP6_DAD_CALLBACK Callback OPTIONAL,
- IN VOID *Context OPTIONAL
- )
- {
- IP6_DAD_ENTRY *Entry;
- EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS *DadXmits;
- IP6_SERVICE *IpSb;
- EFI_STATUS Status;
- UINT32 MaxDelayTick;
- NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE);
- ASSERT (AddressInfo != NULL);
- //
- // Do nothing if we have already started DAD on the address.
- //
- if (Ip6FindDADEntry (IpIf->Service, &AddressInfo->Address, NULL) != NULL) {
- return EFI_SUCCESS;
- }
- Status = EFI_SUCCESS;
- IpSb = IpIf->Service;
- DadXmits = &IpSb->Ip6ConfigInstance.DadXmits;
- //
- // Allocate the resources and insert info
- //
- Entry = AllocatePool (sizeof (IP6_DAD_ENTRY));
- if (Entry == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Map the incoming unicast address to solicited-node multicast address
- //
- Ip6CreateSNMulticastAddr (&AddressInfo->Address, &Entry->Destination);
- //
- // Join in the solicited-node multicast address.
- //
- Status = Ip6JoinGroup (IpSb, IpIf, &Entry->Destination);
- if (EFI_ERROR (Status)) {
- FreePool (Entry);
- return Status;
- }
- Entry->Signature = IP6_DAD_ENTRY_SIGNATURE;
- Entry->MaxTransmit = DadXmits->DupAddrDetectTransmits;
- Entry->Transmit = 0;
- Entry->Receive = 0;
- MaxDelayTick = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS;
- Entry->RetransTick = (MaxDelayTick * ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5;
- Entry->AddressInfo = AddressInfo;
- Entry->Callback = Callback;
- Entry->Context = Context;
- InsertTailList (&IpIf->DupAddrDetectList, &Entry->Link);
- if (Entry->MaxTransmit == 0) {
- //
- // DAD is disabled on this interface, immediately mark this DAD successful.
- //
- Ip6OnDADFinished (TRUE, IpIf, Entry);
- }
- return EFI_SUCCESS;
- }
- /**
- Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
- @param[in] IpSb The pointer to the IP6_SERVICE instance.
- @param[in] Target The address information which needs DAD performed .
- @param[out] Interface If not NULL, output the IP6 interface that configures
- the tentative address.
- @return NULL if failed to find the matching DAD entry.
- Otherwise, point to the found DAD entry.
- **/
- IP6_DAD_ENTRY *
- Ip6FindDADEntry (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *Target,
- OUT IP6_INTERFACE **Interface OPTIONAL
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Entry2;
- IP6_INTERFACE *IpIf;
- IP6_DAD_ENTRY *DupAddrDetect;
- IP6_ADDRESS_INFO *AddrInfo;
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
- NET_LIST_FOR_EACH (Entry2, &IpIf->DupAddrDetectList) {
- DupAddrDetect = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
- AddrInfo = DupAddrDetect->AddressInfo;
- if (EFI_IP6_EQUAL (&AddrInfo->Address, Target)) {
- if (Interface != NULL) {
- *Interface = IpIf;
- }
- return DupAddrDetect;
- }
- }
- }
- return NULL;
- }
- /**
- Generate router solicit message and send it out to Destination Address or
- All Router Link Local scope multicast address.
- @param[in] IpSb The IP service to send the packet.
- @param[in] Interface If not NULL, points to the IP6 interface to send
- the packet.
- @param[in] SourceAddress If not NULL, the source address of the message.
- @param[in] DestinationAddress If not NULL, the destination address of the message.
- @param[in] SourceLinkAddress If not NULL, the MAC address of the source.
- A source link-layer address option will be appended
- to the message.
- @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
- operation.
- @retval EFI_SUCCESS The router solicit message was successfully sent.
- **/
- EFI_STATUS
- Ip6SendRouterSolicit (
- IN IP6_SERVICE *IpSb,
- IN IP6_INTERFACE *Interface OPTIONAL,
- IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,
- IN EFI_IPv6_ADDRESS *DestinationAddress OPTIONAL,
- IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
- )
- {
- NET_BUF *Packet;
- EFI_IP6_HEADER Head;
- IP6_ICMP_INFORMATION_HEAD *IcmpHead;
- IP6_ETHER_ADDR_OPTION *LinkLayerOption;
- UINT16 PayloadLen;
- IP6_INTERFACE *IpIf;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- IpIf = Interface;
- if ((IpIf == NULL) && (IpSb->DefaultInterface != NULL)) {
- IpIf = IpSb->DefaultInterface;
- }
- //
- // Generate the packet to be sent
- //
- PayloadLen = (UINT16)sizeof (IP6_ICMP_INFORMATION_HEAD);
- if (SourceLinkAddress != NULL) {
- PayloadLen += sizeof (IP6_ETHER_ADDR_OPTION);
- }
- Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
- if (Packet == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Create the basic IPv6 header.
- //
- Head.FlowLabelL = 0;
- Head.FlowLabelH = 0;
- Head.PayloadLength = HTONS (PayloadLen);
- Head.NextHeader = IP6_ICMP;
- Head.HopLimit = IP6_HOP_LIMIT;
- if (SourceAddress != NULL) {
- IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
- } else {
- ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
- }
- if (DestinationAddress != NULL) {
- IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
- } else {
- Ip6SetToAllNodeMulticast (TRUE, IP6_LINK_LOCAL_SCOPE, &Head.DestinationAddress);
- }
- NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
- //
- // Fill in the ICMP header, and Source link-layer address if contained.
- //
- IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
- ASSERT (IcmpHead != NULL);
- ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
- IcmpHead->Head.Type = ICMP_V6_ROUTER_SOLICIT;
- IcmpHead->Head.Code = 0;
- LinkLayerOption = NULL;
- if (SourceLinkAddress != NULL) {
- LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
- Packet,
- sizeof (IP6_ETHER_ADDR_OPTION),
- FALSE
- );
- ASSERT (LinkLayerOption != NULL);
- LinkLayerOption->Type = Ip6OptionEtherSource;
- LinkLayerOption->Length = (UINT8)sizeof (IP6_ETHER_ADDR_OPTION);
- CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
- }
- //
- // Transmit the packet
- //
- return Ip6Output (IpSb, IpIf, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
- }
- /**
- Generate a Neighbor Advertisement message and send it out to Destination Address.
- @param[in] IpSb The IP service to send the packet.
- @param[in] SourceAddress The source address of the message.
- @param[in] DestinationAddress The destination address of the message.
- @param[in] TargetIp6Address The target address field in the Neighbor Solicitation
- message that prompted this advertisement.
- @param[in] TargetLinkAddress The MAC address for the target, i.e. the sender
- of the advertisement.
- @param[in] IsRouter If TRUE, indicates the sender is a router.
- @param[in] Override If TRUE, indicates the advertisement should override
- an existing cache entry and update the MAC address.
- @param[in] Solicited If TRUE, indicates the advertisement was sent
- in response to a Neighbor Solicitation from
- the Destination address.
- @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
- operation.
- @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
- **/
- EFI_STATUS
- Ip6SendNeighborAdvertise (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *SourceAddress,
- IN EFI_IPv6_ADDRESS *DestinationAddress,
- IN EFI_IPv6_ADDRESS *TargetIp6Address,
- IN EFI_MAC_ADDRESS *TargetLinkAddress,
- IN BOOLEAN IsRouter,
- IN BOOLEAN Override,
- IN BOOLEAN Solicited
- )
- {
- NET_BUF *Packet;
- EFI_IP6_HEADER Head;
- IP6_ICMP_INFORMATION_HEAD *IcmpHead;
- IP6_ETHER_ADDR_OPTION *LinkLayerOption;
- EFI_IPv6_ADDRESS *Target;
- UINT16 PayloadLen;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- //
- // The Neighbor Advertisement message must include a Target link-layer address option
- // when responding to multicast solicitation and should include such option when
- // responding to unicast solicitation. It also must include such option as unsolicited
- // advertisement.
- //
- ASSERT (DestinationAddress != NULL && TargetIp6Address != NULL && TargetLinkAddress != NULL);
- PayloadLen = (UINT16)(sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS) + sizeof (IP6_ETHER_ADDR_OPTION));
- //
- // Generate the packet to be sent
- //
- Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
- if (Packet == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Create the basic IPv6 header.
- //
- Head.FlowLabelL = 0;
- Head.FlowLabelH = 0;
- Head.PayloadLength = HTONS (PayloadLen);
- Head.NextHeader = IP6_ICMP;
- Head.HopLimit = IP6_HOP_LIMIT;
- IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
- IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
- NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
- //
- // Fill in the ICMP header, Target address, and Target link-layer address.
- // Set the Router flag, Solicited flag and Override flag.
- //
- IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
- ASSERT (IcmpHead != NULL);
- ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
- IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_ADVERTISE;
- IcmpHead->Head.Code = 0;
- if (IsRouter) {
- IcmpHead->Fourth |= IP6_IS_ROUTER_FLAG;
- }
- if (Solicited) {
- IcmpHead->Fourth |= IP6_SOLICITED_FLAG;
- }
- if (Override) {
- IcmpHead->Fourth |= IP6_OVERRIDE_FLAG;
- }
- Target = (EFI_IPv6_ADDRESS *)NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
- ASSERT (Target != NULL);
- IP6_COPY_ADDRESS (Target, TargetIp6Address);
- LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
- Packet,
- sizeof (IP6_ETHER_ADDR_OPTION),
- FALSE
- );
- ASSERT (LinkLayerOption != NULL);
- LinkLayerOption->Type = Ip6OptionEtherTarget;
- LinkLayerOption->Length = 1;
- CopyMem (LinkLayerOption->EtherAddr, TargetLinkAddress, 6);
- //
- // Transmit the packet
- //
- return Ip6Output (IpSb, NULL, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
- }
- /**
- Generate the Neighbor Solicitation message and send it to the Destination Address.
- @param[in] IpSb The IP service to send the packet
- @param[in] SourceAddress The source address of the message.
- @param[in] DestinationAddress The destination address of the message.
- @param[in] TargetIp6Address The IP address of the target of the solicitation.
- It must not be a multicast address.
- @param[in] SourceLinkAddress The MAC address for the sender. If not NULL,
- a source link-layer address option will be appended
- to the message.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
- operation.
- @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
- **/
- EFI_STATUS
- Ip6SendNeighborSolicit (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *SourceAddress,
- IN EFI_IPv6_ADDRESS *DestinationAddress,
- IN EFI_IPv6_ADDRESS *TargetIp6Address,
- IN EFI_MAC_ADDRESS *SourceLinkAddress OPTIONAL
- )
- {
- NET_BUF *Packet;
- EFI_IP6_HEADER Head;
- IP6_ICMP_INFORMATION_HEAD *IcmpHead;
- IP6_ETHER_ADDR_OPTION *LinkLayerOption;
- EFI_IPv6_ADDRESS *Target;
- BOOLEAN IsDAD;
- UINT16 PayloadLen;
- IP6_NEIGHBOR_ENTRY *Neighbor;
- //
- // Check input parameters
- //
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- if ((DestinationAddress == NULL) || (TargetIp6Address == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- IsDAD = FALSE;
- if ((SourceAddress == NULL) || ((SourceAddress != NULL) && NetIp6IsUnspecifiedAddr (SourceAddress))) {
- IsDAD = TRUE;
- }
- //
- // The Neighbor Solicitation message should include a source link-layer address option
- // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
- // Otherwise must not include it.
- //
- PayloadLen = (UINT16)(sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS));
- if (!IsDAD) {
- if (SourceLinkAddress == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- PayloadLen = (UINT16)(PayloadLen + sizeof (IP6_ETHER_ADDR_OPTION));
- }
- //
- // Generate the packet to be sent
- //
- Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32)PayloadLen);
- if (Packet == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Create the basic IPv6 header
- //
- Head.FlowLabelL = 0;
- Head.FlowLabelH = 0;
- Head.PayloadLength = HTONS (PayloadLen);
- Head.NextHeader = IP6_ICMP;
- Head.HopLimit = IP6_HOP_LIMIT;
- if (SourceAddress != NULL) {
- IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
- } else {
- ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
- }
- IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
- NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
- //
- // Fill in the ICMP header, Target address, and Source link-layer address.
- //
- IcmpHead = (IP6_ICMP_INFORMATION_HEAD *)NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
- ASSERT (IcmpHead != NULL);
- ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
- IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_SOLICIT;
- IcmpHead->Head.Code = 0;
- Target = (EFI_IPv6_ADDRESS *)NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
- ASSERT (Target != NULL);
- IP6_COPY_ADDRESS (Target, TargetIp6Address);
- LinkLayerOption = NULL;
- if (!IsDAD) {
- //
- // Fill in the source link-layer address option
- //
- LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)NetbufAllocSpace (
- Packet,
- sizeof (IP6_ETHER_ADDR_OPTION),
- FALSE
- );
- ASSERT (LinkLayerOption != NULL);
- LinkLayerOption->Type = Ip6OptionEtherSource;
- LinkLayerOption->Length = 1;
- CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
- }
- //
- // Create a Neighbor Cache entry in the INCOMPLETE state when performing
- // address resolution.
- //
- if (!IsDAD && Ip6IsSNMulticastAddr (DestinationAddress)) {
- Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
- if (Neighbor == NULL) {
- Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, NULL);
- ASSERT (Neighbor != NULL);
- }
- }
- //
- // Transmit the packet
- //
- return Ip6Output (IpSb, IpSb->DefaultInterface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
- }
- /**
- Process the Neighbor Solicitation message. The message may be sent for Duplicate
- Address Detection or Address Resolution.
- @param[in] IpSb The IP service that received the packet.
- @param[in] Head The IP head of the message.
- @param[in] Packet The content of the message with IP head removed.
- @retval EFI_SUCCESS The packet processed successfully.
- @retval EFI_INVALID_PARAMETER The packet is invalid.
- @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
- @retval Others Failed to process the packet.
- **/
- EFI_STATUS
- Ip6ProcessNeighborSolicit (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_ICMP_INFORMATION_HEAD Icmp;
- EFI_IPv6_ADDRESS Target;
- IP6_ETHER_ADDR_OPTION LinkLayerOption;
- BOOLEAN IsDAD;
- BOOLEAN IsUnicast;
- BOOLEAN IsMaintained;
- IP6_DAD_ENTRY *DupAddrDetect;
- IP6_INTERFACE *IpIf;
- IP6_NEIGHBOR_ENTRY *Neighbor;
- BOOLEAN Solicited;
- BOOLEAN UpdateCache;
- EFI_IPv6_ADDRESS Dest;
- UINT16 OptionLen;
- UINT8 *Option;
- BOOLEAN Provided;
- EFI_STATUS Status;
- VOID *MacAddress;
- NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
- NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
- //
- // Perform Message Validation:
- // The IP Hop Limit field has a value of 255, i.e., the packet
- // could not possibly have been forwarded by a router.
- // ICMP Code is 0.
- // Target Address is not a multicast address.
- //
- Status = EFI_INVALID_PARAMETER;
- if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) || !NetIp6IsValidUnicast (&Target)) {
- goto Exit;
- }
- //
- // ICMP length is 24 or more octets.
- //
- OptionLen = 0;
- if (Head->PayloadLength < IP6_ND_LENGTH) {
- goto Exit;
- } else {
- OptionLen = (UINT16)(Head->PayloadLength - IP6_ND_LENGTH);
- if (OptionLen != 0) {
- Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
- ASSERT (Option != NULL);
- //
- // All included options should have a length that is greater than zero.
- //
- if (!Ip6IsNDOptionValid (Option, OptionLen)) {
- goto Exit;
- }
- }
- }
- IsDAD = NetIp6IsUnspecifiedAddr (&Head->SourceAddress);
- IsUnicast = (BOOLEAN) !Ip6IsSNMulticastAddr (&Head->DestinationAddress);
- IsMaintained = Ip6IsOneOfSetAddress (IpSb, &Target, &IpIf, NULL);
- Provided = FALSE;
- if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
- NetbufCopy (
- Packet,
- IP6_ND_LENGTH,
- sizeof (IP6_ETHER_ADDR_OPTION),
- (UINT8 *)&LinkLayerOption
- );
- //
- // The solicitation for neighbor discovery should include a source link-layer
- // address option. If the option is not recognized, silently ignore it.
- //
- if (LinkLayerOption.Type == Ip6OptionEtherSource) {
- if (IsDAD) {
- //
- // If the IP source address is the unspecified address, the source
- // link-layer address option must not be included in the message.
- //
- goto Exit;
- }
- Provided = TRUE;
- }
- }
- //
- // If the IP source address is the unspecified address, the IP
- // destination address is a solicited-node multicast address.
- //
- if (IsDAD && IsUnicast) {
- goto Exit;
- }
- //
- // If the target address is tentative, and the source address is a unicast address,
- // the solicitation's sender is performing address resolution on the target;
- // the solicitation should be silently ignored.
- //
- if (!IsDAD && !IsMaintained) {
- goto Exit;
- }
- //
- // If received unicast neighbor solicitation but destination is not this node,
- // drop the packet.
- //
- if (IsUnicast && !IsMaintained) {
- goto Exit;
- }
- //
- // In DAD, when target address is a tentative address,
- // process the received neighbor solicitation message but not send out response.
- //
- if (IsDAD && !IsMaintained) {
- DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
- if (DupAddrDetect != NULL) {
- //
- // Check the MAC address of the incoming packet.
- //
- if (IpSb->RecvRequest.MnpToken.Packet.RxData == NULL) {
- goto Exit;
- }
- MacAddress = IpSb->RecvRequest.MnpToken.Packet.RxData->SourceAddress;
- if (MacAddress != NULL) {
- if (CompareMem (
- MacAddress,
- &IpSb->SnpMode.CurrentAddress,
- IpSb->SnpMode.HwAddressSize
- ) != 0)
- {
- //
- // The NS is from another node to performing DAD on the same address.
- // Fail DAD for the tentative address.
- //
- Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
- Status = EFI_ICMP_ERROR;
- } else {
- //
- // The below layer loopback the NS we sent. Record it and wait for more.
- //
- DupAddrDetect->Receive++;
- Status = EFI_SUCCESS;
- }
- }
- }
- goto Exit;
- }
- //
- // If the solicitation does not contain a link-layer address, DO NOT create or
- // update the neighbor cache entries.
- //
- if (Provided) {
- Neighbor = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
- UpdateCache = FALSE;
- if (Neighbor == NULL) {
- Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &Head->SourceAddress, NULL);
- if (Neighbor == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- UpdateCache = TRUE;
- } else {
- if (CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6) != 0) {
- UpdateCache = TRUE;
- }
- }
- if (UpdateCache) {
- Neighbor->State = EfiNeighborStale;
- Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
- //
- // Send queued packets if exist.
- //
- Neighbor->CallBack ((VOID *)Neighbor);
- }
- }
- //
- // Sends a Neighbor Advertisement as response.
- // Set the Router flag to zero since the node is a host.
- // If the source address of the solicitation is unspecified, and target address
- // is one of the maintained address, reply a unsolicited multicast advertisement.
- //
- if (IsDAD && IsMaintained) {
- Solicited = FALSE;
- Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &Dest);
- } else {
- Solicited = TRUE;
- IP6_COPY_ADDRESS (&Dest, &Head->SourceAddress);
- }
- Status = Ip6SendNeighborAdvertise (
- IpSb,
- &Target,
- &Dest,
- &Target,
- &IpSb->SnpMode.CurrentAddress,
- FALSE,
- TRUE,
- Solicited
- );
- Exit:
- NetbufFree (Packet);
- return Status;
- }
- /**
- Process the Neighbor Advertisement message.
- @param[in] IpSb The IP service that received the packet.
- @param[in] Head The IP head of the message.
- @param[in] Packet The content of the message with IP head removed.
- @retval EFI_SUCCESS The packet processed successfully.
- @retval EFI_INVALID_PARAMETER The packet is invalid.
- @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
- @retval Others Failed to process the packet.
- **/
- EFI_STATUS
- Ip6ProcessNeighborAdvertise (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_ICMP_INFORMATION_HEAD Icmp;
- EFI_IPv6_ADDRESS Target;
- IP6_ETHER_ADDR_OPTION LinkLayerOption;
- BOOLEAN Provided;
- INTN Compare;
- IP6_NEIGHBOR_ENTRY *Neighbor;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- BOOLEAN Solicited;
- BOOLEAN IsRouter;
- BOOLEAN Override;
- IP6_DAD_ENTRY *DupAddrDetect;
- IP6_INTERFACE *IpIf;
- UINT16 OptionLen;
- UINT8 *Option;
- EFI_STATUS Status;
- NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
- NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
- //
- // Validate the incoming Neighbor Advertisement
- //
- Status = EFI_INVALID_PARAMETER;
- //
- // The IP Hop Limit field has a value of 255, i.e., the packet
- // could not possibly have been forwarded by a router.
- // ICMP Code is 0.
- // Target Address is not a multicast address.
- //
- if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) || !NetIp6IsValidUnicast (&Target)) {
- goto Exit;
- }
- //
- // ICMP length is 24 or more octets.
- //
- Provided = FALSE;
- OptionLen = 0;
- if (Head->PayloadLength < IP6_ND_LENGTH) {
- goto Exit;
- } else {
- OptionLen = (UINT16)(Head->PayloadLength - IP6_ND_LENGTH);
- if (OptionLen != 0) {
- Option = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
- ASSERT (Option != NULL);
- //
- // All included options should have a length that is greater than zero.
- //
- if (!Ip6IsNDOptionValid (Option, OptionLen)) {
- goto Exit;
- }
- }
- }
- //
- // If the IP destination address is a multicast address, Solicited Flag is ZERO.
- //
- Solicited = FALSE;
- if ((Icmp.Fourth & IP6_SOLICITED_FLAG) == IP6_SOLICITED_FLAG) {
- Solicited = TRUE;
- }
- if (IP6_IS_MULTICAST (&Head->DestinationAddress) && Solicited) {
- goto Exit;
- }
- //
- // DAD - Check whether the Target is one of our tentative address.
- //
- DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
- if (DupAddrDetect != NULL) {
- //
- // DAD fails, some other node is using this address.
- //
- NetbufFree (Packet);
- Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
- return EFI_ICMP_ERROR;
- }
- //
- // Search the Neighbor Cache for the target's entry. If no entry exists,
- // the advertisement should be silently discarded.
- //
- Neighbor = Ip6FindNeighborEntry (IpSb, &Target);
- if (Neighbor == NULL) {
- goto Exit;
- }
- //
- // Get IsRouter Flag and Override Flag
- //
- IsRouter = FALSE;
- Override = FALSE;
- if ((Icmp.Fourth & IP6_IS_ROUTER_FLAG) == IP6_IS_ROUTER_FLAG) {
- IsRouter = TRUE;
- }
- if ((Icmp.Fourth & IP6_OVERRIDE_FLAG) == IP6_OVERRIDE_FLAG) {
- Override = TRUE;
- }
- //
- // Check whether link layer option is included.
- //
- if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
- NetbufCopy (
- Packet,
- IP6_ND_LENGTH,
- sizeof (IP6_ETHER_ADDR_OPTION),
- (UINT8 *)&LinkLayerOption
- );
- if (LinkLayerOption.Type == Ip6OptionEtherTarget) {
- Provided = TRUE;
- }
- }
- Compare = 0;
- if (Provided) {
- Compare = CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
- }
- if (!Neighbor->IsRouter && IsRouter) {
- DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
- if (DefaultRouter != NULL) {
- DefaultRouter->NeighborCache = Neighbor;
- }
- }
- if (Neighbor->State == EfiNeighborInComplete) {
- //
- // If the target's Neighbor Cache entry is in INCOMPLETE state and no
- // Target Link-Layer address option is included while link layer has
- // address, the message should be silently discarded.
- //
- if (!Provided) {
- goto Exit;
- }
- //
- // Update the Neighbor Cache
- //
- CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
- if (Solicited) {
- Neighbor->State = EfiNeighborReachable;
- Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
- } else {
- Neighbor->State = EfiNeighborStale;
- Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- //
- // Send any packets queued for the neighbor awaiting address resolution.
- //
- Neighbor->CallBack ((VOID *)Neighbor);
- }
- Neighbor->IsRouter = IsRouter;
- } else {
- if (!Override && (Compare != 0)) {
- //
- // When the Override Flag is clear and supplied link-layer address differs from
- // that in the cache, if the state of the entry is not REACHABLE, ignore the
- // message. Otherwise set it to STALE but do not update the entry in any
- // other way.
- //
- if (Neighbor->State == EfiNeighborReachable) {
- Neighbor->State = EfiNeighborStale;
- Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- }
- } else {
- if (Compare != 0) {
- CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
- }
- //
- // Update the entry's state
- //
- if (Solicited) {
- Neighbor->State = EfiNeighborReachable;
- Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
- } else {
- if (Compare != 0) {
- Neighbor->State = EfiNeighborStale;
- Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- }
- }
- //
- // When IsRouter is changed from TRUE to FALSE, remove the router from the
- // Default Router List and remove the Destination Cache entries for all destinations
- // using the neighbor as a router.
- //
- if (Neighbor->IsRouter && !IsRouter) {
- DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
- if (DefaultRouter != NULL) {
- Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
- }
- }
- Neighbor->IsRouter = IsRouter;
- }
- }
- if (Neighbor->State == EfiNeighborReachable) {
- Neighbor->CallBack ((VOID *)Neighbor);
- }
- Status = EFI_SUCCESS;
- Exit:
- NetbufFree (Packet);
- return Status;
- }
- /**
- Process the Router Advertisement message according to RFC4861.
- @param[in] IpSb The IP service that received the packet.
- @param[in] Head The IP head of the message.
- @param[in] Packet The content of the message with the IP head removed.
- @retval EFI_SUCCESS The packet processed successfully.
- @retval EFI_INVALID_PARAMETER The packet is invalid.
- @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
- operation.
- @retval Others Failed to process the packet.
- **/
- EFI_STATUS
- Ip6ProcessRouterAdvertise (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_ICMP_INFORMATION_HEAD Icmp;
- UINT32 ReachableTime;
- UINT32 RetransTimer;
- UINT16 RouterLifetime;
- UINT32 Offset;
- UINT8 Type;
- UINT8 Length;
- IP6_ETHER_ADDR_OPTION LinkLayerOption;
- UINT32 Fourth;
- UINT8 CurHopLimit;
- BOOLEAN Mflag;
- BOOLEAN Oflag;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- IP6_NEIGHBOR_ENTRY *NeighborCache;
- EFI_MAC_ADDRESS LinkLayerAddress;
- IP6_MTU_OPTION MTUOption;
- IP6_PREFIX_INFO_OPTION PrefixOption;
- IP6_PREFIX_LIST_ENTRY *PrefixList;
- BOOLEAN OnLink;
- BOOLEAN Autonomous;
- EFI_IPv6_ADDRESS StatelessAddress;
- EFI_STATUS Status;
- UINT16 OptionLen;
- UINT8 *Option;
- INTN Result;
- Status = EFI_INVALID_PARAMETER;
- if (IpSb->Ip6ConfigInstance.Policy != Ip6ConfigPolicyAutomatic) {
- //
- // Skip the process below as it's not required under the current policy.
- //
- goto Exit;
- }
- NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);
- //
- // Validate the incoming Router Advertisement
- //
- //
- // The IP source address must be a link-local address
- //
- if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
- goto Exit;
- }
- //
- // The IP Hop Limit field has a value of 255, i.e. the packet
- // could not possibly have been forwarded by a router.
- // ICMP Code is 0.
- // ICMP length (derived from the IP length) is 16 or more octets.
- //
- if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp.Head.Code != 0) ||
- (Head->PayloadLength < IP6_RA_LENGTH))
- {
- goto Exit;
- }
- //
- // All included options have a length that is greater than zero.
- //
- OptionLen = (UINT16)(Head->PayloadLength - IP6_RA_LENGTH);
- if (OptionLen != 0) {
- Option = NetbufGetByte (Packet, IP6_RA_LENGTH, NULL);
- ASSERT (Option != NULL);
- if (!Ip6IsNDOptionValid (Option, OptionLen)) {
- goto Exit;
- }
- }
- //
- // Process Fourth field.
- // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
- // and Router Lifetime (16 bit).
- //
- Fourth = NTOHL (Icmp.Fourth);
- CopyMem (&RouterLifetime, &Fourth, sizeof (UINT16));
- //
- // If the source address already in the default router list, update it.
- // Otherwise create a new entry.
- // A Lifetime of zero indicates that the router is not a default router.
- //
- DefaultRouter = Ip6FindDefaultRouter (IpSb, &Head->SourceAddress);
- if (DefaultRouter == NULL) {
- if (RouterLifetime != 0) {
- DefaultRouter = Ip6CreateDefaultRouter (IpSb, &Head->SourceAddress, RouterLifetime);
- if (DefaultRouter == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- }
- } else {
- if (RouterLifetime != 0) {
- DefaultRouter->Lifetime = RouterLifetime;
- //
- // Check the corresponding neighbor cache entry here.
- //
- if (DefaultRouter->NeighborCache == NULL) {
- DefaultRouter->NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
- }
- } else {
- //
- // If the address is in the host's default router list and the router lifetime is zero,
- // immediately time-out the entry.
- //
- Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
- }
- }
- CurHopLimit = *((UINT8 *)&Fourth + 3);
- if (CurHopLimit != 0) {
- IpSb->CurHopLimit = CurHopLimit;
- }
- Mflag = FALSE;
- Oflag = FALSE;
- if ((*((UINT8 *)&Fourth + 2) & IP6_M_ADDR_CONFIG_FLAG) == IP6_M_ADDR_CONFIG_FLAG) {
- Mflag = TRUE;
- } else {
- if ((*((UINT8 *)&Fourth + 2) & IP6_O_CONFIG_FLAG) == IP6_O_CONFIG_FLAG) {
- Oflag = TRUE;
- }
- }
- if (Mflag || Oflag) {
- //
- // Use Ip6Config to get available addresses or other configuration from DHCP.
- //
- Ip6ConfigStartStatefulAutoConfig (&IpSb->Ip6ConfigInstance, Oflag);
- }
- //
- // Process Reachable Time and Retrans Timer fields.
- //
- NetbufCopy (Packet, sizeof (Icmp), sizeof (UINT32), (UINT8 *)&ReachableTime);
- NetbufCopy (Packet, sizeof (Icmp) + sizeof (UINT32), sizeof (UINT32), (UINT8 *)&RetransTimer);
- ReachableTime = NTOHL (ReachableTime);
- RetransTimer = NTOHL (RetransTimer);
- if ((ReachableTime != 0) && (ReachableTime != IpSb->BaseReachableTime)) {
- //
- // If new value is not unspecified and differs from the previous one, record it
- // in BaseReachableTime and recompute a ReachableTime.
- //
- IpSb->BaseReachableTime = ReachableTime;
- Ip6UpdateReachableTime (IpSb);
- }
- if (RetransTimer != 0) {
- IpSb->RetransTimer = RetransTimer;
- }
- //
- // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
- //
- NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
- if (NeighborCache != NULL) {
- NeighborCache->IsRouter = TRUE;
- }
- //
- // If an valid router advertisement is received, stops router solicitation.
- //
- IpSb->RouterAdvertiseReceived = TRUE;
- //
- // The only defined options that may appear are the Source
- // Link-Layer Address, Prefix information and MTU options.
- // All included options have a length that is greater than zero and
- // fit within the input packet.
- //
- Offset = 16;
- while (Offset < (UINT32)Head->PayloadLength) {
- NetbufCopy (Packet, Offset, sizeof (UINT8), &Type);
- switch (Type) {
- case Ip6OptionEtherSource:
- //
- // Update the neighbor cache
- //
- NetbufCopy (Packet, Offset, sizeof (IP6_ETHER_ADDR_OPTION), (UINT8 *)&LinkLayerOption);
- //
- // Option size validity ensured by Ip6IsNDOptionValid().
- //
- ASSERT (LinkLayerOption.Length != 0);
- ASSERT (Offset + (UINT32)LinkLayerOption.Length * 8 <= (UINT32)Head->PayloadLength);
- ZeroMem (&LinkLayerAddress, sizeof (EFI_MAC_ADDRESS));
- CopyMem (&LinkLayerAddress, LinkLayerOption.EtherAddr, 6);
- if (NeighborCache == NULL) {
- NeighborCache = Ip6CreateNeighborEntry (
- IpSb,
- Ip6OnArpResolved,
- &Head->SourceAddress,
- &LinkLayerAddress
- );
- if (NeighborCache == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- NeighborCache->IsRouter = TRUE;
- NeighborCache->State = EfiNeighborStale;
- NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- } else {
- Result = CompareMem (&LinkLayerAddress, &NeighborCache->LinkAddress, 6);
- //
- // If the link-local address is the same as that already in the cache,
- // the cache entry's state remains unchanged. Otherwise update the
- // reachability state to STALE.
- //
- if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
- CopyMem (&NeighborCache->LinkAddress, &LinkLayerAddress, 6);
- NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- if (NeighborCache->State == EfiNeighborInComplete) {
- //
- // Send queued packets if exist.
- //
- NeighborCache->State = EfiNeighborStale;
- NeighborCache->CallBack ((VOID *)NeighborCache);
- } else {
- NeighborCache->State = EfiNeighborStale;
- }
- }
- }
- Offset += (UINT32)LinkLayerOption.Length * 8;
- break;
- case Ip6OptionPrefixInfo:
- NetbufCopy (Packet, Offset, sizeof (IP6_PREFIX_INFO_OPTION), (UINT8 *)&PrefixOption);
- //
- // Option size validity ensured by Ip6IsNDOptionValid().
- //
- ASSERT (PrefixOption.Length == 4);
- ASSERT (Offset + (UINT32)PrefixOption.Length * 8 <= (UINT32)Head->PayloadLength);
- PrefixOption.ValidLifetime = NTOHL (PrefixOption.ValidLifetime);
- PrefixOption.PreferredLifetime = NTOHL (PrefixOption.PreferredLifetime);
- //
- // Get L and A flag, recorded in the lower 2 bits of Reserved1
- //
- OnLink = FALSE;
- if ((PrefixOption.Reserved1 & IP6_ON_LINK_FLAG) == IP6_ON_LINK_FLAG) {
- OnLink = TRUE;
- }
- Autonomous = FALSE;
- if ((PrefixOption.Reserved1 & IP6_AUTO_CONFIG_FLAG) == IP6_AUTO_CONFIG_FLAG) {
- Autonomous = TRUE;
- }
- //
- // If the prefix is the link-local prefix, silently ignore the prefix option.
- //
- if ((PrefixOption.PrefixLength == IP6_LINK_LOCAL_PREFIX_LENGTH) &&
- NetIp6IsLinkLocalAddr (&PrefixOption.Prefix)
- )
- {
- Offset += sizeof (IP6_PREFIX_INFO_OPTION);
- break;
- }
- //
- // Do following if on-link flag is set according to RFC4861.
- //
- if (OnLink) {
- PrefixList = Ip6FindPrefixListEntry (
- IpSb,
- TRUE,
- PrefixOption.PrefixLength,
- &PrefixOption.Prefix
- );
- //
- // Create a new entry for the prefix, if the ValidLifetime is zero,
- // silently ignore the prefix option.
- //
- if ((PrefixList == NULL) && (PrefixOption.ValidLifetime != 0)) {
- PrefixList = Ip6CreatePrefixListEntry (
- IpSb,
- TRUE,
- PrefixOption.ValidLifetime,
- PrefixOption.PreferredLifetime,
- PrefixOption.PrefixLength,
- &PrefixOption.Prefix
- );
- if (PrefixList == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- } else if (PrefixList != NULL) {
- if (PrefixOption.ValidLifetime != 0) {
- PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
- } else {
- //
- // If the prefix exists and incoming ValidLifetime is zero, immediately
- // remove the prefix.
- Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
- }
- }
- }
- //
- // Do following if Autonomous flag is set according to RFC4862.
- //
- if (Autonomous && (PrefixOption.PreferredLifetime <= PrefixOption.ValidLifetime)) {
- PrefixList = Ip6FindPrefixListEntry (
- IpSb,
- FALSE,
- PrefixOption.PrefixLength,
- &PrefixOption.Prefix
- );
- //
- // Create a new entry for the prefix, and form an address by prefix + interface id
- // If the sum of the prefix length and interface identifier length
- // does not equal 128 bits, the Prefix Information option MUST be ignored.
- //
- if ((PrefixList == NULL) &&
- (PrefixOption.ValidLifetime != 0) &&
- (PrefixOption.PrefixLength + IpSb->InterfaceIdLen * 8 == 128)
- )
- {
- //
- // Form the address in network order.
- //
- CopyMem (&StatelessAddress, &PrefixOption.Prefix, sizeof (UINT64));
- CopyMem (&StatelessAddress.Addr[8], IpSb->InterfaceId, sizeof (UINT64));
- //
- // If the address is not yet in the assigned address list, adds it into.
- //
- if (!Ip6IsOneOfSetAddress (IpSb, &StatelessAddress, NULL, NULL)) {
- //
- // And also not in the DAD process, check its uniqueness firstly.
- //
- if (Ip6FindDADEntry (IpSb, &StatelessAddress, NULL) == NULL) {
- Status = Ip6SetAddress (
- IpSb->DefaultInterface,
- &StatelessAddress,
- FALSE,
- PrefixOption.PrefixLength,
- PrefixOption.ValidLifetime,
- PrefixOption.PreferredLifetime,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- goto Exit;
- }
- }
- }
- //
- // Adds the prefix option to stateless prefix option list.
- //
- PrefixList = Ip6CreatePrefixListEntry (
- IpSb,
- FALSE,
- PrefixOption.ValidLifetime,
- PrefixOption.PreferredLifetime,
- PrefixOption.PrefixLength,
- &PrefixOption.Prefix
- );
- if (PrefixList == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- } else if (PrefixList != NULL) {
- //
- // Reset the preferred lifetime of the address if the advertised prefix exists.
- // Perform specific action to valid lifetime together.
- //
- PrefixList->PreferredLifetime = PrefixOption.PreferredLifetime;
- if ((PrefixOption.ValidLifetime > 7200) ||
- (PrefixOption.ValidLifetime > PrefixList->ValidLifetime))
- {
- //
- // If the received Valid Lifetime is greater than 2 hours or
- // greater than RemainingLifetime, set the valid lifetime of the
- // corresponding address to the advertised Valid Lifetime.
- //
- PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
- } else if (PrefixList->ValidLifetime <= 7200) {
- //
- // If RemainingLifetime is less than or equals to 2 hours, ignore the
- // Prefix Information option with regards to the valid lifetime.
- // TODO: If this option has been authenticated, set the valid lifetime.
- //
- } else {
- //
- // Otherwise, reset the valid lifetime of the corresponding
- // address to 2 hours.
- //
- PrefixList->ValidLifetime = 7200;
- }
- }
- }
- Offset += sizeof (IP6_PREFIX_INFO_OPTION);
- break;
- case Ip6OptionMtu:
- NetbufCopy (Packet, Offset, sizeof (IP6_MTU_OPTION), (UINT8 *)&MTUOption);
- //
- // Option size validity ensured by Ip6IsNDOptionValid().
- //
- ASSERT (MTUOption.Length == 1);
- ASSERT (Offset + (UINT32)MTUOption.Length * 8 <= (UINT32)Head->PayloadLength);
- //
- // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
- // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
- // in Router Advertisement.
- //
- Offset += sizeof (IP6_MTU_OPTION);
- break;
- default:
- //
- // Silently ignore unrecognized options
- //
- NetbufCopy (Packet, Offset + sizeof (UINT8), sizeof (UINT8), &Length);
- ASSERT (Length != 0);
- Offset += (UINT32)Length * 8;
- break;
- }
- }
- Status = EFI_SUCCESS;
- Exit:
- NetbufFree (Packet);
- return Status;
- }
- /**
- Process the ICMPv6 redirect message. Find the instance, then update
- its route cache.
- @param[in] IpSb The IP6 service binding instance that received
- the packet.
- @param[in] Head The IP head of the received ICMPv6 packet.
- @param[in] Packet The content of the ICMPv6 redirect packet with
- the IP head removed.
- @retval EFI_INVALID_PARAMETER The parameter is invalid.
- @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
- operation.
- @retval EFI_SUCCESS Successfully updated the route caches.
- **/
- EFI_STATUS
- Ip6ProcessRedirect (
- IN IP6_SERVICE *IpSb,
- IN EFI_IP6_HEADER *Head,
- IN NET_BUF *Packet
- )
- {
- IP6_ICMP_INFORMATION_HEAD *Icmp;
- EFI_IPv6_ADDRESS *Target;
- EFI_IPv6_ADDRESS *IcmpDest;
- UINT8 *Option;
- UINT16 OptionLen;
- IP6_ROUTE_ENTRY *RouteEntry;
- IP6_ROUTE_CACHE_ENTRY *RouteCache;
- IP6_NEIGHBOR_ENTRY *NeighborCache;
- INT32 Length;
- UINT8 OptLen;
- IP6_ETHER_ADDR_OPTION *LinkLayerOption;
- EFI_MAC_ADDRESS Mac;
- UINT32 Index;
- BOOLEAN IsRouter;
- EFI_STATUS Status;
- INTN Result;
- Status = EFI_INVALID_PARAMETER;
- Icmp = (IP6_ICMP_INFORMATION_HEAD *)NetbufGetByte (Packet, 0, NULL);
- if (Icmp == NULL) {
- goto Exit;
- }
- //
- // Validate the incoming Redirect message
- //
- //
- // The IP Hop Limit field has a value of 255, i.e. the packet
- // could not possibly have been forwarded by a router.
- // ICMP Code is 0.
- // ICMP length (derived from the IP length) is 40 or more octets.
- //
- if ((Head->HopLimit != IP6_HOP_LIMIT) || (Icmp->Head.Code != 0) ||
- (Head->PayloadLength < IP6_REDITECT_LENGTH))
- {
- goto Exit;
- }
- //
- // The IP source address must be a link-local address
- //
- if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
- goto Exit;
- }
- //
- // The dest of this ICMP redirect message is not us.
- //
- if (!Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
- goto Exit;
- }
- //
- // All included options have a length that is greater than zero.
- //
- OptionLen = (UINT16)(Head->PayloadLength - IP6_REDITECT_LENGTH);
- if (OptionLen != 0) {
- Option = NetbufGetByte (Packet, IP6_REDITECT_LENGTH, NULL);
- ASSERT (Option != NULL);
- if (!Ip6IsNDOptionValid (Option, OptionLen)) {
- goto Exit;
- }
- }
- Target = (EFI_IPv6_ADDRESS *)(Icmp + 1);
- IcmpDest = Target + 1;
- //
- // The ICMP Destination Address field in the redirect message does not contain
- // a multicast address.
- //
- if (IP6_IS_MULTICAST (IcmpDest)) {
- goto Exit;
- }
- //
- // The ICMP Target Address is either a link-local address (when redirected to
- // a router) or the same as the ICMP Destination Address (when redirected to
- // the on-link destination).
- //
- IsRouter = (BOOLEAN) !EFI_IP6_EQUAL (Target, IcmpDest);
- if (!NetIp6IsLinkLocalAddr (Target) && IsRouter) {
- goto Exit;
- }
- //
- // Check the options. The only interested option here is the target-link layer
- // address option.
- //
- Length = Packet->TotalSize - 40;
- Option = (UINT8 *)(IcmpDest + 1);
- LinkLayerOption = NULL;
- while (Length > 0) {
- switch (*Option) {
- case Ip6OptionEtherTarget:
- LinkLayerOption = (IP6_ETHER_ADDR_OPTION *)Option;
- OptLen = LinkLayerOption->Length;
- if (OptLen != 1) {
- //
- // For ethernet, the length must be 1.
- //
- goto Exit;
- }
- break;
- default:
- OptLen = *(Option + 1);
- if (OptLen == 0) {
- //
- // A length of 0 is invalid.
- //
- goto Exit;
- }
- break;
- }
- Length -= 8 * OptLen;
- Option += 8 * OptLen;
- }
- if (Length != 0) {
- goto Exit;
- }
- //
- // The IP source address of the Redirect is the same as the current
- // first-hop router for the specified ICMP Destination Address.
- //
- RouteCache = Ip6FindRouteCache (IpSb->RouteTable, IcmpDest, &Head->DestinationAddress);
- if (RouteCache != NULL) {
- if (!EFI_IP6_EQUAL (&RouteCache->NextHop, &Head->SourceAddress)) {
- //
- // The source of this Redirect message must match the NextHop of the
- // corresponding route cache entry.
- //
- goto Exit;
- }
- //
- // Update the NextHop.
- //
- IP6_COPY_ADDRESS (&RouteCache->NextHop, Target);
- if (!IsRouter) {
- RouteEntry = (IP6_ROUTE_ENTRY *)RouteCache->Tag;
- RouteEntry->Flag = RouteEntry->Flag | IP6_DIRECT_ROUTE;
- }
- } else {
- //
- // Get the Route Entry.
- //
- RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, IcmpDest, NULL);
- if (RouteEntry == NULL) {
- RouteEntry = Ip6CreateRouteEntry (IcmpDest, 0, NULL);
- if (RouteEntry == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- }
- if (!IsRouter) {
- RouteEntry->Flag = IP6_DIRECT_ROUTE;
- }
- //
- // Create a route cache for this.
- //
- RouteCache = Ip6CreateRouteCacheEntry (
- IcmpDest,
- &Head->DestinationAddress,
- Target,
- (UINTN)RouteEntry
- );
- if (RouteCache == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Exit;
- }
- //
- // Insert the newly created route cache entry.
- //
- Index = IP6_ROUTE_CACHE_HASH (IcmpDest, &Head->DestinationAddress);
- InsertHeadList (&IpSb->RouteTable->Cache.CacheBucket[Index], &RouteCache->Link);
- }
- //
- // Try to locate the neighbor cache for the Target.
- //
- NeighborCache = Ip6FindNeighborEntry (IpSb, Target);
- if (LinkLayerOption != NULL) {
- if (NeighborCache == NULL) {
- //
- // Create a neighbor cache for the Target.
- //
- ZeroMem (&Mac, sizeof (EFI_MAC_ADDRESS));
- CopyMem (&Mac, LinkLayerOption->EtherAddr, 6);
- NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, Target, &Mac);
- if (NeighborCache == NULL) {
- //
- // Just report a success here. The neighbor cache can be created in
- // some other place.
- //
- Status = EFI_SUCCESS;
- goto Exit;
- }
- NeighborCache->State = EfiNeighborStale;
- NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- } else {
- Result = CompareMem (LinkLayerOption->EtherAddr, &NeighborCache->LinkAddress, 6);
- //
- // If the link-local address is the same as that already in the cache,
- // the cache entry's state remains unchanged. Otherwise update the
- // reachability state to STALE.
- //
- if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
- CopyMem (&NeighborCache->LinkAddress, LinkLayerOption->EtherAddr, 6);
- NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- if (NeighborCache->State == EfiNeighborInComplete) {
- //
- // Send queued packets if exist.
- //
- NeighborCache->State = EfiNeighborStale;
- NeighborCache->CallBack ((VOID *)NeighborCache);
- } else {
- NeighborCache->State = EfiNeighborStale;
- }
- }
- }
- }
- if ((NeighborCache != NULL) && IsRouter) {
- //
- // The Target is a router, set IsRouter to TRUE.
- //
- NeighborCache->IsRouter = TRUE;
- }
- Status = EFI_SUCCESS;
- Exit:
- NetbufFree (Packet);
- return Status;
- }
- /**
- Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
- @param[in] IpSb The IP6 service binding instance.
- @param[in] TargetIp6Address Pointer to Target IPv6 address.
- @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
- @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
- cache. It will be deleted after Timeout. A value of zero means that
- the entry is permanent. A non-zero value means that the entry is
- dynamic.
- @param[in] Override If TRUE, the cached link-layer address of the matching entry will
- be overridden and updated; if FALSE, and if a
- corresponding cache entry already existed, EFI_ACCESS_DENIED
- will be returned.
- @retval EFI_SUCCESS The neighbor cache entry has been added.
- @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
- due to insufficient resources.
- @retval EFI_NOT_FOUND TargetLinkAddress is NULL.
- @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
- and that entry is tagged as un-overridden (when DeleteFlag
- is FALSE).
- **/
- EFI_STATUS
- Ip6AddNeighbor (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *TargetIp6Address,
- IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
- IN UINT32 Timeout,
- IN BOOLEAN Override
- )
- {
- IP6_NEIGHBOR_ENTRY *Neighbor;
- Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
- if (Neighbor != NULL) {
- if (!Override) {
- return EFI_ACCESS_DENIED;
- } else {
- if (TargetLinkAddress != NULL) {
- IP6_COPY_LINK_ADDRESS (&Neighbor->LinkAddress, TargetLinkAddress);
- }
- }
- } else {
- if (TargetLinkAddress == NULL) {
- return EFI_NOT_FOUND;
- }
- Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, TargetLinkAddress);
- if (Neighbor == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
- Neighbor->State = EfiNeighborReachable;
- if (Timeout != 0) {
- Neighbor->Ticks = IP6_GET_TICKS (Timeout / TICKS_PER_MS);
- Neighbor->Dynamic = TRUE;
- } else {
- Neighbor->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- }
- return EFI_SUCCESS;
- }
- /**
- Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
- @param[in] IpSb The IP6 service binding instance.
- @param[in] TargetIp6Address Pointer to Target IPv6 address.
- @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
- @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
- cache. It will be deleted after Timeout. A value of zero means that
- the entry is permanent. A non-zero value means that the entry is
- dynamic.
- @param[in] Override If TRUE, the cached link-layer address of the matching entry will
- be overridden and updated; if FALSE, and if a
- corresponding cache entry already existed, EFI_ACCESS_DENIED
- will be returned.
- @retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
- @retval EFI_NOT_FOUND This entry is not in the neighbor cache.
- **/
- EFI_STATUS
- Ip6DelNeighbor (
- IN IP6_SERVICE *IpSb,
- IN EFI_IPv6_ADDRESS *TargetIp6Address,
- IN EFI_MAC_ADDRESS *TargetLinkAddress OPTIONAL,
- IN UINT32 Timeout,
- IN BOOLEAN Override
- )
- {
- IP6_NEIGHBOR_ENTRY *Neighbor;
- Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
- if (Neighbor == NULL) {
- return EFI_NOT_FOUND;
- }
- RemoveEntryList (&Neighbor->Link);
- FreePool (Neighbor);
- return EFI_SUCCESS;
- }
- /**
- The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
- This time routine handles DAD module and neighbor state transition.
- It is also responsible for sending out router solicitations.
- @param[in] Event The IP6 service instance's heartbeat timer.
- @param[in] Context The IP6 service instance.
- **/
- VOID
- EFIAPI
- Ip6NdFasterTimerTicking (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- LIST_ENTRY *Entry2;
- IP6_INTERFACE *IpIf;
- IP6_DELAY_JOIN_LIST *DelayNode;
- EFI_IPv6_ADDRESS Source;
- IP6_DAD_ENTRY *DupAddrDetect;
- EFI_STATUS Status;
- IP6_NEIGHBOR_ENTRY *NeighborCache;
- EFI_IPv6_ADDRESS Destination;
- IP6_SERVICE *IpSb;
- BOOLEAN Flag;
- IpSb = (IP6_SERVICE *)Context;
- NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
- ZeroMem (&Source, sizeof (EFI_IPv6_ADDRESS));
- //
- // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
- // Solicitation messages, each separated by at least
- // RTR_SOLICITATION_INTERVAL (4) seconds.
- //
- if ((IpSb->Ip6ConfigInstance.Policy == Ip6ConfigPolicyAutomatic) &&
- !IpSb->RouterAdvertiseReceived &&
- (IpSb->SolicitTimer > 0)
- )
- {
- if ((IpSb->Ticks == 0) || (--IpSb->Ticks == 0)) {
- Status = Ip6SendRouterSolicit (IpSb, NULL, NULL, NULL, NULL);
- if (!EFI_ERROR (Status)) {
- IpSb->SolicitTimer--;
- IpSb->Ticks = (UINT32)IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL);
- }
- }
- }
- NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
- IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
- //
- // Process the delay list to join the solicited-node multicast address.
- //
- NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
- DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
- if ((DelayNode->DelayTime == 0) || (--DelayNode->DelayTime == 0)) {
- //
- // The timer expires, init the duplicate address detection.
- //
- Ip6InitDADProcess (
- DelayNode->Interface,
- DelayNode->AddressInfo,
- DelayNode->DadCallback,
- DelayNode->Context
- );
- //
- // Remove the delay node
- //
- RemoveEntryList (&DelayNode->Link);
- FreePool (DelayNode);
- }
- }
- //
- // Process the duplicate address detection list.
- //
- NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
- DupAddrDetect = NET_LIST_USER_STRUCT (Entry2, IP6_DAD_ENTRY, Link);
- if ((DupAddrDetect->RetransTick == 0) || (--DupAddrDetect->RetransTick == 0)) {
- //
- // The timer expires, check the remaining transmit counts.
- //
- if (DupAddrDetect->Transmit < DupAddrDetect->MaxTransmit) {
- //
- // Send the Neighbor Solicitation message with
- // Source - unspecified address, destination - solicited-node multicast address
- // Target - the address to be validated
- //
- Status = Ip6SendNeighborSolicit (
- IpSb,
- NULL,
- &DupAddrDetect->Destination,
- &DupAddrDetect->AddressInfo->Address,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- DupAddrDetect->Transmit++;
- DupAddrDetect->RetransTick = IP6_GET_TICKS (IpSb->RetransTimer);
- } else {
- //
- // All required solicitation has been sent out, and the RetransTime after the last
- // Neighbor Solicit is elapsed, finish the DAD process.
- //
- Flag = FALSE;
- if ((DupAddrDetect->Receive == 0) ||
- (DupAddrDetect->Transmit <= DupAddrDetect->Receive))
- {
- Flag = TRUE;
- }
- Ip6OnDADFinished (Flag, IpIf, DupAddrDetect);
- }
- }
- }
- }
- //
- // Polling the state of Neighbor cache
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
- NeighborCache = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
- switch (NeighborCache->State) {
- case EfiNeighborInComplete:
- if (NeighborCache->Ticks > 0) {
- --NeighborCache->Ticks;
- }
- //
- // Retransmit Neighbor Solicitation messages approximately every
- // RetransTimer milliseconds while awaiting a response.
- //
- if (NeighborCache->Ticks == 0) {
- if (NeighborCache->Transmit > 1) {
- //
- // Send out multicast neighbor solicitation for address resolution.
- // After last neighbor solicitation message has been sent out, wait
- // for RetransTimer and then remove entry if no response is received.
- //
- Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
- Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
- if (EFI_ERROR (Status)) {
- return;
- }
- Status = Ip6SendNeighborSolicit (
- IpSb,
- &Source,
- &Destination,
- &NeighborCache->Neighbor,
- &IpSb->SnpMode.CurrentAddress
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- }
- //
- // Update the retransmit times.
- //
- if (NeighborCache->Transmit > 0) {
- --NeighborCache->Transmit;
- NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
- }
- }
- if (NeighborCache->Transmit == 0) {
- //
- // Timeout, send ICMP destination unreachable packet and then remove entry
- //
- Status = Ip6FreeNeighborEntry (
- IpSb,
- NeighborCache,
- TRUE,
- TRUE,
- EFI_ICMP_ERROR,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- }
- break;
- case EfiNeighborReachable:
- //
- // This entry is inserted by EfiIp6Neighbors() as static entry
- // and will not timeout.
- //
- if (!NeighborCache->Dynamic && (NeighborCache->Ticks == IP6_INFINIT_LIFETIME)) {
- break;
- }
- if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
- if (NeighborCache->Dynamic) {
- //
- // This entry is inserted by EfiIp6Neighbors() as dynamic entry
- // and will be deleted after timeout.
- //
- Status = Ip6FreeNeighborEntry (
- IpSb,
- NeighborCache,
- FALSE,
- TRUE,
- EFI_TIMEOUT,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- } else {
- NeighborCache->State = EfiNeighborStale;
- NeighborCache->Ticks = (UINT32)IP6_INFINIT_LIFETIME;
- }
- }
- break;
- case EfiNeighborDelay:
- if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
- NeighborCache->State = EfiNeighborProbe;
- NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
- NeighborCache->Transmit = IP6_MAX_UNICAST_SOLICIT + 1;
- //
- // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
- //
- Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
- if (EFI_ERROR (Status)) {
- return;
- }
- Status = Ip6SendNeighborSolicit (
- IpSb,
- &Source,
- &NeighborCache->Neighbor,
- &NeighborCache->Neighbor,
- &IpSb->SnpMode.CurrentAddress
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- NeighborCache->Transmit--;
- }
- break;
- case EfiNeighborProbe:
- if (NeighborCache->Ticks > 0) {
- --NeighborCache->Ticks;
- }
- //
- // Retransmit Neighbor Solicitation messages approximately every
- // RetransTimer milliseconds while awaiting a response.
- //
- if (NeighborCache->Ticks == 0) {
- if (NeighborCache->Transmit > 1) {
- //
- // Send out unicast neighbor solicitation for Neighbor Unreachability
- // Detection. After last neighbor solicitation message has been sent out,
- // wait for RetransTimer and then remove entry if no response is received.
- //
- Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
- if (EFI_ERROR (Status)) {
- return;
- }
- Status = Ip6SendNeighborSolicit (
- IpSb,
- &Source,
- &NeighborCache->Neighbor,
- &NeighborCache->Neighbor,
- &IpSb->SnpMode.CurrentAddress
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- }
- //
- // Update the retransmit times.
- //
- if (NeighborCache->Transmit > 0) {
- --NeighborCache->Transmit;
- NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
- }
- }
- if (NeighborCache->Transmit == 0) {
- //
- // Delete the neighbor entry.
- //
- Status = Ip6FreeNeighborEntry (
- IpSb,
- NeighborCache,
- FALSE,
- TRUE,
- EFI_TIMEOUT,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return;
- }
- }
- break;
- default:
- break;
- }
- }
- }
- /**
- The heartbeat timer of ND module in 1 second. This time routine handles following
- things: 1) maintain default router list; 2) maintain prefix options;
- 3) maintain route caches.
- @param[in] IpSb The IP6 service binding instance.
- **/
- VOID
- Ip6NdTimerTicking (
- IN IP6_SERVICE *IpSb
- )
- {
- LIST_ENTRY *Entry;
- LIST_ENTRY *Next;
- IP6_DEFAULT_ROUTER *DefaultRouter;
- IP6_PREFIX_LIST_ENTRY *PrefixOption;
- UINT8 Index;
- IP6_ROUTE_CACHE_ENTRY *RouteCache;
- //
- // Decrease the lifetime of default router, if expires remove it from default router list.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->DefaultRouterList) {
- DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
- if (DefaultRouter->Lifetime != IP6_INF_ROUTER_LIFETIME) {
- if ((DefaultRouter->Lifetime == 0) || (--DefaultRouter->Lifetime == 0)) {
- Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
- }
- }
- }
- //
- // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
- //
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->AutonomousPrefix) {
- PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
- if (PrefixOption->ValidLifetime != (UINT32)IP6_INFINIT_LIFETIME) {
- if ((PrefixOption->ValidLifetime > 0) && (--PrefixOption->ValidLifetime > 0)) {
- if ((PrefixOption->PreferredLifetime != (UINT32)IP6_INFINIT_LIFETIME) &&
- (PrefixOption->PreferredLifetime > 0)
- )
- {
- --PrefixOption->PreferredLifetime;
- }
- } else {
- Ip6DestroyPrefixListEntry (IpSb, PrefixOption, FALSE, TRUE);
- }
- }
- }
- NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->OnlinkPrefix) {
- PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
- if (PrefixOption->ValidLifetime != (UINT32)IP6_INFINIT_LIFETIME) {
- if ((PrefixOption->ValidLifetime == 0) || (--PrefixOption->ValidLifetime == 0)) {
- Ip6DestroyPrefixListEntry (IpSb, PrefixOption, TRUE, TRUE);
- }
- }
- }
- //
- // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
- // Remove the entries at the tail of the bucket. These entries
- // are likely to be used least.
- // Reclaim frequency is set to 1 second.
- //
- for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
- while (IpSb->RouteTable->Cache.CacheNum[Index] > IP6_ROUTE_CACHE_MAX) {
- Entry = NetListRemoveTail (&IpSb->RouteTable->Cache.CacheBucket[Index]);
- if (Entry == NULL) {
- break;
- }
- RouteCache = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
- Ip6FreeRouteCacheEntry (RouteCache);
- ASSERT (IpSb->RouteTable->Cache.CacheNum[Index] > 0);
- IpSb->RouteTable->Cache.CacheNum[Index]--;
- }
- }
- }
|