Dhcp6Io.c 90 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136
  1. /** @file
  2. Dhcp6 internal functions implementation.
  3. (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
  4. Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "Dhcp6Impl.h"
  8. /**
  9. Enqueue the packet into the retry list in case of timeout.
  10. @param[in] Instance The pointer to the Dhcp6 instance.
  11. @param[in] Packet The pointer to the Dhcp6 packet to retry.
  12. @param[in] Elapsed The pointer to the elapsed time value in the packet.
  13. @param[in] RetryCtl The pointer to the transmission control of the packet.
  14. This parameter is optional and may be NULL.
  15. @retval EFI_SUCCESS Successfully enqueued the packet into the retry list according
  16. to its message type.
  17. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  18. @retval EFI_DEVICE_ERROR An unexpected message type.
  19. **/
  20. EFI_STATUS
  21. Dhcp6EnqueueRetry (
  22. IN DHCP6_INSTANCE *Instance,
  23. IN EFI_DHCP6_PACKET *Packet,
  24. IN UINT16 *Elapsed,
  25. IN EFI_DHCP6_RETRANSMISSION *RetryCtl OPTIONAL
  26. )
  27. {
  28. DHCP6_TX_CB *TxCb;
  29. DHCP6_IA_CB *IaCb;
  30. ASSERT (Packet != NULL);
  31. IaCb = &Instance->IaCb;
  32. TxCb = AllocateZeroPool (sizeof (DHCP6_TX_CB));
  33. if (TxCb == NULL) {
  34. return EFI_OUT_OF_RESOURCES;
  35. }
  36. //
  37. // Save tx packet pointer, and it will be destroyed when reply received.
  38. //
  39. TxCb->TxPacket = Packet;
  40. TxCb->Xid = Packet->Dhcp6.Header.TransactionId;
  41. //
  42. // Save pointer to elapsed-time value so we can update it on retransmits.
  43. //
  44. TxCb->Elapsed = Elapsed;
  45. //
  46. // Calculate the retransmission according to the message type.
  47. //
  48. switch (Packet->Dhcp6.Header.MessageType) {
  49. case Dhcp6MsgSolicit:
  50. //
  51. // Calculate the retransmission threshold value for solicit packet.
  52. // Use the default value by rfc-3315 if user doesn't configure.
  53. //
  54. if (RetryCtl == NULL) {
  55. TxCb->RetryCtl.Irt = DHCP6_SOL_IRT;
  56. TxCb->RetryCtl.Mrc = DHCP6_SOL_MRC;
  57. TxCb->RetryCtl.Mrt = DHCP6_SOL_MRT;
  58. TxCb->RetryCtl.Mrd = DHCP6_SOL_MRD;
  59. } else {
  60. TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_SOL_IRT;
  61. TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_SOL_MRC;
  62. TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_SOL_MRT;
  63. TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_SOL_MRD;
  64. }
  65. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  66. TxCb->RetryCtl.Irt,
  67. TRUE,
  68. FALSE
  69. );
  70. break;
  71. case Dhcp6MsgRequest:
  72. //
  73. // Calculate the retransmission threshold value for request packet.
  74. //
  75. TxCb->RetryCtl.Irt = DHCP6_REQ_IRT;
  76. TxCb->RetryCtl.Mrc = DHCP6_REQ_MRC;
  77. TxCb->RetryCtl.Mrt = DHCP6_REQ_MRT;
  78. TxCb->RetryCtl.Mrd = DHCP6_REQ_MRD;
  79. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  80. TxCb->RetryCtl.Irt,
  81. TRUE,
  82. TRUE
  83. );
  84. break;
  85. case Dhcp6MsgConfirm:
  86. //
  87. // Calculate the retransmission threshold value for confirm packet.
  88. //
  89. TxCb->RetryCtl.Irt = DHCP6_CNF_IRT;
  90. TxCb->RetryCtl.Mrc = DHCP6_CNF_MRC;
  91. TxCb->RetryCtl.Mrt = DHCP6_CNF_MRT;
  92. TxCb->RetryCtl.Mrd = DHCP6_CNF_MRD;
  93. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  94. TxCb->RetryCtl.Irt,
  95. TRUE,
  96. TRUE
  97. );
  98. break;
  99. case Dhcp6MsgRenew:
  100. //
  101. // Calculate the retransmission threshold value for renew packet.
  102. //
  103. TxCb->RetryCtl.Irt = DHCP6_REB_IRT;
  104. TxCb->RetryCtl.Mrc = DHCP6_REB_MRC;
  105. TxCb->RetryCtl.Mrt = DHCP6_REB_MRT;
  106. TxCb->RetryCtl.Mrd = IaCb->T2 - IaCb->T1;
  107. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  108. TxCb->RetryCtl.Irt,
  109. TRUE,
  110. TRUE
  111. );
  112. break;
  113. case Dhcp6MsgRebind:
  114. //
  115. // Calculate the retransmission threshold value for rebind packet.
  116. //
  117. TxCb->RetryCtl.Irt = DHCP6_REN_IRT;
  118. TxCb->RetryCtl.Mrc = DHCP6_REN_MRC;
  119. TxCb->RetryCtl.Mrt = DHCP6_REN_MRT;
  120. TxCb->RetryCtl.Mrd = IaCb->AllExpireTime - IaCb->T2;
  121. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  122. TxCb->RetryCtl.Irt,
  123. TRUE,
  124. TRUE
  125. );
  126. break;
  127. case Dhcp6MsgDecline:
  128. //
  129. // Calculate the retransmission threshold value for decline packet.
  130. //
  131. TxCb->RetryCtl.Irt = DHCP6_DEC_IRT;
  132. TxCb->RetryCtl.Mrc = DHCP6_DEC_MRC;
  133. TxCb->RetryCtl.Mrt = DHCP6_DEC_MRT;
  134. TxCb->RetryCtl.Mrd = DHCP6_DEC_MRD;
  135. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  136. TxCb->RetryCtl.Irt,
  137. TRUE,
  138. TRUE
  139. );
  140. break;
  141. case Dhcp6MsgRelease:
  142. //
  143. // Calculate the retransmission threshold value for release packet.
  144. //
  145. TxCb->RetryCtl.Irt = DHCP6_REL_IRT;
  146. TxCb->RetryCtl.Mrc = DHCP6_REL_MRC;
  147. TxCb->RetryCtl.Mrt = DHCP6_REL_MRT;
  148. TxCb->RetryCtl.Mrd = DHCP6_REL_MRD;
  149. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  150. TxCb->RetryCtl.Irt,
  151. TRUE,
  152. TRUE
  153. );
  154. break;
  155. case Dhcp6MsgInfoRequest:
  156. //
  157. // Calculate the retransmission threshold value for info-request packet.
  158. // Use the default value by rfc-3315 if user doesn't configure.
  159. //
  160. if (RetryCtl == NULL) {
  161. TxCb->RetryCtl.Irt = DHCP6_INF_IRT;
  162. TxCb->RetryCtl.Mrc = DHCP6_INF_MRC;
  163. TxCb->RetryCtl.Mrt = DHCP6_INF_MRT;
  164. TxCb->RetryCtl.Mrd = DHCP6_INF_MRD;
  165. } else {
  166. TxCb->RetryCtl.Irt = (RetryCtl->Irt != 0) ? RetryCtl->Irt : DHCP6_INF_IRT;
  167. TxCb->RetryCtl.Mrc = (RetryCtl->Mrc != 0) ? RetryCtl->Mrc : DHCP6_INF_MRC;
  168. TxCb->RetryCtl.Mrt = (RetryCtl->Mrt != 0) ? RetryCtl->Mrt : DHCP6_INF_MRT;
  169. TxCb->RetryCtl.Mrd = (RetryCtl->Mrd != 0) ? RetryCtl->Mrd : DHCP6_INF_MRD;
  170. }
  171. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  172. TxCb->RetryCtl.Irt,
  173. TRUE,
  174. TRUE
  175. );
  176. break;
  177. default:
  178. //
  179. // Unexpected message type.
  180. //
  181. FreePool (TxCb);
  182. return EFI_DEVICE_ERROR;
  183. }
  184. //
  185. // Insert into the retransmit list of the instance.
  186. //
  187. InsertTailList (&Instance->TxList, &TxCb->Link);
  188. return EFI_SUCCESS;
  189. }
  190. /**
  191. Dequeue the packet from retry list if reply received or timeout at last.
  192. @param[in] Instance The pointer to the Dhcp6 instance.
  193. @param[in] PacketXid The packet transaction id to match.
  194. @param[in] NeedSignal If TRUE, then an timeout event need be signaled when it is existed.
  195. Otherwise, this parameter is ignored.
  196. @retval EFI_SUCCESS Successfully dequeued the packet into retry list .
  197. @retval EFI_NOT_FOUND There is no xid matched in retry list.
  198. **/
  199. EFI_STATUS
  200. Dhcp6DequeueRetry (
  201. IN DHCP6_INSTANCE *Instance,
  202. IN UINT32 PacketXid,
  203. IN BOOLEAN NeedSignal
  204. )
  205. {
  206. LIST_ENTRY *Entry;
  207. LIST_ENTRY *NextEntry;
  208. DHCP6_TX_CB *TxCb;
  209. DHCP6_INF_CB *InfCb;
  210. //
  211. // Seek the retransmit node in the retransmit list by packet xid.
  212. //
  213. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
  214. TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
  215. ASSERT (TxCb->TxPacket);
  216. if (TxCb->Xid == PacketXid) {
  217. if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
  218. //
  219. // Seek the info-request node in the info-request list by packet xid.
  220. //
  221. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {
  222. InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);
  223. if (InfCb->Xid == PacketXid) {
  224. //
  225. // Remove the info-request node, and signal the event if timeout.
  226. //
  227. if ((InfCb->TimeoutEvent != NULL) && NeedSignal) {
  228. gBS->SignalEvent (InfCb->TimeoutEvent);
  229. }
  230. RemoveEntryList (&InfCb->Link);
  231. FreePool (InfCb);
  232. }
  233. }
  234. }
  235. //
  236. // Remove the retransmit node.
  237. //
  238. RemoveEntryList (&TxCb->Link);
  239. ASSERT (TxCb->TxPacket);
  240. FreePool (TxCb->TxPacket);
  241. FreePool (TxCb);
  242. return EFI_SUCCESS;
  243. }
  244. }
  245. return EFI_NOT_FOUND;
  246. }
  247. /**
  248. Clean up the specific nodes in the retry list.
  249. @param[in] Instance The pointer to the Dhcp6 instance.
  250. @param[in] Scope The scope of cleanup nodes.
  251. **/
  252. VOID
  253. Dhcp6CleanupRetry (
  254. IN DHCP6_INSTANCE *Instance,
  255. IN UINT32 Scope
  256. )
  257. {
  258. LIST_ENTRY *Entry;
  259. LIST_ENTRY *NextEntry;
  260. DHCP6_TX_CB *TxCb;
  261. DHCP6_INF_CB *InfCb;
  262. //
  263. // Clean up all the stateful messages from the retransmit list.
  264. //
  265. if ((Scope == DHCP6_PACKET_STATEFUL) || (Scope == DHCP6_PACKET_ALL)) {
  266. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
  267. TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
  268. ASSERT (TxCb->TxPacket);
  269. if (TxCb->TxPacket->Dhcp6.Header.MessageType != Dhcp6MsgInfoRequest) {
  270. RemoveEntryList (&TxCb->Link);
  271. FreePool (TxCb->TxPacket);
  272. FreePool (TxCb);
  273. }
  274. }
  275. }
  276. //
  277. // Clean up all the stateless messages from the retransmit list.
  278. //
  279. if ((Scope == DHCP6_PACKET_STATELESS) || (Scope == DHCP6_PACKET_ALL)) {
  280. //
  281. // Clean up all the retransmit list for stateless messages.
  282. //
  283. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
  284. TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
  285. ASSERT (TxCb->TxPacket);
  286. if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
  287. RemoveEntryList (&TxCb->Link);
  288. FreePool (TxCb->TxPacket);
  289. FreePool (TxCb);
  290. }
  291. }
  292. //
  293. // Clean up all the info-request messages list.
  294. //
  295. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->InfList) {
  296. InfCb = NET_LIST_USER_STRUCT (Entry, DHCP6_INF_CB, Link);
  297. if (InfCb->TimeoutEvent != NULL) {
  298. gBS->SignalEvent (InfCb->TimeoutEvent);
  299. }
  300. RemoveEntryList (&InfCb->Link);
  301. FreePool (InfCb);
  302. }
  303. }
  304. }
  305. /**
  306. Check whether the TxCb is still a valid control block in the instance's retry list.
  307. @param[in] Instance The pointer to DHCP6_INSTANCE.
  308. @param[in] TxCb The control block for a transmitted message.
  309. @retval TRUE The control block is in Instance's retry list.
  310. @retval FALSE The control block is NOT in Instance's retry list.
  311. **/
  312. BOOLEAN
  313. Dhcp6IsValidTxCb (
  314. IN DHCP6_INSTANCE *Instance,
  315. IN DHCP6_TX_CB *TxCb
  316. )
  317. {
  318. LIST_ENTRY *Entry;
  319. NET_LIST_FOR_EACH (Entry, &Instance->TxList) {
  320. if (TxCb == NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link)) {
  321. return TRUE;
  322. }
  323. }
  324. return FALSE;
  325. }
  326. /**
  327. Clean up the session of the instance stateful exchange.
  328. @param[in, out] Instance The pointer to the Dhcp6 instance.
  329. @param[in] Status The return status from udp.
  330. **/
  331. VOID
  332. Dhcp6CleanupSession (
  333. IN OUT DHCP6_INSTANCE *Instance,
  334. IN EFI_STATUS Status
  335. )
  336. {
  337. UINTN Index;
  338. EFI_DHCP6_IA *Ia;
  339. ASSERT (Instance->Config);
  340. ASSERT (Instance->IaCb.Ia);
  341. //
  342. // Clean up the retransmit list for stateful messages.
  343. //
  344. Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATEFUL);
  345. if (Instance->Unicast != NULL) {
  346. FreePool (Instance->Unicast);
  347. }
  348. if (Instance->AdSelect != NULL) {
  349. FreePool (Instance->AdSelect);
  350. }
  351. if (Instance->IaCb.Ia->ReplyPacket != NULL) {
  352. FreePool (Instance->IaCb.Ia->ReplyPacket);
  353. }
  354. //
  355. // Reinitialize the Ia fields of the instance.
  356. //
  357. Instance->UdpSts = Status;
  358. Instance->AdSelect = NULL;
  359. Instance->AdPref = 0;
  360. Instance->Unicast = NULL;
  361. Instance->IaCb.T1 = 0;
  362. Instance->IaCb.T2 = 0;
  363. Instance->IaCb.AllExpireTime = 0;
  364. Instance->IaCb.LeaseTime = 0;
  365. //
  366. // Clear start time
  367. //
  368. Instance->StartTime = 0;
  369. Ia = Instance->IaCb.Ia;
  370. Ia->State = Dhcp6Init;
  371. Ia->ReplyPacket = NULL;
  372. //
  373. // Set the addresses as zero lifetime, and then the notify
  374. // function in Ip6Config will remove these timeout address.
  375. //
  376. for (Index = 0; Index < Ia->IaAddressCount; Index++) {
  377. Ia->IaAddress[Index].PreferredLifetime = 0;
  378. Ia->IaAddress[Index].ValidLifetime = 0;
  379. }
  380. //
  381. //
  382. // Signal the Ia information updated event to informal user.
  383. //
  384. if (Instance->Config->IaInfoEvent != NULL) {
  385. gBS->SignalEvent (Instance->Config->IaInfoEvent);
  386. }
  387. }
  388. /**
  389. Callback to user when Dhcp6 transmit/receive occurs.
  390. @param[in] Instance The pointer to the Dhcp6 instance.
  391. @param[in] Event The current Dhcp6 event.
  392. @param[in, out] Packet The pointer to the packet sending or received.
  393. @retval EFI_SUCCESS The user function returns success.
  394. @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
  395. @retval EFI_ABORTED The user function ask it to abort.
  396. **/
  397. EFI_STATUS
  398. EFIAPI
  399. Dhcp6CallbackUser (
  400. IN DHCP6_INSTANCE *Instance,
  401. IN EFI_DHCP6_EVENT Event,
  402. IN OUT EFI_DHCP6_PACKET **Packet
  403. )
  404. {
  405. EFI_STATUS Status;
  406. EFI_DHCP6_PACKET *NewPacket;
  407. EFI_DHCP6_CALLBACK Callback;
  408. VOID *Context;
  409. ASSERT (Packet != NULL);
  410. ASSERT (Instance->Config != NULL);
  411. ASSERT (Instance->IaCb.Ia != NULL);
  412. NewPacket = NULL;
  413. Status = EFI_SUCCESS;
  414. Callback = Instance->Config->Dhcp6Callback;
  415. Context = Instance->Config->CallbackContext;
  416. //
  417. // Callback to user with the new message if has.
  418. //
  419. if (Callback != NULL) {
  420. Status = Callback (
  421. &Instance->Dhcp6,
  422. Context,
  423. Instance->IaCb.Ia->State,
  424. Event,
  425. *Packet,
  426. &NewPacket
  427. );
  428. //
  429. // Updated the new packet from user to replace the original one.
  430. //
  431. if (NewPacket != NULL) {
  432. ASSERT (*Packet != NULL);
  433. FreePool (*Packet);
  434. *Packet = NewPacket;
  435. }
  436. }
  437. return Status;
  438. }
  439. /**
  440. Update Ia according to the new reply message.
  441. @param[in, out] Instance The pointer to the Dhcp6 instance.
  442. @param[in] Packet The pointer to reply messages.
  443. @retval EFI_SUCCESS Updated the Ia information successfully.
  444. @retval EFI_DEVICE_ERROR An unexpected error.
  445. **/
  446. EFI_STATUS
  447. Dhcp6UpdateIaInfo (
  448. IN OUT DHCP6_INSTANCE *Instance,
  449. IN EFI_DHCP6_PACKET *Packet
  450. )
  451. {
  452. EFI_STATUS Status;
  453. UINT8 *Option;
  454. UINT8 *IaInnerOpt;
  455. UINT16 IaInnerLen;
  456. UINT16 StsCode;
  457. UINT32 T1;
  458. UINT32 T2;
  459. ASSERT (Instance->Config != NULL);
  460. //
  461. // If the reply was received in response to a solicit with rapid commit option,
  462. // request, renew or rebind message, the client updates the information it has
  463. // recorded about IAs from the IA options contained in the reply message:
  464. // 1. record the T1 and T2 times
  465. // 2. add any new addresses in the IA
  466. // 3. discard any addresses from the IA, that have a valid lifetime of 0
  467. // 4. update lifetimes for any addresses that already recorded
  468. // 5. leave unchanged any information about addresses
  469. //
  470. // See details in the section-18.1.8 of rfc-3315.
  471. //
  472. Option = Dhcp6SeekIaOption (
  473. Packet->Dhcp6.Option,
  474. Packet->Length - sizeof (EFI_DHCP6_HEADER),
  475. &Instance->Config->IaDescriptor
  476. );
  477. if (Option == NULL) {
  478. return EFI_DEVICE_ERROR;
  479. }
  480. //
  481. // The format of the IA_NA option is:
  482. //
  483. // 0 1 2 3
  484. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  485. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  486. // | OPTION_IA_NA | option-len |
  487. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  488. // | IAID (4 octets) |
  489. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  490. // | T1 |
  491. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  492. // | T2 |
  493. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  494. // | |
  495. // . IA_NA-options .
  496. // . .
  497. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  498. //
  499. // The format of the IA_TA option is:
  500. //
  501. // 0 1 2 3
  502. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  503. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  504. // | OPTION_IA_TA | option-len |
  505. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  506. // | IAID (4 octets) |
  507. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  508. // | |
  509. // . IA_TA-options .
  510. // . .
  511. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  512. //
  513. //
  514. // sizeof (option-code + option-len + IaId) = 8
  515. // sizeof (option-code + option-len + IaId + T1) = 12
  516. // sizeof (option-code + option-len + IaId + T1 + T2) = 16
  517. //
  518. // The inner options still start with 2 bytes option-code and 2 bytes option-len.
  519. //
  520. if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
  521. T1 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 8)));
  522. T2 = NTOHL (ReadUnaligned32 ((UINT32 *)(Option + 12)));
  523. //
  524. // Refer to RFC3155 Chapter 22.4. If a client receives an IA_NA with T1 greater than T2,
  525. // and both T1 and T2 are greater than 0, the client discards the IA_NA option and processes
  526. // the remainder of the message as though the server had not included the invalid IA_NA option.
  527. //
  528. if ((T1 > T2) && (T2 > 0)) {
  529. return EFI_DEVICE_ERROR;
  530. }
  531. IaInnerOpt = Option + 16;
  532. IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 12);
  533. } else {
  534. T1 = 0;
  535. T2 = 0;
  536. IaInnerOpt = Option + 8;
  537. IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 2))) - 4);
  538. }
  539. //
  540. // The format of the Status Code option is:
  541. //
  542. // 0 1 2 3
  543. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  544. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  545. // | OPTION_STATUS_CODE | option-len |
  546. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  547. // | status-code | |
  548. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
  549. // . .
  550. // . status-message .
  551. // . .
  552. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  553. //
  554. //
  555. // sizeof (option-code + option-len) = 4
  556. //
  557. StsCode = Dhcp6StsSuccess;
  558. Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
  559. if (Option != NULL) {
  560. StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));
  561. if (StsCode != Dhcp6StsSuccess) {
  562. return EFI_DEVICE_ERROR;
  563. }
  564. }
  565. //
  566. // Generate control block for the Ia.
  567. //
  568. Status = Dhcp6GenerateIaCb (
  569. Instance,
  570. IaInnerOpt,
  571. IaInnerLen,
  572. T1,
  573. T2
  574. );
  575. return Status;
  576. }
  577. /**
  578. Seek StatusCode Option in package. A Status Code option may appear in the
  579. options field of a DHCP message and/or in the options field of another option.
  580. See details in section 22.13, RFC3315.
  581. @param[in] Instance The pointer to the Dhcp6 instance.
  582. @param[in] Packet The pointer to reply messages.
  583. @param[out] Option The pointer to status code option.
  584. @retval EFI_SUCCESS Seek status code option successfully.
  585. @retval EFI_DEVICE_ERROR An unexpected error.
  586. **/
  587. EFI_STATUS
  588. Dhcp6SeekStsOption (
  589. IN DHCP6_INSTANCE *Instance,
  590. IN EFI_DHCP6_PACKET *Packet,
  591. OUT UINT8 **Option
  592. )
  593. {
  594. UINT8 *IaInnerOpt;
  595. UINT16 IaInnerLen;
  596. UINT16 StsCode;
  597. //
  598. // Seek StatusCode option directly in DHCP message body. That is, search in
  599. // non-encapsulated option fields.
  600. //
  601. *Option = Dhcp6SeekOption (
  602. Packet->Dhcp6.Option,
  603. Packet->Length - 4,
  604. Dhcp6OptStatusCode
  605. );
  606. if (*Option != NULL) {
  607. StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));
  608. if (StsCode != Dhcp6StsSuccess) {
  609. return EFI_DEVICE_ERROR;
  610. }
  611. }
  612. //
  613. // Seek in encapsulated options, IA_NA and IA_TA.
  614. //
  615. *Option = Dhcp6SeekIaOption (
  616. Packet->Dhcp6.Option,
  617. Packet->Length - sizeof (EFI_DHCP6_HEADER),
  618. &Instance->Config->IaDescriptor
  619. );
  620. if (*Option == NULL) {
  621. return EFI_SUCCESS;
  622. }
  623. //
  624. // The format of the IA_NA option is:
  625. //
  626. // 0 1 2 3
  627. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  628. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  629. // | OPTION_IA_NA | option-len |
  630. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  631. // | IAID (4 octets) |
  632. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  633. // | T1 |
  634. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  635. // | T2 |
  636. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  637. // | |
  638. // . IA_NA-options .
  639. // . .
  640. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  641. //
  642. // The format of the IA_TA option is:
  643. //
  644. // 0 1 2 3
  645. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  646. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  647. // | OPTION_IA_TA | option-len |
  648. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  649. // | IAID (4 octets) |
  650. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  651. // | |
  652. // . IA_TA-options .
  653. // . .
  654. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  655. //
  656. //
  657. // sizeof (option-code + option-len + IaId) = 8
  658. // sizeof (option-code + option-len + IaId + T1) = 12
  659. // sizeof (option-code + option-len + IaId + T1 + T2) = 16
  660. //
  661. // The inner options still start with 2 bytes option-code and 2 bytes option-len.
  662. //
  663. if (Instance->Config->IaDescriptor.Type == Dhcp6OptIana) {
  664. IaInnerOpt = *Option + 16;
  665. IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 12);
  666. } else {
  667. IaInnerOpt = *Option + 8;
  668. IaInnerLen = (UINT16)(NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 2))) - 4);
  669. }
  670. //
  671. // The format of the Status Code option is:
  672. //
  673. // 0 1 2 3
  674. // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  675. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  676. // | OPTION_STATUS_CODE | option-len |
  677. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  678. // | status-code | |
  679. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
  680. // . .
  681. // . status-message .
  682. // . .
  683. // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  684. //
  685. //
  686. // sizeof (option-code + option-len) = 4
  687. //
  688. *Option = Dhcp6SeekOption (IaInnerOpt, IaInnerLen, Dhcp6OptStatusCode);
  689. if (*Option != NULL) {
  690. StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(*Option + 4)));
  691. if (StsCode != Dhcp6StsSuccess) {
  692. return EFI_DEVICE_ERROR;
  693. }
  694. }
  695. return EFI_SUCCESS;
  696. }
  697. /**
  698. Transmit Dhcp6 message by udpio.
  699. @param[in] Instance The pointer to the Dhcp6 instance.
  700. @param[in] Packet The pointer to transmit message.
  701. @param[in] Elapsed The pointer to the elapsed time value to fill in.
  702. @retval EFI_SUCCESS Successfully transmitted the packet.
  703. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  704. @retval Others Failed to transmit the packet.
  705. **/
  706. EFI_STATUS
  707. Dhcp6TransmitPacket (
  708. IN DHCP6_INSTANCE *Instance,
  709. IN EFI_DHCP6_PACKET *Packet,
  710. IN UINT16 *Elapsed
  711. )
  712. {
  713. EFI_STATUS Status;
  714. NET_BUF *Wrap;
  715. NET_FRAGMENT Frag;
  716. UDP_END_POINT EndPt;
  717. DHCP6_SERVICE *Service;
  718. Service = Instance->Service;
  719. //
  720. // Wrap it into a netbuf then send it.
  721. //
  722. Frag.Bulk = (UINT8 *)&Packet->Dhcp6.Header;
  723. Frag.Len = Packet->Length;
  724. //
  725. // Do not register free packet here, which will be handled in retry list.
  726. //
  727. Wrap = NetbufFromExt (&Frag, 1, 0, 0, Dhcp6DummyExtFree, NULL);
  728. if (Wrap == NULL) {
  729. return EFI_OUT_OF_RESOURCES;
  730. }
  731. //
  732. // Multicast the Dhcp6 message, unless get the unicast server address by option.
  733. //
  734. ZeroMem (&EndPt, sizeof (UDP_END_POINT));
  735. if (Instance->Unicast != NULL) {
  736. CopyMem (
  737. &EndPt.RemoteAddr,
  738. Instance->Unicast,
  739. sizeof (EFI_IPv6_ADDRESS)
  740. );
  741. } else {
  742. CopyMem (
  743. &EndPt.RemoteAddr,
  744. &mAllDhcpRelayAndServersAddress,
  745. sizeof (EFI_IPv6_ADDRESS)
  746. );
  747. }
  748. EndPt.RemotePort = DHCP6_PORT_SERVER;
  749. EndPt.LocalPort = DHCP6_PORT_CLIENT;
  750. //
  751. // Update the elapsed time value.
  752. //
  753. if (Elapsed != NULL) {
  754. SetElapsedTime (Elapsed, Instance);
  755. }
  756. //
  757. // Send out the message by the configured Udp6Io.
  758. //
  759. Status = UdpIoSendDatagram (
  760. Service->UdpIo,
  761. Wrap,
  762. &EndPt,
  763. NULL,
  764. Dhcp6OnTransmitted,
  765. NULL
  766. );
  767. if (EFI_ERROR (Status)) {
  768. NetbufFree (Wrap);
  769. return Status;
  770. }
  771. return EFI_SUCCESS;
  772. }
  773. /**
  774. Create the solicit message and send it.
  775. @param[in] Instance The pointer to the Dhcp6 instance.
  776. @retval EFI_SUCCESS Created and sent the solicit message successfully.
  777. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  778. @retval Others Failed to send the solicit message.
  779. **/
  780. EFI_STATUS
  781. Dhcp6SendSolicitMsg (
  782. IN DHCP6_INSTANCE *Instance
  783. )
  784. {
  785. EFI_STATUS Status;
  786. EFI_DHCP6_PACKET *Packet;
  787. EFI_DHCP6_PACKET_OPTION *UserOpt;
  788. EFI_DHCP6_DUID *ClientId;
  789. DHCP6_SERVICE *Service;
  790. UINT8 *Cursor;
  791. UINT16 *Elapsed;
  792. UINT32 UserLen;
  793. UINTN Index;
  794. UINT16 Length;
  795. Service = Instance->Service;
  796. ClientId = Service->ClientId;
  797. UserLen = 0;
  798. ASSERT (Service->ClientId != NULL);
  799. ASSERT (Instance->Config != NULL);
  800. ASSERT (Instance->IaCb.Ia != NULL);
  801. //
  802. // Calculate the added length of customized option list.
  803. //
  804. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  805. UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
  806. }
  807. //
  808. // Create the Dhcp6 packet and initialize common fields.
  809. //
  810. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
  811. if (Packet == NULL) {
  812. return EFI_OUT_OF_RESOURCES;
  813. }
  814. Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
  815. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  816. Packet->Dhcp6.Header.MessageType = Dhcp6MsgSolicit;
  817. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  818. //
  819. // Assembly Dhcp6 options for solicit message.
  820. //
  821. Cursor = Packet->Dhcp6.Option;
  822. Length = HTONS (ClientId->Length);
  823. Cursor = Dhcp6AppendOption (
  824. Cursor,
  825. HTONS (Dhcp6OptClientId),
  826. Length,
  827. ClientId->Duid
  828. );
  829. Cursor = Dhcp6AppendETOption (
  830. Cursor,
  831. Instance,
  832. &Elapsed
  833. );
  834. Cursor = Dhcp6AppendIaOption (
  835. Cursor,
  836. Instance->IaCb.Ia,
  837. Instance->IaCb.T1,
  838. Instance->IaCb.T2,
  839. Packet->Dhcp6.Header.MessageType
  840. );
  841. //
  842. // Append user-defined when configurate Dhcp6 service.
  843. //
  844. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  845. UserOpt = Instance->Config->OptionList[Index];
  846. Cursor = Dhcp6AppendOption (
  847. Cursor,
  848. UserOpt->OpCode,
  849. UserOpt->OpLen,
  850. UserOpt->Data
  851. );
  852. }
  853. //
  854. // Determine the size/length of packet.
  855. //
  856. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  857. ASSERT (Packet->Size > Packet->Length + 8);
  858. //
  859. // Callback to user with the packet to be sent and check the user's feedback.
  860. //
  861. Status = Dhcp6CallbackUser (Instance, Dhcp6SendSolicit, &Packet);
  862. if (EFI_ERROR (Status)) {
  863. FreePool (Packet);
  864. return Status;
  865. }
  866. //
  867. // Send solicit packet with the state transition from Dhcp6init to
  868. // Dhcp6selecting.
  869. //
  870. Instance->IaCb.Ia->State = Dhcp6Selecting;
  871. //
  872. // Clear initial time for current transaction.
  873. //
  874. Instance->StartTime = 0;
  875. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  876. if (EFI_ERROR (Status)) {
  877. FreePool (Packet);
  878. return Status;
  879. }
  880. //
  881. // Enqueue the sent packet for the retransmission in case reply timeout.
  882. //
  883. return Dhcp6EnqueueRetry (
  884. Instance,
  885. Packet,
  886. Elapsed,
  887. Instance->Config->SolicitRetransmission
  888. );
  889. }
  890. /**
  891. Configure some parameter to initiate SolicitMsg.
  892. @param[in] Instance The pointer to the Dhcp6 instance.
  893. @retval EFI_SUCCESS Created and sent the solicit message successfully.
  894. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  895. @retval Others Failed to send the solicit message.
  896. **/
  897. EFI_STATUS
  898. Dhcp6InitSolicitMsg (
  899. IN DHCP6_INSTANCE *Instance
  900. )
  901. {
  902. Instance->IaCb.T1 = 0;
  903. Instance->IaCb.T2 = 0;
  904. Instance->IaCb.Ia->IaAddressCount = 0;
  905. return Dhcp6SendSolicitMsg (Instance);
  906. }
  907. /**
  908. Create the request message and send it.
  909. @param[in] Instance The pointer to the Dhcp6 instance.
  910. @retval EFI_SUCCESS Created and sent the request message successfully.
  911. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  912. @retval EFI_DEVICE_ERROR An unexpected error.
  913. @retval Others Failed to send the request message.
  914. **/
  915. EFI_STATUS
  916. Dhcp6SendRequestMsg (
  917. IN DHCP6_INSTANCE *Instance
  918. )
  919. {
  920. EFI_STATUS Status;
  921. EFI_DHCP6_PACKET *Packet;
  922. EFI_DHCP6_PACKET_OPTION *UserOpt;
  923. EFI_DHCP6_DUID *ClientId;
  924. EFI_DHCP6_DUID *ServerId;
  925. DHCP6_SERVICE *Service;
  926. UINT8 *Option;
  927. UINT8 *Cursor;
  928. UINT16 *Elapsed;
  929. UINT32 UserLen;
  930. UINTN Index;
  931. UINT16 Length;
  932. ASSERT (Instance->AdSelect != NULL);
  933. ASSERT (Instance->Config != NULL);
  934. ASSERT (Instance->IaCb.Ia != NULL);
  935. ASSERT (Instance->Service != NULL);
  936. Service = Instance->Service;
  937. ClientId = Service->ClientId;
  938. ASSERT (ClientId != NULL);
  939. //
  940. // Get the server Id from the selected advertisement message.
  941. //
  942. Option = Dhcp6SeekOption (
  943. Instance->AdSelect->Dhcp6.Option,
  944. Instance->AdSelect->Length - 4,
  945. Dhcp6OptServerId
  946. );
  947. if (Option == NULL) {
  948. return EFI_DEVICE_ERROR;
  949. }
  950. ServerId = (EFI_DHCP6_DUID *)(Option + 2);
  951. //
  952. // Calculate the added length of customized option list.
  953. //
  954. UserLen = 0;
  955. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  956. UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
  957. }
  958. //
  959. // Create the Dhcp6 packet and initialize common fields.
  960. //
  961. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
  962. if (Packet == NULL) {
  963. return EFI_OUT_OF_RESOURCES;
  964. }
  965. Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
  966. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  967. Packet->Dhcp6.Header.MessageType = Dhcp6MsgRequest;
  968. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  969. //
  970. // Assembly Dhcp6 options for request message.
  971. //
  972. Cursor = Packet->Dhcp6.Option;
  973. Length = HTONS (ClientId->Length);
  974. Cursor = Dhcp6AppendOption (
  975. Cursor,
  976. HTONS (Dhcp6OptClientId),
  977. Length,
  978. ClientId->Duid
  979. );
  980. Cursor = Dhcp6AppendETOption (
  981. Cursor,
  982. Instance,
  983. &Elapsed
  984. );
  985. Cursor = Dhcp6AppendOption (
  986. Cursor,
  987. HTONS (Dhcp6OptServerId),
  988. ServerId->Length,
  989. ServerId->Duid
  990. );
  991. Cursor = Dhcp6AppendIaOption (
  992. Cursor,
  993. Instance->IaCb.Ia,
  994. Instance->IaCb.T1,
  995. Instance->IaCb.T2,
  996. Packet->Dhcp6.Header.MessageType
  997. );
  998. //
  999. // Append user-defined when configurate Dhcp6 service.
  1000. //
  1001. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  1002. UserOpt = Instance->Config->OptionList[Index];
  1003. Cursor = Dhcp6AppendOption (
  1004. Cursor,
  1005. UserOpt->OpCode,
  1006. UserOpt->OpLen,
  1007. UserOpt->Data
  1008. );
  1009. }
  1010. //
  1011. // Determine the size/length of packet.
  1012. //
  1013. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1014. ASSERT (Packet->Size > Packet->Length + 8);
  1015. //
  1016. // Callback to user with the packet to be sent and check the user's feedback.
  1017. //
  1018. Status = Dhcp6CallbackUser (Instance, Dhcp6SendRequest, &Packet);
  1019. if (EFI_ERROR (Status)) {
  1020. FreePool (Packet);
  1021. return Status;
  1022. }
  1023. //
  1024. // Send request packet with the state transition from Dhcp6selecting to
  1025. // Dhcp6requesting.
  1026. //
  1027. Instance->IaCb.Ia->State = Dhcp6Requesting;
  1028. //
  1029. // Clear initial time for current transaction.
  1030. //
  1031. Instance->StartTime = 0;
  1032. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1033. if (EFI_ERROR (Status)) {
  1034. FreePool (Packet);
  1035. return Status;
  1036. }
  1037. //
  1038. // Enqueue the sent packet for the retransmission in case reply timeout.
  1039. //
  1040. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
  1041. }
  1042. /**
  1043. Create the decline message and send it.
  1044. @param[in] Instance The pointer to the Dhcp6 instance.
  1045. @param[in] DecIa The pointer to the decline Ia.
  1046. @retval EFI_SUCCESS Created and sent the decline message successfully.
  1047. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1048. @retval EFI_DEVICE_ERROR An unexpected error.
  1049. @retval Others Failed to send the decline message.
  1050. **/
  1051. EFI_STATUS
  1052. Dhcp6SendDeclineMsg (
  1053. IN DHCP6_INSTANCE *Instance,
  1054. IN EFI_DHCP6_IA *DecIa
  1055. )
  1056. {
  1057. EFI_STATUS Status;
  1058. EFI_DHCP6_PACKET *Packet;
  1059. EFI_DHCP6_PACKET *LastReply;
  1060. EFI_DHCP6_DUID *ClientId;
  1061. EFI_DHCP6_DUID *ServerId;
  1062. DHCP6_SERVICE *Service;
  1063. UINT8 *Option;
  1064. UINT8 *Cursor;
  1065. UINT16 *Elapsed;
  1066. UINT16 Length;
  1067. ASSERT (Instance->Config != NULL);
  1068. ASSERT (Instance->IaCb.Ia != NULL);
  1069. ASSERT (Instance->Service != NULL);
  1070. Service = Instance->Service;
  1071. ClientId = Service->ClientId;
  1072. LastReply = Instance->IaCb.Ia->ReplyPacket;
  1073. ASSERT (ClientId != NULL);
  1074. ASSERT (LastReply != NULL);
  1075. //
  1076. // Get the server Id from the last reply message.
  1077. //
  1078. Option = Dhcp6SeekOption (
  1079. LastReply->Dhcp6.Option,
  1080. LastReply->Length - 4,
  1081. Dhcp6OptServerId
  1082. );
  1083. if (Option == NULL) {
  1084. return EFI_DEVICE_ERROR;
  1085. }
  1086. //
  1087. // EFI_DHCP6_DUID contains a length field of 2 bytes.
  1088. //
  1089. ServerId = (EFI_DHCP6_DUID *)(Option + 2);
  1090. //
  1091. // Create the Dhcp6 packet and initialize common fields.
  1092. //
  1093. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);
  1094. if (Packet == NULL) {
  1095. return EFI_OUT_OF_RESOURCES;
  1096. }
  1097. Packet->Size = DHCP6_BASE_PACKET_SIZE;
  1098. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  1099. Packet->Dhcp6.Header.MessageType = Dhcp6MsgDecline;
  1100. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  1101. //
  1102. // Assembly Dhcp6 options for rebind/renew message.
  1103. //
  1104. Cursor = Packet->Dhcp6.Option;
  1105. Length = HTONS (ClientId->Length);
  1106. Cursor = Dhcp6AppendOption (
  1107. Cursor,
  1108. HTONS (Dhcp6OptClientId),
  1109. Length,
  1110. ClientId->Duid
  1111. );
  1112. Cursor = Dhcp6AppendETOption (
  1113. Cursor,
  1114. Instance,
  1115. &Elapsed
  1116. );
  1117. Cursor = Dhcp6AppendOption (
  1118. Cursor,
  1119. HTONS (Dhcp6OptServerId),
  1120. ServerId->Length,
  1121. ServerId->Duid
  1122. );
  1123. Cursor = Dhcp6AppendIaOption (Cursor, DecIa, 0, 0, Packet->Dhcp6.Header.MessageType);
  1124. //
  1125. // Determine the size/length of packet.
  1126. //
  1127. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1128. ASSERT (Packet->Size > Packet->Length + 8);
  1129. //
  1130. // Callback to user with the packet to be sent and check the user's feedback.
  1131. //
  1132. Status = Dhcp6CallbackUser (Instance, Dhcp6SendDecline, &Packet);
  1133. if (EFI_ERROR (Status)) {
  1134. FreePool (Packet);
  1135. return Status;
  1136. }
  1137. //
  1138. // Send decline packet with the state transition from Dhcp6bound to
  1139. // Dhcp6declining.
  1140. //
  1141. Instance->IaCb.Ia->State = Dhcp6Declining;
  1142. //
  1143. // Clear initial time for current transaction.
  1144. //
  1145. Instance->StartTime = 0;
  1146. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1147. if (EFI_ERROR (Status)) {
  1148. FreePool (Packet);
  1149. return Status;
  1150. }
  1151. //
  1152. // Enqueue the sent packet for the retransmission in case reply timeout.
  1153. //
  1154. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
  1155. }
  1156. /**
  1157. Create the release message and send it.
  1158. @param[in] Instance The pointer to the Dhcp6 instance.
  1159. @param[in] RelIa The pointer to the release Ia.
  1160. @retval EFI_SUCCESS Created and sent the release message successfully.
  1161. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1162. @retval EFI_DEVICE_ERROR An unexpected error.
  1163. @retval Others Failed to send the release message.
  1164. **/
  1165. EFI_STATUS
  1166. Dhcp6SendReleaseMsg (
  1167. IN DHCP6_INSTANCE *Instance,
  1168. IN EFI_DHCP6_IA *RelIa
  1169. )
  1170. {
  1171. EFI_STATUS Status;
  1172. EFI_DHCP6_PACKET *Packet;
  1173. EFI_DHCP6_PACKET *LastReply;
  1174. EFI_DHCP6_DUID *ClientId;
  1175. EFI_DHCP6_DUID *ServerId;
  1176. DHCP6_SERVICE *Service;
  1177. UINT8 *Option;
  1178. UINT8 *Cursor;
  1179. UINT16 *Elapsed;
  1180. UINT16 Length;
  1181. ASSERT (Instance->Config);
  1182. ASSERT (Instance->IaCb.Ia);
  1183. Service = Instance->Service;
  1184. ClientId = Service->ClientId;
  1185. LastReply = Instance->IaCb.Ia->ReplyPacket;
  1186. ASSERT (ClientId);
  1187. ASSERT (LastReply);
  1188. //
  1189. // Get the server Id from the last reply message.
  1190. //
  1191. Option = Dhcp6SeekOption (
  1192. LastReply->Dhcp6.Option,
  1193. LastReply->Length - 4,
  1194. Dhcp6OptServerId
  1195. );
  1196. if (Option == NULL) {
  1197. return EFI_DEVICE_ERROR;
  1198. }
  1199. ServerId = (EFI_DHCP6_DUID *)(Option + 2);
  1200. //
  1201. // Create the Dhcp6 packet and initialize common fields.
  1202. //
  1203. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE);
  1204. if (Packet == NULL) {
  1205. return EFI_OUT_OF_RESOURCES;
  1206. }
  1207. Packet->Size = DHCP6_BASE_PACKET_SIZE;
  1208. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  1209. Packet->Dhcp6.Header.MessageType = Dhcp6MsgRelease;
  1210. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  1211. //
  1212. // Assembly Dhcp6 options for rebind/renew message
  1213. //
  1214. Cursor = Packet->Dhcp6.Option;
  1215. Length = HTONS (ClientId->Length);
  1216. Cursor = Dhcp6AppendOption (
  1217. Cursor,
  1218. HTONS (Dhcp6OptClientId),
  1219. Length,
  1220. ClientId->Duid
  1221. );
  1222. //
  1223. // ServerId is extracted from packet, it's network order.
  1224. //
  1225. Cursor = Dhcp6AppendOption (
  1226. Cursor,
  1227. HTONS (Dhcp6OptServerId),
  1228. ServerId->Length,
  1229. ServerId->Duid
  1230. );
  1231. Cursor = Dhcp6AppendETOption (
  1232. Cursor,
  1233. Instance,
  1234. &Elapsed
  1235. );
  1236. Cursor = Dhcp6AppendIaOption (Cursor, RelIa, 0, 0, Packet->Dhcp6.Header.MessageType);
  1237. //
  1238. // Determine the size/length of packet
  1239. //
  1240. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1241. ASSERT (Packet->Size > Packet->Length + 8);
  1242. //
  1243. // Callback to user with the packet to be sent and check the user's feedback.
  1244. //
  1245. Status = Dhcp6CallbackUser (Instance, Dhcp6SendRelease, &Packet);
  1246. if (EFI_ERROR (Status)) {
  1247. FreePool (Packet);
  1248. return Status;
  1249. }
  1250. //
  1251. // Send release packet with the state transition from Dhcp6bound to
  1252. // Dhcp6releasing.
  1253. //
  1254. Instance->IaCb.Ia->State = Dhcp6Releasing;
  1255. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1256. if (EFI_ERROR (Status)) {
  1257. FreePool (Packet);
  1258. return Status;
  1259. }
  1260. //
  1261. // Enqueue the sent packet for the retransmission in case reply timeout.
  1262. //
  1263. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
  1264. }
  1265. /**
  1266. Create the renew/rebind message and send it.
  1267. @param[in] Instance The pointer to the Dhcp6 instance.
  1268. @param[in] RebindRequest If TRUE, it is a Rebind type message.
  1269. Otherwise, it is a Renew type message.
  1270. @retval EFI_SUCCESS Created and sent the renew/rebind message successfully.
  1271. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1272. @retval EFI_DEVICE_ERROR An unexpected error.
  1273. @retval Others Failed to send the renew/rebind message.
  1274. **/
  1275. EFI_STATUS
  1276. Dhcp6SendRenewRebindMsg (
  1277. IN DHCP6_INSTANCE *Instance,
  1278. IN BOOLEAN RebindRequest
  1279. )
  1280. {
  1281. EFI_STATUS Status;
  1282. EFI_DHCP6_PACKET *Packet;
  1283. EFI_DHCP6_PACKET *LastReply;
  1284. EFI_DHCP6_PACKET_OPTION *UserOpt;
  1285. EFI_DHCP6_DUID *ClientId;
  1286. EFI_DHCP6_DUID *ServerId;
  1287. EFI_DHCP6_STATE State;
  1288. EFI_DHCP6_EVENT Event;
  1289. DHCP6_SERVICE *Service;
  1290. UINT8 *Option;
  1291. UINT8 *Cursor;
  1292. UINT16 *Elapsed;
  1293. UINT32 UserLen;
  1294. UINTN Index;
  1295. UINT16 Length;
  1296. ASSERT (Instance->Config);
  1297. ASSERT (Instance->IaCb.Ia);
  1298. Service = Instance->Service;
  1299. ClientId = Service->ClientId;
  1300. ASSERT (ClientId);
  1301. //
  1302. // Calculate the added length of customized option list.
  1303. //
  1304. UserLen = 0;
  1305. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  1306. UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
  1307. }
  1308. //
  1309. // Create the Dhcp6 packet and initialize common fields.
  1310. //
  1311. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
  1312. if (Packet == NULL) {
  1313. return EFI_OUT_OF_RESOURCES;
  1314. }
  1315. Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
  1316. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  1317. Packet->Dhcp6.Header.MessageType = RebindRequest ? Dhcp6MsgRebind : Dhcp6MsgRenew;
  1318. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  1319. //
  1320. // Assembly Dhcp6 options for rebind/renew message.
  1321. //
  1322. Cursor = Packet->Dhcp6.Option;
  1323. Length = HTONS (ClientId->Length);
  1324. Cursor = Dhcp6AppendOption (
  1325. Cursor,
  1326. HTONS (Dhcp6OptClientId),
  1327. Length,
  1328. ClientId->Duid
  1329. );
  1330. Cursor = Dhcp6AppendETOption (
  1331. Cursor,
  1332. Instance,
  1333. &Elapsed
  1334. );
  1335. Cursor = Dhcp6AppendIaOption (
  1336. Cursor,
  1337. Instance->IaCb.Ia,
  1338. Instance->IaCb.T1,
  1339. Instance->IaCb.T2,
  1340. Packet->Dhcp6.Header.MessageType
  1341. );
  1342. if (!RebindRequest) {
  1343. //
  1344. // Get the server Id from the last reply message and
  1345. // insert it for rebind request.
  1346. //
  1347. LastReply = Instance->IaCb.Ia->ReplyPacket;
  1348. ASSERT (LastReply);
  1349. Option = Dhcp6SeekOption (
  1350. LastReply->Dhcp6.Option,
  1351. LastReply->Length - 4,
  1352. Dhcp6OptServerId
  1353. );
  1354. if (Option == NULL) {
  1355. FreePool (Packet);
  1356. return EFI_DEVICE_ERROR;
  1357. }
  1358. ServerId = (EFI_DHCP6_DUID *)(Option + 2);
  1359. Cursor = Dhcp6AppendOption (
  1360. Cursor,
  1361. HTONS (Dhcp6OptServerId),
  1362. ServerId->Length,
  1363. ServerId->Duid
  1364. );
  1365. }
  1366. //
  1367. // Append user-defined when configurate Dhcp6 service.
  1368. //
  1369. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  1370. UserOpt = Instance->Config->OptionList[Index];
  1371. Cursor = Dhcp6AppendOption (
  1372. Cursor,
  1373. UserOpt->OpCode,
  1374. UserOpt->OpLen,
  1375. UserOpt->Data
  1376. );
  1377. }
  1378. //
  1379. // Determine the size/length of packet.
  1380. //
  1381. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1382. ASSERT (Packet->Size > Packet->Length + 8);
  1383. //
  1384. // Callback to user with the packet to be sent and check the user's feedback.
  1385. //
  1386. State = (RebindRequest) ? Dhcp6Rebinding : Dhcp6Renewing;
  1387. Event = (RebindRequest) ? Dhcp6EnterRebinding : Dhcp6EnterRenewing;
  1388. Status = Dhcp6CallbackUser (Instance, Event, &Packet);
  1389. if (EFI_ERROR (Status)) {
  1390. FreePool (Packet);
  1391. return Status;
  1392. }
  1393. //
  1394. // Send renew/rebind packet with the state transition from Dhcp6bound to
  1395. // Dhcp6renew/rebind.
  1396. // And sync the lease time when send renew/rebind, in case that user send
  1397. // renew/rebind actively.
  1398. //
  1399. Instance->IaCb.Ia->State = State;
  1400. Instance->IaCb.LeaseTime = (RebindRequest) ? Instance->IaCb.T2 : Instance->IaCb.T1;
  1401. //
  1402. // Clear initial time for current transaction.
  1403. //
  1404. Instance->StartTime = 0;
  1405. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1406. if (EFI_ERROR (Status)) {
  1407. FreePool (Packet);
  1408. return Status;
  1409. }
  1410. //
  1411. // Enqueue the sent packet for the retransmission in case reply timeout.
  1412. //
  1413. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
  1414. }
  1415. /**
  1416. Start the information request process.
  1417. @param[in] Instance The pointer to the Dhcp6 instance.
  1418. @param[in] SendClientId If TRUE, the client identifier option will be included in
  1419. information request message. Otherwise, the client identifier
  1420. option will not be included.
  1421. @param[in] OptionRequest The pointer to the option request option.
  1422. @param[in] OptionCount The number options in the OptionList.
  1423. @param[in] OptionList The array pointers to the appended options.
  1424. @param[in] Retransmission The pointer to the retransmission control.
  1425. @param[in] TimeoutEvent The event of timeout.
  1426. @param[in] ReplyCallback The callback function when the reply was received.
  1427. @param[in] CallbackContext The pointer to the parameter passed to the callback.
  1428. @retval EFI_SUCCESS Start the info-request process successfully.
  1429. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1430. @retval EFI_NO_MAPPING No source address is available for use.
  1431. @retval Others Failed to start the info-request process.
  1432. **/
  1433. EFI_STATUS
  1434. Dhcp6StartInfoRequest (
  1435. IN DHCP6_INSTANCE *Instance,
  1436. IN BOOLEAN SendClientId,
  1437. IN EFI_DHCP6_PACKET_OPTION *OptionRequest,
  1438. IN UINT32 OptionCount,
  1439. IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL,
  1440. IN EFI_DHCP6_RETRANSMISSION *Retransmission,
  1441. IN EFI_EVENT TimeoutEvent OPTIONAL,
  1442. IN EFI_DHCP6_INFO_CALLBACK ReplyCallback,
  1443. IN VOID *CallbackContext OPTIONAL
  1444. )
  1445. {
  1446. EFI_STATUS Status;
  1447. DHCP6_INF_CB *InfCb;
  1448. DHCP6_SERVICE *Service;
  1449. EFI_TPL OldTpl;
  1450. Service = Instance->Service;
  1451. OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
  1452. Instance->UdpSts = EFI_ALREADY_STARTED;
  1453. //
  1454. // Create and initialize the control block for the info-request.
  1455. //
  1456. InfCb = AllocateZeroPool (sizeof (DHCP6_INF_CB));
  1457. if (InfCb == NULL) {
  1458. gBS->RestoreTPL (OldTpl);
  1459. return EFI_OUT_OF_RESOURCES;
  1460. }
  1461. InfCb->ReplyCallback = ReplyCallback;
  1462. InfCb->CallbackContext = CallbackContext;
  1463. InfCb->TimeoutEvent = TimeoutEvent;
  1464. InsertTailList (&Instance->InfList, &InfCb->Link);
  1465. //
  1466. // Send the info-request message to start exchange process.
  1467. //
  1468. Status = Dhcp6SendInfoRequestMsg (
  1469. Instance,
  1470. InfCb,
  1471. SendClientId,
  1472. OptionRequest,
  1473. OptionCount,
  1474. OptionList,
  1475. Retransmission
  1476. );
  1477. if (EFI_ERROR (Status)) {
  1478. goto ON_ERROR;
  1479. }
  1480. //
  1481. // Register receive callback for the stateless exchange process.
  1482. //
  1483. Status = UdpIoRecvDatagram (
  1484. Service->UdpIo,
  1485. Dhcp6ReceivePacket,
  1486. Service,
  1487. 0
  1488. );
  1489. if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
  1490. goto ON_ERROR;
  1491. }
  1492. gBS->RestoreTPL (OldTpl);
  1493. return EFI_SUCCESS;
  1494. ON_ERROR:
  1495. gBS->RestoreTPL (OldTpl);
  1496. RemoveEntryList (&InfCb->Link);
  1497. FreePool (InfCb);
  1498. return Status;
  1499. }
  1500. /**
  1501. Create the information request message and send it.
  1502. @param[in] Instance The pointer to the Dhcp6 instance.
  1503. @param[in] InfCb The pointer to the information request control block.
  1504. @param[in] SendClientId If TRUE, the client identifier option will be included in
  1505. information request message. Otherwise, the client identifier
  1506. option will not be included.
  1507. @param[in] OptionRequest The pointer to the option request option.
  1508. @param[in] OptionCount The number options in the OptionList.
  1509. @param[in] OptionList The array pointers to the appended options.
  1510. @param[in] Retransmission The pointer to the retransmission control.
  1511. @retval EFI_SUCCESS Created and sent the info-request message successfully.
  1512. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1513. @retval Others Failed to send the info-request message.
  1514. **/
  1515. EFI_STATUS
  1516. Dhcp6SendInfoRequestMsg (
  1517. IN DHCP6_INSTANCE *Instance,
  1518. IN DHCP6_INF_CB *InfCb,
  1519. IN BOOLEAN SendClientId,
  1520. IN EFI_DHCP6_PACKET_OPTION *OptionRequest,
  1521. IN UINT32 OptionCount,
  1522. IN EFI_DHCP6_PACKET_OPTION *OptionList[],
  1523. IN EFI_DHCP6_RETRANSMISSION *Retransmission
  1524. )
  1525. {
  1526. EFI_STATUS Status;
  1527. EFI_DHCP6_PACKET *Packet;
  1528. EFI_DHCP6_PACKET_OPTION *UserOpt;
  1529. EFI_DHCP6_DUID *ClientId;
  1530. DHCP6_SERVICE *Service;
  1531. UINT8 *Cursor;
  1532. UINT16 *Elapsed;
  1533. UINT32 UserLen;
  1534. UINTN Index;
  1535. UINT16 Length;
  1536. ASSERT (OptionRequest);
  1537. Service = Instance->Service;
  1538. ClientId = Service->ClientId;
  1539. UserLen = NTOHS (OptionRequest->OpLen) + 4;
  1540. ASSERT (ClientId);
  1541. //
  1542. // Calculate the added length of customized option list.
  1543. //
  1544. for (Index = 0; Index < OptionCount; Index++) {
  1545. UserLen += (NTOHS (OptionList[Index]->OpLen) + 4);
  1546. }
  1547. //
  1548. // Create the Dhcp6 packet and initialize common fields.
  1549. //
  1550. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
  1551. if (Packet == NULL) {
  1552. return EFI_OUT_OF_RESOURCES;
  1553. }
  1554. Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
  1555. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  1556. Packet->Dhcp6.Header.MessageType = Dhcp6MsgInfoRequest;
  1557. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  1558. InfCb->Xid = Packet->Dhcp6.Header.TransactionId;
  1559. //
  1560. // Assembly Dhcp6 options for info-request message.
  1561. //
  1562. Cursor = Packet->Dhcp6.Option;
  1563. if (SendClientId) {
  1564. Length = HTONS (ClientId->Length);
  1565. Cursor = Dhcp6AppendOption (
  1566. Cursor,
  1567. HTONS (Dhcp6OptClientId),
  1568. Length,
  1569. ClientId->Duid
  1570. );
  1571. }
  1572. Cursor = Dhcp6AppendETOption (
  1573. Cursor,
  1574. Instance,
  1575. &Elapsed
  1576. );
  1577. Cursor = Dhcp6AppendOption (
  1578. Cursor,
  1579. OptionRequest->OpCode,
  1580. OptionRequest->OpLen,
  1581. OptionRequest->Data
  1582. );
  1583. //
  1584. // Append user-defined when configurate Dhcp6 service.
  1585. //
  1586. for (Index = 0; Index < OptionCount; Index++) {
  1587. UserOpt = OptionList[Index];
  1588. Cursor = Dhcp6AppendOption (
  1589. Cursor,
  1590. UserOpt->OpCode,
  1591. UserOpt->OpLen,
  1592. UserOpt->Data
  1593. );
  1594. }
  1595. //
  1596. // Determine the size/length of packet.
  1597. //
  1598. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1599. ASSERT (Packet->Size > Packet->Length + 8);
  1600. //
  1601. // Clear initial time for current transaction.
  1602. //
  1603. Instance->StartTime = 0;
  1604. //
  1605. // Send info-request packet with no state.
  1606. //
  1607. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1608. if (EFI_ERROR (Status)) {
  1609. FreePool (Packet);
  1610. return Status;
  1611. }
  1612. //
  1613. // Enqueue the sent packet for the retransmission in case reply timeout.
  1614. //
  1615. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, Retransmission);
  1616. }
  1617. /**
  1618. Create the Confirm message and send it.
  1619. @param[in] Instance The pointer to the Dhcp6 instance.
  1620. @retval EFI_SUCCESS Created and sent the confirm message successfully.
  1621. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1622. @retval EFI_DEVICE_ERROR An unexpected error.
  1623. @retval Others Failed to send the confirm message.
  1624. **/
  1625. EFI_STATUS
  1626. Dhcp6SendConfirmMsg (
  1627. IN DHCP6_INSTANCE *Instance
  1628. )
  1629. {
  1630. UINT8 *Cursor;
  1631. UINTN Index;
  1632. UINT16 Length;
  1633. UINT32 UserLen;
  1634. EFI_STATUS Status;
  1635. DHCP6_SERVICE *Service;
  1636. EFI_DHCP6_DUID *ClientId;
  1637. EFI_DHCP6_PACKET *Packet;
  1638. EFI_DHCP6_PACKET_OPTION *UserOpt;
  1639. UINT16 *Elapsed;
  1640. ASSERT (Instance->Config != NULL);
  1641. ASSERT (Instance->IaCb.Ia != NULL);
  1642. ASSERT (Instance->Service != NULL);
  1643. Service = Instance->Service;
  1644. ClientId = Service->ClientId;
  1645. ASSERT (ClientId != NULL);
  1646. //
  1647. // Calculate the added length of customized option list.
  1648. //
  1649. UserLen = 0;
  1650. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  1651. UserLen += (NTOHS (Instance->Config->OptionList[Index]->OpLen) + 4);
  1652. }
  1653. //
  1654. // Create the Dhcp6 packet and initialize common fields.
  1655. //
  1656. Packet = AllocateZeroPool (DHCP6_BASE_PACKET_SIZE + UserLen);
  1657. if (Packet == NULL) {
  1658. return EFI_OUT_OF_RESOURCES;
  1659. }
  1660. Packet->Size = DHCP6_BASE_PACKET_SIZE + UserLen;
  1661. Packet->Length = sizeof (EFI_DHCP6_HEADER);
  1662. Packet->Dhcp6.Header.MessageType = Dhcp6MsgConfirm;
  1663. Packet->Dhcp6.Header.TransactionId = Service->Xid++;
  1664. //
  1665. // Assembly Dhcp6 options for solicit message.
  1666. //
  1667. Cursor = Packet->Dhcp6.Option;
  1668. Length = HTONS (ClientId->Length);
  1669. Cursor = Dhcp6AppendOption (
  1670. Cursor,
  1671. HTONS (Dhcp6OptClientId),
  1672. Length,
  1673. ClientId->Duid
  1674. );
  1675. Cursor = Dhcp6AppendETOption (
  1676. Cursor,
  1677. Instance,
  1678. &Elapsed
  1679. );
  1680. Cursor = Dhcp6AppendIaOption (
  1681. Cursor,
  1682. Instance->IaCb.Ia,
  1683. Instance->IaCb.T1,
  1684. Instance->IaCb.T2,
  1685. Packet->Dhcp6.Header.MessageType
  1686. );
  1687. //
  1688. // Append user-defined when configurate Dhcp6 service.
  1689. //
  1690. for (Index = 0; Index < Instance->Config->OptionCount; Index++) {
  1691. UserOpt = Instance->Config->OptionList[Index];
  1692. Cursor = Dhcp6AppendOption (
  1693. Cursor,
  1694. UserOpt->OpCode,
  1695. UserOpt->OpLen,
  1696. UserOpt->Data
  1697. );
  1698. }
  1699. //
  1700. // Determine the size/length of packet.
  1701. //
  1702. Packet->Length += (UINT32)(Cursor - Packet->Dhcp6.Option);
  1703. ASSERT (Packet->Size > Packet->Length + 8);
  1704. //
  1705. // Callback to user with the packet to be sent and check the user's feedback.
  1706. //
  1707. Status = Dhcp6CallbackUser (Instance, Dhcp6SendConfirm, &Packet);
  1708. if (EFI_ERROR (Status)) {
  1709. FreePool (Packet);
  1710. return Status;
  1711. }
  1712. //
  1713. // Send confirm packet with the state transition from Dhcp6Bound to
  1714. // Dhcp6Confirming.
  1715. //
  1716. Instance->IaCb.Ia->State = Dhcp6Confirming;
  1717. //
  1718. // Clear initial time for current transaction.
  1719. //
  1720. Instance->StartTime = 0;
  1721. Status = Dhcp6TransmitPacket (Instance, Packet, Elapsed);
  1722. if (EFI_ERROR (Status)) {
  1723. FreePool (Packet);
  1724. return Status;
  1725. }
  1726. //
  1727. // Enqueue the sent packet for the retransmission in case reply timeout.
  1728. //
  1729. return Dhcp6EnqueueRetry (Instance, Packet, Elapsed, NULL);
  1730. }
  1731. /**
  1732. Handle with the Dhcp6 reply message.
  1733. @param[in] Instance The pointer to Dhcp6 instance.
  1734. @param[in] Packet The pointer to the Dhcp6 reply message.
  1735. @retval EFI_SUCCESS Processed the reply message successfully.
  1736. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1737. @retval EFI_DEVICE_ERROR An unexpected error.
  1738. @retval Others Failed to process the reply message.
  1739. **/
  1740. EFI_STATUS
  1741. Dhcp6HandleReplyMsg (
  1742. IN DHCP6_INSTANCE *Instance,
  1743. IN EFI_DHCP6_PACKET *Packet
  1744. )
  1745. {
  1746. EFI_STATUS Status;
  1747. UINT8 *Option;
  1748. UINT16 StsCode;
  1749. ASSERT (Instance->Config != NULL);
  1750. ASSERT (Instance->IaCb.Ia != NULL);
  1751. ASSERT (Packet != NULL);
  1752. Status = EFI_SUCCESS;
  1753. if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
  1754. return EFI_DEVICE_ERROR;
  1755. }
  1756. //
  1757. // If the client subsequently receives a valid reply message that includes a
  1758. // rapid commit option since send a solicit with rapid commit option before,
  1759. // preocess the reply message and discard any reply messages received in
  1760. // response to the request message.
  1761. // See details in the section-17.1.4 of rfc-3315.
  1762. //
  1763. Option = Dhcp6SeekOption (
  1764. Packet->Dhcp6.Option,
  1765. Packet->Length - 4,
  1766. Dhcp6OptRapidCommit
  1767. );
  1768. if (((Option != NULL) && !Instance->Config->RapidCommit) || ((Option == NULL) && Instance->Config->RapidCommit)) {
  1769. return EFI_DEVICE_ERROR;
  1770. }
  1771. //
  1772. // As to a valid reply packet in response to a request/renew/rebind packet,
  1773. // ignore the packet if not contains the Ia option
  1774. //
  1775. if ((Instance->IaCb.Ia->State == Dhcp6Requesting) ||
  1776. (Instance->IaCb.Ia->State == Dhcp6Renewing) ||
  1777. (Instance->IaCb.Ia->State == Dhcp6Rebinding)
  1778. )
  1779. {
  1780. Option = Dhcp6SeekIaOption (
  1781. Packet->Dhcp6.Option,
  1782. Packet->Length,
  1783. &Instance->Config->IaDescriptor
  1784. );
  1785. if (Option == NULL) {
  1786. return EFI_SUCCESS;
  1787. }
  1788. }
  1789. //
  1790. // Callback to user with the received packet and check the user's feedback.
  1791. //
  1792. Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdReply, &Packet);
  1793. if (EFI_ERROR (Status)) {
  1794. return Status;
  1795. }
  1796. //
  1797. // When receive a valid reply packet in response to a decline/release packet,
  1798. // the client considers the decline/release event completed regardless of the
  1799. // status code.
  1800. //
  1801. if ((Instance->IaCb.Ia->State == Dhcp6Declining) || (Instance->IaCb.Ia->State == Dhcp6Releasing)) {
  1802. if (Instance->IaCb.Ia->IaAddressCount != 0) {
  1803. Instance->IaCb.Ia->State = Dhcp6Bound;
  1804. } else {
  1805. ASSERT (Instance->IaCb.Ia->ReplyPacket);
  1806. FreePool (Instance->IaCb.Ia->ReplyPacket);
  1807. Instance->IaCb.Ia->ReplyPacket = NULL;
  1808. Instance->IaCb.Ia->State = Dhcp6Init;
  1809. }
  1810. //
  1811. // For sync, set the success flag out of polling in decline/release.
  1812. //
  1813. Instance->UdpSts = EFI_SUCCESS;
  1814. //
  1815. // For async, signal the Ia event to inform Ia information update.
  1816. //
  1817. if (Instance->Config->IaInfoEvent != NULL) {
  1818. gBS->SignalEvent (Instance->Config->IaInfoEvent);
  1819. }
  1820. //
  1821. // Reset start time for next exchange.
  1822. //
  1823. Instance->StartTime = 0;
  1824. Status = EFI_SUCCESS;
  1825. goto ON_EXIT;
  1826. }
  1827. //
  1828. // Upon the receipt of a valid reply packet in response to a solicit, request,
  1829. // confirm, renew and rebind, the behavior depends on the status code option.
  1830. // See the details in the section-18.1.8 of rfc-3315.
  1831. //
  1832. Option = NULL;
  1833. Status = Dhcp6SeekStsOption (
  1834. Instance,
  1835. Packet,
  1836. &Option
  1837. );
  1838. if (!EFI_ERROR (Status)) {
  1839. //
  1840. // No status code or no error status code means succeed to reply.
  1841. //
  1842. Status = Dhcp6UpdateIaInfo (Instance, Packet);
  1843. if (!EFI_ERROR (Status)) {
  1844. //
  1845. // Reset start time for next exchange.
  1846. //
  1847. Instance->StartTime = 0;
  1848. //
  1849. // Set bound state and store the reply packet.
  1850. //
  1851. if (Instance->IaCb.Ia->ReplyPacket != NULL) {
  1852. FreePool (Instance->IaCb.Ia->ReplyPacket);
  1853. }
  1854. Instance->IaCb.Ia->ReplyPacket = AllocateZeroPool (Packet->Size);
  1855. if (Instance->IaCb.Ia->ReplyPacket == NULL) {
  1856. Status = EFI_OUT_OF_RESOURCES;
  1857. goto ON_EXIT;
  1858. }
  1859. CopyMem (Instance->IaCb.Ia->ReplyPacket, Packet, Packet->Size);
  1860. Instance->IaCb.Ia->State = Dhcp6Bound;
  1861. //
  1862. // For sync, set the success flag out of polling in start/renewrebind.
  1863. //
  1864. Instance->UdpSts = EFI_SUCCESS;
  1865. //
  1866. // Maybe this is a new round DHCP process due to some reason, such as NotOnLink
  1867. // ReplyMsg for ConfirmMsg should trigger new round to acquire new address. In that
  1868. // case, clear old address.ValidLifetime and append to new address. Therefore, DHCP
  1869. // consumers can be notified to flush old address.
  1870. //
  1871. Dhcp6AppendCacheIa (Instance);
  1872. //
  1873. // For async, signal the Ia event to inform Ia information update.
  1874. //
  1875. if (Instance->Config->IaInfoEvent != NULL) {
  1876. gBS->SignalEvent (Instance->Config->IaInfoEvent);
  1877. }
  1878. } else if (Status == EFI_NOT_FOUND) {
  1879. //
  1880. // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message,
  1881. // the client sends a Renew or Rebind if the IA is not in the Reply message.
  1882. // Return EFI_SUCCESS so we can continue to restart the Renew/Rebind process.
  1883. //
  1884. return EFI_SUCCESS;
  1885. }
  1886. goto ON_EXIT;
  1887. } else if (Option != NULL) {
  1888. //
  1889. // Any error status code option is found.
  1890. //
  1891. StsCode = NTOHS (ReadUnaligned16 ((UINT16 *)(Option + 4)));
  1892. switch (StsCode) {
  1893. case Dhcp6StsUnspecFail:
  1894. //
  1895. // It indicates the server is unable to process the message due to an
  1896. // unspecified failure condition, so just retry if possible.
  1897. //
  1898. break;
  1899. case Dhcp6StsUseMulticast:
  1900. //
  1901. // It indicates the server receives a message via unicast from a client
  1902. // to which the server has not sent a unicast option, so retry it by
  1903. // multi-cast address.
  1904. //
  1905. if (Instance->Unicast != NULL) {
  1906. FreePool (Instance->Unicast);
  1907. Instance->Unicast = NULL;
  1908. }
  1909. break;
  1910. case Dhcp6StsNotOnLink:
  1911. if (Instance->IaCb.Ia->State == Dhcp6Confirming) {
  1912. //
  1913. // Before initiate new round DHCP, cache the current IA.
  1914. //
  1915. Status = Dhcp6CacheIa (Instance);
  1916. if (EFI_ERROR (Status)) {
  1917. return Status;
  1918. }
  1919. //
  1920. // Restart S.A.R.R process to acquire new address.
  1921. //
  1922. Status = Dhcp6InitSolicitMsg (Instance);
  1923. if (EFI_ERROR (Status)) {
  1924. return Status;
  1925. }
  1926. }
  1927. break;
  1928. case Dhcp6StsNoBinding:
  1929. if ((Instance->IaCb.Ia->State == Dhcp6Renewing) || (Instance->IaCb.Ia->State == Dhcp6Rebinding)) {
  1930. //
  1931. // Refer to RFC3315 Chapter 18.1.8, for each IA in the original Renew or Rebind message, the client
  1932. // sends a Request message if the IA contained a Status Code option with the NoBinding status.
  1933. //
  1934. Status = Dhcp6SendRequestMsg (Instance);
  1935. if (EFI_ERROR (Status)) {
  1936. return Status;
  1937. }
  1938. }
  1939. break;
  1940. default:
  1941. //
  1942. // The other status code, just restart solicitation.
  1943. //
  1944. break;
  1945. }
  1946. }
  1947. return EFI_SUCCESS;
  1948. ON_EXIT:
  1949. if (!EFI_ERROR (Status)) {
  1950. Status = Dhcp6DequeueRetry (
  1951. Instance,
  1952. Packet->Dhcp6.Header.TransactionId,
  1953. FALSE
  1954. );
  1955. }
  1956. return Status;
  1957. }
  1958. /**
  1959. Select the appointed Dhcp6 advertisement message.
  1960. @param[in] Instance The pointer to the Dhcp6 instance.
  1961. @param[in] AdSelect The pointer to the selected Dhcp6 advertisement message.
  1962. @retval EFI_SUCCESS Selected the right advertisement message successfully.
  1963. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  1964. @retval Others Failed to select the advertise message.
  1965. **/
  1966. EFI_STATUS
  1967. Dhcp6SelectAdvertiseMsg (
  1968. IN DHCP6_INSTANCE *Instance,
  1969. IN EFI_DHCP6_PACKET *AdSelect
  1970. )
  1971. {
  1972. EFI_STATUS Status;
  1973. UINT8 *Option;
  1974. ASSERT (AdSelect != NULL);
  1975. //
  1976. // Callback to user with the selected advertisement packet, and the user
  1977. // might overwrite it.
  1978. //
  1979. Status = Dhcp6CallbackUser (Instance, Dhcp6SelectAdvertise, &AdSelect);
  1980. if (EFI_ERROR (Status)) {
  1981. return Status;
  1982. }
  1983. Instance->AdSelect = AdSelect;
  1984. //
  1985. // Dequeue the sent packet for the retransmission since advertisement selected.
  1986. //
  1987. Status = Dhcp6DequeueRetry (
  1988. Instance,
  1989. AdSelect->Dhcp6.Header.TransactionId,
  1990. FALSE
  1991. );
  1992. if (EFI_ERROR (Status)) {
  1993. return Status;
  1994. }
  1995. //
  1996. // Check whether there is server unicast option in the selected advertise
  1997. // packet, and update it.
  1998. //
  1999. Option = Dhcp6SeekOption (
  2000. AdSelect->Dhcp6.Option,
  2001. AdSelect->Length - 4,
  2002. Dhcp6OptServerUnicast
  2003. );
  2004. if (Option != NULL) {
  2005. Instance->Unicast = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
  2006. if (Instance->Unicast == NULL) {
  2007. return EFI_OUT_OF_RESOURCES;
  2008. }
  2009. CopyMem (Instance->Unicast, Option + 4, sizeof (EFI_IPv6_ADDRESS));
  2010. }
  2011. //
  2012. // Update the information of the Ia by the selected advertisement message.
  2013. //
  2014. Status = Dhcp6UpdateIaInfo (Instance, AdSelect);
  2015. if (EFI_ERROR (Status)) {
  2016. return Status;
  2017. }
  2018. //
  2019. // Send the request message to continue the S.A.R.R. process.
  2020. //
  2021. return Dhcp6SendRequestMsg (Instance);
  2022. }
  2023. /**
  2024. Handle with the Dhcp6 advertisement message.
  2025. @param[in] Instance The pointer to the Dhcp6 instance.
  2026. @param[in] Packet The pointer to the Dhcp6 advertisement message.
  2027. @retval EFI_SUCCESS Processed the advertisement message successfully.
  2028. @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
  2029. @retval EFI_DEVICE_ERROR An unexpected error.
  2030. @retval Others Failed to process the advertise message.
  2031. **/
  2032. EFI_STATUS
  2033. Dhcp6HandleAdvertiseMsg (
  2034. IN DHCP6_INSTANCE *Instance,
  2035. IN EFI_DHCP6_PACKET *Packet
  2036. )
  2037. {
  2038. EFI_STATUS Status;
  2039. UINT8 *Option;
  2040. BOOLEAN Timeout;
  2041. ASSERT (Instance->Config);
  2042. ASSERT (Instance->IaCb.Ia);
  2043. Timeout = FALSE;
  2044. //
  2045. // If the client does receives a valid reply message that includes a rapid
  2046. // commit option since a solicit with rapid commit option sent before, select
  2047. // this reply message. Or else, process the advertise messages as normal.
  2048. // See details in the section-17.1.4 of rfc-3315.
  2049. //
  2050. Option = Dhcp6SeekOption (
  2051. Packet->Dhcp6.Option,
  2052. Packet->Length - 4,
  2053. Dhcp6OptRapidCommit
  2054. );
  2055. if ((Option != NULL) && Instance->Config->RapidCommit && (Packet->Dhcp6.Header.MessageType == Dhcp6MsgReply)) {
  2056. return Dhcp6HandleReplyMsg (Instance, Packet);
  2057. }
  2058. if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) {
  2059. return EFI_DEVICE_ERROR;
  2060. }
  2061. //
  2062. // Client must ignore any advertise message that includes a status code option
  2063. // containing the value noaddrsavail, with the exception that the client may
  2064. // display the associated status message to the user.
  2065. // See the details in the section-17.1.3 of rfc-3315.
  2066. //
  2067. Status = Dhcp6SeekStsOption (
  2068. Instance,
  2069. Packet,
  2070. &Option
  2071. );
  2072. if (EFI_ERROR (Status)) {
  2073. return EFI_DEVICE_ERROR;
  2074. }
  2075. //
  2076. // Callback to user with the received packet and check the user's feedback.
  2077. //
  2078. Status = Dhcp6CallbackUser (Instance, Dhcp6RcvdAdvertise, &Packet);
  2079. if (!EFI_ERROR (Status)) {
  2080. //
  2081. // Success means user choose the current advertisement packet.
  2082. //
  2083. if (Instance->AdSelect != NULL) {
  2084. FreePool (Instance->AdSelect);
  2085. }
  2086. //
  2087. // Store the selected advertisement packet and set a flag.
  2088. //
  2089. Instance->AdSelect = AllocateZeroPool (Packet->Size);
  2090. if (Instance->AdSelect == NULL) {
  2091. return EFI_OUT_OF_RESOURCES;
  2092. }
  2093. CopyMem (Instance->AdSelect, Packet, Packet->Size);
  2094. Instance->AdPref = 0xff;
  2095. } else if (Status == EFI_NOT_READY) {
  2096. //
  2097. // Not_ready means user wants to continue to receive more advertise packets.
  2098. //
  2099. if ((Instance->AdPref == 0xff) && (Instance->AdSelect == NULL)) {
  2100. //
  2101. // It's a tricky point. The timer routine set adpref as 0xff if the first
  2102. // rt timeout and no advertisement received, which means any advertisement
  2103. // received will be selected after the first rt.
  2104. //
  2105. Timeout = TRUE;
  2106. }
  2107. //
  2108. // Check whether the current packet has a 255 preference option or not.
  2109. // Take non-preference option as 0 value.
  2110. //
  2111. Option = Dhcp6SeekOption (
  2112. Packet->Dhcp6.Option,
  2113. Packet->Length - 4,
  2114. Dhcp6OptPreference
  2115. );
  2116. if ((Instance->AdSelect == NULL) || ((Option != NULL) && (*(Option + 4) > Instance->AdPref))) {
  2117. //
  2118. // No advertisements received before or preference is more than other
  2119. // advertisements received before. Then store the new packet and the
  2120. // preference value.
  2121. //
  2122. if (Instance->AdSelect != NULL) {
  2123. FreePool (Instance->AdSelect);
  2124. }
  2125. Instance->AdSelect = AllocateZeroPool (Packet->Size);
  2126. if (Instance->AdSelect == NULL) {
  2127. return EFI_OUT_OF_RESOURCES;
  2128. }
  2129. CopyMem (Instance->AdSelect, Packet, Packet->Size);
  2130. if (Option != NULL) {
  2131. Instance->AdPref = *(Option + 4);
  2132. }
  2133. } else {
  2134. //
  2135. // Non-preference and other advertisements received before or current
  2136. // preference is less than other advertisements received before.
  2137. // Leave the packet alone.
  2138. }
  2139. } else {
  2140. //
  2141. // Other error status means termination.
  2142. //
  2143. return Status;
  2144. }
  2145. //
  2146. // Client must collect advertise messages as more as possible until the first
  2147. // RT has elapsed, or get a highest preference 255 advertise.
  2148. // See details in the section-17.1.2 of rfc-3315.
  2149. //
  2150. if ((Instance->AdPref == 0xff) || Timeout) {
  2151. Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
  2152. }
  2153. return Status;
  2154. }
  2155. /**
  2156. The Dhcp6 stateful exchange process routine.
  2157. @param[in] Instance The pointer to the Dhcp6 instance.
  2158. @param[in] Packet The pointer to the received Dhcp6 message.
  2159. **/
  2160. VOID
  2161. Dhcp6HandleStateful (
  2162. IN DHCP6_INSTANCE *Instance,
  2163. IN EFI_DHCP6_PACKET *Packet
  2164. )
  2165. {
  2166. EFI_STATUS Status;
  2167. EFI_DHCP6_DUID *ClientId;
  2168. DHCP6_SERVICE *Service;
  2169. UINT8 *Option;
  2170. Service = Instance->Service;
  2171. ClientId = Service->ClientId;
  2172. Status = EFI_SUCCESS;
  2173. if (Instance->Config == NULL) {
  2174. goto ON_CONTINUE;
  2175. }
  2176. ASSERT (ClientId);
  2177. ASSERT (Instance->Config);
  2178. ASSERT (Instance->IaCb.Ia);
  2179. //
  2180. // Discard the packet if not advertisement or reply packet.
  2181. //
  2182. if ((Packet->Dhcp6.Header.MessageType != Dhcp6MsgAdvertise) && (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply)) {
  2183. goto ON_CONTINUE;
  2184. }
  2185. //
  2186. // Check whether include client Id or not.
  2187. //
  2188. Option = Dhcp6SeekOption (
  2189. Packet->Dhcp6.Option,
  2190. Packet->Length - 4,
  2191. Dhcp6OptClientId
  2192. );
  2193. if ((Option == NULL) || (CompareMem (Option + 4, ClientId->Duid, ClientId->Length) != 0)) {
  2194. goto ON_CONTINUE;
  2195. }
  2196. //
  2197. // Check whether include server Id or not.
  2198. //
  2199. Option = Dhcp6SeekOption (
  2200. Packet->Dhcp6.Option,
  2201. Packet->Length - 4,
  2202. Dhcp6OptServerId
  2203. );
  2204. if (Option == NULL) {
  2205. goto ON_CONTINUE;
  2206. }
  2207. switch (Instance->IaCb.Ia->State) {
  2208. case Dhcp6Selecting:
  2209. //
  2210. // Handle the advertisement message when in the Dhcp6Selecting state.
  2211. // Do not need check return status, if failed, just continue to the next.
  2212. //
  2213. Dhcp6HandleAdvertiseMsg (Instance, Packet);
  2214. break;
  2215. case Dhcp6Requesting:
  2216. case Dhcp6Confirming:
  2217. case Dhcp6Renewing:
  2218. case Dhcp6Rebinding:
  2219. case Dhcp6Releasing:
  2220. case Dhcp6Declining:
  2221. //
  2222. // Handle the reply message when in the Dhcp6Requesting, Dhcp6Renewing
  2223. // Dhcp6Rebinding, Dhcp6Releasing and Dhcp6Declining state.
  2224. // If failed here, it should reset the current session.
  2225. //
  2226. Status = Dhcp6HandleReplyMsg (Instance, Packet);
  2227. if (EFI_ERROR (Status)) {
  2228. goto ON_EXIT;
  2229. }
  2230. break;
  2231. default:
  2232. //
  2233. // Other state has not supported yet.
  2234. //
  2235. break;
  2236. }
  2237. ON_CONTINUE:
  2238. //
  2239. // Continue to receive the following Dhcp6 message.
  2240. //
  2241. Status = UdpIoRecvDatagram (
  2242. Service->UdpIo,
  2243. Dhcp6ReceivePacket,
  2244. Service,
  2245. 0
  2246. );
  2247. ON_EXIT:
  2248. if (EFI_ERROR (Status)) {
  2249. Dhcp6CleanupSession (Instance, Status);
  2250. }
  2251. }
  2252. /**
  2253. The Dhcp6 stateless exchange process routine.
  2254. @param[in] Instance The pointer to the Dhcp6 instance.
  2255. @param[in] Packet The pointer to the received Dhcp6 message.
  2256. **/
  2257. VOID
  2258. Dhcp6HandleStateless (
  2259. IN DHCP6_INSTANCE *Instance,
  2260. IN EFI_DHCP6_PACKET *Packet
  2261. )
  2262. {
  2263. EFI_STATUS Status;
  2264. DHCP6_SERVICE *Service;
  2265. DHCP6_INF_CB *InfCb;
  2266. UINT8 *Option;
  2267. BOOLEAN IsMatched;
  2268. Service = Instance->Service;
  2269. Status = EFI_SUCCESS;
  2270. IsMatched = FALSE;
  2271. InfCb = NULL;
  2272. if (Packet->Dhcp6.Header.MessageType != Dhcp6MsgReply) {
  2273. goto ON_EXIT;
  2274. }
  2275. //
  2276. // Check whether it's a desired Info-request message by Xid.
  2277. //
  2278. while (!IsListEmpty (&Instance->InfList)) {
  2279. InfCb = NET_LIST_HEAD (&Instance->InfList, DHCP6_INF_CB, Link);
  2280. if (InfCb->Xid == Packet->Dhcp6.Header.TransactionId) {
  2281. IsMatched = TRUE;
  2282. break;
  2283. }
  2284. }
  2285. if (!IsMatched) {
  2286. goto ON_EXIT;
  2287. }
  2288. //
  2289. // Check whether include server Id or not.
  2290. //
  2291. Option = Dhcp6SeekOption (
  2292. Packet->Dhcp6.Option,
  2293. Packet->Length - 4,
  2294. Dhcp6OptServerId
  2295. );
  2296. if (Option == NULL) {
  2297. goto ON_EXIT;
  2298. }
  2299. //
  2300. // Callback to user with the received packet and check the user's feedback.
  2301. //
  2302. Status = InfCb->ReplyCallback (
  2303. &Instance->Dhcp6,
  2304. InfCb->CallbackContext,
  2305. Packet
  2306. );
  2307. if (Status == EFI_NOT_READY) {
  2308. //
  2309. // Success or aborted will both stop this info-request exchange process,
  2310. // but not ready means user wants to continue to receive reply.
  2311. //
  2312. goto ON_EXIT;
  2313. }
  2314. //
  2315. // Dequeue the sent packet from the txlist if the xid matched, and ignore
  2316. // if no xid matched.
  2317. //
  2318. Dhcp6DequeueRetry (
  2319. Instance,
  2320. Packet->Dhcp6.Header.TransactionId,
  2321. FALSE
  2322. );
  2323. //
  2324. // For sync, set the status out of polling for info-request.
  2325. //
  2326. Instance->UdpSts = Status;
  2327. ON_EXIT:
  2328. Status = UdpIoRecvDatagram (
  2329. Service->UdpIo,
  2330. Dhcp6ReceivePacket,
  2331. Service,
  2332. 0
  2333. );
  2334. if (EFI_ERROR (Status)) {
  2335. Dhcp6CleanupRetry (Instance, DHCP6_PACKET_STATELESS);
  2336. }
  2337. }
  2338. /**
  2339. The receive callback function for Dhcp6 exchange process.
  2340. @param[in] Udp6Wrap The pointer to the received net buffer.
  2341. @param[in] EndPoint The pointer to the udp end point.
  2342. @param[in] IoStatus The return status from udp io.
  2343. @param[in] Context The opaque parameter to the function.
  2344. **/
  2345. VOID
  2346. EFIAPI
  2347. Dhcp6ReceivePacket (
  2348. IN NET_BUF *Udp6Wrap,
  2349. IN UDP_END_POINT *EndPoint,
  2350. IN EFI_STATUS IoStatus,
  2351. IN VOID *Context
  2352. )
  2353. {
  2354. EFI_DHCP6_HEADER *Head;
  2355. EFI_DHCP6_PACKET *Packet;
  2356. DHCP6_SERVICE *Service;
  2357. DHCP6_INSTANCE *Instance;
  2358. DHCP6_TX_CB *TxCb;
  2359. UINT32 Size;
  2360. BOOLEAN IsDispatched;
  2361. BOOLEAN IsStateless;
  2362. LIST_ENTRY *Entry1;
  2363. LIST_ENTRY *Next1;
  2364. LIST_ENTRY *Entry2;
  2365. LIST_ENTRY *Next2;
  2366. EFI_STATUS Status;
  2367. ASSERT (Udp6Wrap != NULL);
  2368. ASSERT (Context != NULL);
  2369. Service = (DHCP6_SERVICE *)Context;
  2370. Instance = NULL;
  2371. Packet = NULL;
  2372. IsDispatched = FALSE;
  2373. IsStateless = FALSE;
  2374. if (EFI_ERROR (IoStatus)) {
  2375. return;
  2376. }
  2377. if (Udp6Wrap->TotalSize < sizeof (EFI_DHCP6_HEADER)) {
  2378. goto ON_CONTINUE;
  2379. }
  2380. //
  2381. // Copy the net buffer received from upd6 to a Dhcp6 packet.
  2382. //
  2383. Size = sizeof (EFI_DHCP6_PACKET) + Udp6Wrap->TotalSize;
  2384. Packet = (EFI_DHCP6_PACKET *)AllocateZeroPool (Size);
  2385. if (Packet == NULL) {
  2386. goto ON_CONTINUE;
  2387. }
  2388. Packet->Size = Size;
  2389. Head = &Packet->Dhcp6.Header;
  2390. Packet->Length = NetbufCopy (Udp6Wrap, 0, Udp6Wrap->TotalSize, (UINT8 *)Head);
  2391. if (Packet->Length == 0) {
  2392. goto ON_CONTINUE;
  2393. }
  2394. //
  2395. // Dispatch packet to right instance by transaction id.
  2396. //
  2397. NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {
  2398. Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);
  2399. NET_LIST_FOR_EACH_SAFE (Entry2, Next2, &Instance->TxList) {
  2400. TxCb = NET_LIST_USER_STRUCT (Entry2, DHCP6_TX_CB, Link);
  2401. if (Packet->Dhcp6.Header.TransactionId == TxCb->Xid) {
  2402. //
  2403. // Find the corresponding packet in tx list, and check it whether belongs
  2404. // to stateful exchange process.
  2405. //
  2406. if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
  2407. IsStateless = TRUE;
  2408. }
  2409. IsDispatched = TRUE;
  2410. break;
  2411. }
  2412. }
  2413. if (IsDispatched) {
  2414. break;
  2415. }
  2416. }
  2417. //
  2418. // Skip this packet if not dispatched to any instance.
  2419. //
  2420. if (!IsDispatched) {
  2421. goto ON_CONTINUE;
  2422. }
  2423. //
  2424. // Dispatch the received packet ot the right instance.
  2425. //
  2426. if (IsStateless) {
  2427. Dhcp6HandleStateless (Instance, Packet);
  2428. } else {
  2429. Dhcp6HandleStateful (Instance, Packet);
  2430. }
  2431. ON_CONTINUE:
  2432. if (!IsDispatched) {
  2433. Status = UdpIoRecvDatagram (
  2434. Service->UdpIo,
  2435. Dhcp6ReceivePacket,
  2436. Service,
  2437. 0
  2438. );
  2439. if (EFI_ERROR (Status)) {
  2440. NET_LIST_FOR_EACH_SAFE (Entry1, Next1, &Service->Child) {
  2441. Instance = NET_LIST_USER_STRUCT (Entry1, DHCP6_INSTANCE, Link);
  2442. Dhcp6CleanupRetry (Instance, DHCP6_PACKET_ALL);
  2443. }
  2444. }
  2445. }
  2446. NetbufFree (Udp6Wrap);
  2447. if (Packet != NULL) {
  2448. FreePool (Packet);
  2449. }
  2450. }
  2451. /**
  2452. Detect Link movement for specified network device.
  2453. This routine will try to invoke Snp->GetStatus() to get the media status.
  2454. If media present status switches from unpresent to present, a link movement
  2455. is detected. Note that the underlying UNDI driver may not support reporting
  2456. media status from GET_STATUS command. If that, fail to detect link movement.
  2457. @param[in] Instance The pointer to DHCP6_INSTANCE.
  2458. @retval TRUE A link movement is detected.
  2459. @retval FALSE A link movement is not detected.
  2460. **/
  2461. BOOLEAN
  2462. Dhcp6LinkMovDetect (
  2463. IN DHCP6_INSTANCE *Instance
  2464. )
  2465. {
  2466. UINT32 InterruptStatus;
  2467. BOOLEAN MediaPresent;
  2468. EFI_STATUS Status;
  2469. EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
  2470. ASSERT (Instance != NULL);
  2471. Snp = Instance->Service->Snp;
  2472. MediaPresent = Instance->MediaPresent;
  2473. //
  2474. // Check whether SNP support media detection
  2475. //
  2476. if (!Snp->Mode->MediaPresentSupported) {
  2477. return FALSE;
  2478. }
  2479. //
  2480. // Invoke Snp->GetStatus() to refresh MediaPresent field in SNP mode data
  2481. //
  2482. Status = Snp->GetStatus (Snp, &InterruptStatus, NULL);
  2483. if (EFI_ERROR (Status)) {
  2484. return FALSE;
  2485. }
  2486. Instance->MediaPresent = Snp->Mode->MediaPresent;
  2487. //
  2488. // Media transimit Unpresent to Present means new link movement is detected.
  2489. //
  2490. if (!MediaPresent && Instance->MediaPresent) {
  2491. return TRUE;
  2492. }
  2493. return FALSE;
  2494. }
  2495. /**
  2496. The timer routine of the Dhcp6 instance for each second.
  2497. @param[in] Event The timer event.
  2498. @param[in] Context The opaque parameter to the function.
  2499. **/
  2500. VOID
  2501. EFIAPI
  2502. Dhcp6OnTimerTick (
  2503. IN EFI_EVENT Event,
  2504. IN VOID *Context
  2505. )
  2506. {
  2507. LIST_ENTRY *Entry;
  2508. LIST_ENTRY *NextEntry;
  2509. DHCP6_INSTANCE *Instance;
  2510. DHCP6_TX_CB *TxCb;
  2511. DHCP6_IA_CB *IaCb;
  2512. UINT32 LossTime;
  2513. EFI_STATUS Status;
  2514. ASSERT (Context != NULL);
  2515. Instance = (DHCP6_INSTANCE *)Context;
  2516. //
  2517. // 1. Loop the tx list, count live time of every tx packet to check whether
  2518. // need re-transmit or not.
  2519. //
  2520. NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Instance->TxList) {
  2521. TxCb = NET_LIST_USER_STRUCT (Entry, DHCP6_TX_CB, Link);
  2522. TxCb->TickTime++;
  2523. if (TxCb->TickTime > TxCb->RetryExp) {
  2524. //
  2525. // Handle the first rt in the transmission of solicit specially.
  2526. //
  2527. if (((TxCb->RetryCnt == 0) || TxCb->SolicitRetry) && (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit)) {
  2528. if (Instance->AdSelect == NULL) {
  2529. //
  2530. // Set adpref as 0xff here to indicate select any advertisement
  2531. // afterwards.
  2532. //
  2533. Instance->AdPref = 0xff;
  2534. } else {
  2535. //
  2536. // Select the advertisement received before.
  2537. //
  2538. Status = Dhcp6SelectAdvertiseMsg (Instance, Instance->AdSelect);
  2539. if (Status == EFI_ABORTED) {
  2540. goto ON_CLOSE;
  2541. } else if (EFI_ERROR (Status)) {
  2542. TxCb->RetryCnt++;
  2543. }
  2544. return;
  2545. }
  2546. }
  2547. //
  2548. // Increase the retry count for the packet and add up the total loss time.
  2549. //
  2550. TxCb->RetryCnt++;
  2551. TxCb->RetryLos += TxCb->RetryExp;
  2552. //
  2553. // Check whether overflow the max retry count limit for this packet
  2554. //
  2555. if ((TxCb->RetryCtl.Mrc != 0) && (TxCb->RetryCtl.Mrc < TxCb->RetryCnt)) {
  2556. Status = EFI_NO_RESPONSE;
  2557. goto ON_CLOSE;
  2558. }
  2559. //
  2560. // Check whether overflow the max retry duration for this packet
  2561. //
  2562. if ((TxCb->RetryCtl.Mrd != 0) && (TxCb->RetryCtl.Mrd <= TxCb->RetryLos)) {
  2563. Status = EFI_NO_RESPONSE;
  2564. goto ON_CLOSE;
  2565. }
  2566. //
  2567. // Re-calculate retry expire timeout for the next time.
  2568. //
  2569. // Firstly, Check the new calculated time whether overflow the max retry
  2570. // expire time.
  2571. //
  2572. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  2573. TxCb->RetryExp,
  2574. FALSE,
  2575. TRUE
  2576. );
  2577. if ((TxCb->RetryCtl.Mrt != 0) && (TxCb->RetryCtl.Mrt < TxCb->RetryExp)) {
  2578. TxCb->RetryExp = Dhcp6CalculateExpireTime (
  2579. TxCb->RetryCtl.Mrt,
  2580. TRUE,
  2581. TRUE
  2582. );
  2583. }
  2584. //
  2585. // Secondly, Check the new calculated time whether overflow the max retry
  2586. // duration time.
  2587. //
  2588. LossTime = TxCb->RetryLos + TxCb->RetryExp;
  2589. if ((TxCb->RetryCtl.Mrd != 0) && (TxCb->RetryCtl.Mrd < LossTime)) {
  2590. TxCb->RetryExp = TxCb->RetryCtl.Mrd - TxCb->RetryLos;
  2591. }
  2592. //
  2593. // Reset the tick time for the next retransmission
  2594. //
  2595. TxCb->TickTime = 0;
  2596. //
  2597. // Retransmit the last sent packet again.
  2598. //
  2599. Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed);
  2600. TxCb->SolicitRetry = FALSE;
  2601. if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) {
  2602. TxCb->SolicitRetry = TRUE;
  2603. }
  2604. }
  2605. }
  2606. //
  2607. // 2. Check the configured Ia, count lease time of every valid Ia to check
  2608. // whether need to renew or rebind this Ia.
  2609. //
  2610. IaCb = &Instance->IaCb;
  2611. if ((Instance->Config == NULL) || (IaCb->Ia == NULL)) {
  2612. return;
  2613. }
  2614. if ((IaCb->Ia->State == Dhcp6Bound) || (IaCb->Ia->State == Dhcp6Renewing) || (IaCb->Ia->State == Dhcp6Rebinding)) {
  2615. IaCb->LeaseTime++;
  2616. if ((IaCb->LeaseTime > IaCb->T2) && (IaCb->Ia->State == Dhcp6Bound)) {
  2617. //
  2618. // Exceed t2, send rebind packet to extend the Ia lease.
  2619. //
  2620. Dhcp6SendRenewRebindMsg (Instance, TRUE);
  2621. } else if ((IaCb->LeaseTime > IaCb->T1) && (IaCb->Ia->State == Dhcp6Bound)) {
  2622. //
  2623. // Exceed t1, send renew packet to extend the Ia lease.
  2624. //
  2625. Dhcp6SendRenewRebindMsg (Instance, FALSE);
  2626. }
  2627. }
  2628. //
  2629. // 3. In any situation when a client may have moved to a new link, the
  2630. // client MUST initiate a Confirm/Reply message exchange.
  2631. //
  2632. if (Dhcp6LinkMovDetect (Instance) && (IaCb->Ia->State == Dhcp6Bound)) {
  2633. Dhcp6SendConfirmMsg (Instance);
  2634. }
  2635. return;
  2636. ON_CLOSE:
  2637. if (Dhcp6IsValidTxCb (Instance, TxCb) &&
  2638. (TxCb->TxPacket != NULL) &&
  2639. ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) ||
  2640. (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) ||
  2641. (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm))
  2642. )
  2643. {
  2644. //
  2645. // The failure of renew/Confirm will still switch to the bound state.
  2646. //
  2647. if ((TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgRenew) ||
  2648. (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgConfirm))
  2649. {
  2650. ASSERT (Instance->IaCb.Ia);
  2651. Instance->IaCb.Ia->State = Dhcp6Bound;
  2652. }
  2653. //
  2654. // The failure of info-request will return no response.
  2655. //
  2656. if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgInfoRequest) {
  2657. Instance->UdpSts = EFI_NO_RESPONSE;
  2658. }
  2659. Dhcp6DequeueRetry (
  2660. Instance,
  2661. TxCb->Xid,
  2662. TRUE
  2663. );
  2664. } else {
  2665. //
  2666. // The failure of the others will terminate current state machine if timeout.
  2667. //
  2668. Dhcp6CleanupSession (Instance, Status);
  2669. }
  2670. }