]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Input.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Input.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 IP6 internal functions to process the incoming packets.\r
3\r
f75a7f56 4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
c79de074 5 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
a3bcde70 6\r
ecf98fbc 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a3bcde70
HT
8\r
9**/\r
10\r
11#include "Ip6Impl.h"\r
12\r
13/**\r
14 Create an empty assemble entry for the packet identified by\r
15 (Dst, Src, Id). The default life for the packet is 60 seconds.\r
16\r
17 @param[in] Dst The destination address.\r
18 @param[in] Src The source address.\r
19 @param[in] Id The ID field in the IP header.\r
20\r
21 @return NULL if failed to allocate memory for the entry. Otherwise,\r
22 the pointer to the just created reassemble entry.\r
23\r
24**/\r
25IP6_ASSEMBLE_ENTRY *\r
26Ip6CreateAssembleEntry (\r
d1050b9d
MK
27 IN EFI_IPv6_ADDRESS *Dst,\r
28 IN EFI_IPv6_ADDRESS *Src,\r
29 IN UINT32 Id\r
a3bcde70
HT
30 )\r
31{\r
d1050b9d 32 IP6_ASSEMBLE_ENTRY *Assemble;\r
a3bcde70
HT
33\r
34 Assemble = AllocatePool (sizeof (IP6_ASSEMBLE_ENTRY));\r
35 if (Assemble == NULL) {\r
36 return NULL;\r
37 }\r
38\r
39 IP6_COPY_ADDRESS (&Assemble->Dst, Dst);\r
40 IP6_COPY_ADDRESS (&Assemble->Src, Src);\r
41 InitializeListHead (&Assemble->Fragments);\r
42\r
d1050b9d
MK
43 Assemble->Id = Id;\r
44 Assemble->Life = IP6_FRAGMENT_LIFE + 1;\r
a3bcde70
HT
45\r
46 Assemble->TotalLen = 0;\r
47 Assemble->CurLen = 0;\r
48 Assemble->Head = NULL;\r
49 Assemble->Info = NULL;\r
50 Assemble->Packet = NULL;\r
51\r
52 return Assemble;\r
53}\r
54\r
55/**\r
56 Release all the fragments of a packet, then free the assemble entry.\r
57\r
58 @param[in] Assemble The assemble entry to free.\r
59\r
60**/\r
61VOID\r
62Ip6FreeAssembleEntry (\r
d1050b9d 63 IN IP6_ASSEMBLE_ENTRY *Assemble\r
a3bcde70
HT
64 )\r
65{\r
d1050b9d
MK
66 LIST_ENTRY *Entry;\r
67 LIST_ENTRY *Next;\r
68 NET_BUF *Fragment;\r
a3bcde70
HT
69\r
70 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Assemble->Fragments) {\r
71 Fragment = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
72\r
73 RemoveEntryList (Entry);\r
74 NetbufFree (Fragment);\r
75 }\r
76\r
77 if (Assemble->Packet != NULL) {\r
78 NetbufFree (Assemble->Packet);\r
79 }\r
80\r
81 FreePool (Assemble);\r
82}\r
83\r
84/**\r
85 Release all the fragments of the packet. This is the callback for\r
86 the assembled packet's OnFree. It will free the assemble entry,\r
87 which in turn frees all the fragments of the packet.\r
88\r
89 @param[in] Arg The assemble entry to free.\r
90\r
91**/\r
92VOID\r
93EFIAPI\r
94Ip6OnFreeFragments (\r
d1050b9d 95 IN VOID *Arg\r
a3bcde70
HT
96 )\r
97{\r
d1050b9d 98 Ip6FreeAssembleEntry ((IP6_ASSEMBLE_ENTRY *)Arg);\r
a3bcde70
HT
99}\r
100\r
101/**\r
102 Trim the packet to fit in [Start, End), and update per the\r
103 packet information.\r
104\r
105 @param[in, out] Packet Packet to trim.\r
106 @param[in] Start The sequence of the first byte to fit in.\r
107 @param[in] End One beyond the sequence of last byte to fit in.\r
108\r
109**/\r
110VOID\r
111Ip6TrimPacket (\r
d1050b9d
MK
112 IN OUT NET_BUF *Packet,\r
113 IN INTN Start,\r
114 IN INTN End\r
a3bcde70
HT
115 )\r
116{\r
d1050b9d
MK
117 IP6_CLIP_INFO *Info;\r
118 INTN Len;\r
a3bcde70
HT
119\r
120 Info = IP6_GET_CLIP_INFO (Packet);\r
121\r
122 ASSERT (Info->Start + Info->Length == Info->End);\r
123 ASSERT ((Info->Start < End) && (Start < Info->End));\r
124\r
d1050b9d 125 if (Info->Start < Start) {\r
a3bcde70
HT
126 Len = Start - Info->Start;\r
127\r
d1050b9d
MK
128 NetbufTrim (Packet, (UINT32)Len, NET_BUF_HEAD);\r
129 Info->Start = (UINT32)Start;\r
130 Info->Length -= (UINT32)Len;\r
a3bcde70
HT
131 }\r
132\r
133 if (End < Info->End) {\r
134 Len = End - Info->End;\r
135\r
d1050b9d
MK
136 NetbufTrim (Packet, (UINT32)Len, NET_BUF_TAIL);\r
137 Info->End = (UINT32)End;\r
138 Info->Length -= (UINT32)Len;\r
a3bcde70
HT
139 }\r
140}\r
141\r
142/**\r
143 Reassemble the IP fragments. If all the fragments of the packet\r
144 have been received, it will wrap the packet in a net buffer then\r
145 return it to caller. If the packet can't be assembled, NULL is\r
146 returned.\r
147\r
148 @param[in, out] Table The assemble table used. A new assemble entry will be created\r
149 if the Packet is from a new chain of fragments.\r
150 @param[in] Packet The fragment to assemble. It might be freed if the fragment\r
151 can't be re-assembled.\r
152\r
153 @return NULL if the packet can't be reassembled. The pointer to the just assembled\r
154 packet if all the fragments of the packet have arrived.\r
155\r
156**/\r
157NET_BUF *\r
158Ip6Reassemble (\r
d1050b9d
MK
159 IN OUT IP6_ASSEMBLE_TABLE *Table,\r
160 IN NET_BUF *Packet\r
a3bcde70
HT
161 )\r
162{\r
d1050b9d
MK
163 EFI_IP6_HEADER *Head;\r
164 IP6_CLIP_INFO *This;\r
165 IP6_CLIP_INFO *Node;\r
166 IP6_ASSEMBLE_ENTRY *Assemble;\r
167 IP6_ASSEMBLE_ENTRY *Entry;\r
168 LIST_ENTRY *ListHead;\r
169 LIST_ENTRY *Prev;\r
170 LIST_ENTRY *Cur;\r
171 NET_BUF *Fragment;\r
172 NET_BUF *TmpPacket;\r
173 NET_BUF *NewPacket;\r
174 NET_BUF *Duplicate;\r
175 UINT8 *DupHead;\r
176 INTN Index;\r
177 UINT16 UnFragmentLen;\r
178 UINT8 *NextHeader;\r
a3bcde70
HT
179\r
180 Head = Packet->Ip.Ip6;\r
181 This = IP6_GET_CLIP_INFO (Packet);\r
182\r
183 ASSERT (Head != NULL);\r
184\r
185 //\r
186 // Find the corresponding assemble entry by (Dst, Src, Id)\r
187 //\r
d1050b9d
MK
188 Assemble = NULL;\r
189 Index = IP6_ASSEMBLE_HASH (&Head->DestinationAddress, &Head->SourceAddress, This->Id);\r
a3bcde70
HT
190\r
191 NET_LIST_FOR_EACH (Cur, &Table->Bucket[Index]) {\r
192 Entry = NET_LIST_USER_STRUCT (Cur, IP6_ASSEMBLE_ENTRY, Link);\r
193\r
d1050b9d 194 if ((Entry->Id == This->Id) &&\r
a3bcde70
HT
195 EFI_IP6_EQUAL (&Entry->Src, &Head->SourceAddress) &&\r
196 EFI_IP6_EQUAL (&Entry->Dst, &Head->DestinationAddress)\r
d1050b9d
MK
197 )\r
198 {\r
a3bcde70
HT
199 Assemble = Entry;\r
200 break;\r
201 }\r
202 }\r
203\r
204 //\r
205 // Create a new entry if can not find an existing one, insert it to assemble table\r
206 //\r
207 if (Assemble == NULL) {\r
208 Assemble = Ip6CreateAssembleEntry (\r
209 &Head->DestinationAddress,\r
210 &Head->SourceAddress,\r
211 This->Id\r
212 );\r
213\r
214 if (Assemble == NULL) {\r
215 goto Error;\r
216 }\r
217\r
218 InsertHeadList (&Table->Bucket[Index], &Assemble->Link);\r
219 }\r
220\r
221 //\r
222 // Find the point to insert the packet: before the first\r
223 // fragment with THIS.Start < CUR.Start. the previous one\r
224 // has PREV.Start <= THIS.Start < CUR.Start.\r
225 //\r
226 ListHead = &Assemble->Fragments;\r
227\r
228 NET_LIST_FOR_EACH (Cur, ListHead) {\r
229 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
230\r
231 if (This->Start < IP6_GET_CLIP_INFO (Fragment)->Start) {\r
232 break;\r
233 }\r
234 }\r
235\r
236 //\r
237 // Check whether the current fragment overlaps with the previous one.\r
238 // It holds that: PREV.Start <= THIS.Start < THIS.End. Only need to\r
239 // check whether THIS.Start < PREV.End for overlap. If two fragments\r
240 // overlaps, trim the overlapped part off THIS fragment.\r
241 //\r
cc0b145e 242 if ((Prev = Cur->BackLink) != ListHead) {\r
d1050b9d
MK
243 Fragment = NET_LIST_USER_STRUCT (Prev, NET_BUF, List);\r
244 Node = IP6_GET_CLIP_INFO (Fragment);\r
a3bcde70
HT
245\r
246 if (This->Start < Node->End) {\r
247 if (This->End <= Node->End) {\r
248 goto Error;\r
249 }\r
250\r
251 //\r
252 // Trim the previous fragment from tail.\r
253 //\r
254 Ip6TrimPacket (Fragment, Node->Start, This->Start);\r
255 }\r
256 }\r
257\r
258 //\r
259 // Insert the fragment into the packet. The fragment may be removed\r
260 // from the list by the following checks.\r
261 //\r
262 NetListInsertBefore (Cur, &Packet->List);\r
263\r
264 //\r
265 // Check the packets after the insert point. It holds that:\r
266 // THIS.Start <= NODE.Start < NODE.End. The equality holds\r
267 // if PREV and NEXT are continuous. THIS fragment may fill\r
268 // several holes. Remove the completely overlapped fragments\r
269 //\r
270 while (Cur != ListHead) {\r
271 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
272 Node = IP6_GET_CLIP_INFO (Fragment);\r
273\r
274 //\r
275 // Remove fragments completely overlapped by this fragment\r
276 //\r
277 if (Node->End <= This->End) {\r
278 Cur = Cur->ForwardLink;\r
279\r
280 RemoveEntryList (&Fragment->List);\r
281 Assemble->CurLen -= Node->Length;\r
282\r
283 NetbufFree (Fragment);\r
284 continue;\r
285 }\r
286\r
287 //\r
288 // The conditions are: THIS.Start <= NODE.Start, and THIS.End <\r
289 // NODE.End. Two fragments overlaps if NODE.Start < THIS.End.\r
290 // If two fragments start at the same offset, remove THIS fragment\r
291 // because ((THIS.Start == NODE.Start) && (THIS.End < NODE.End)).\r
292 //\r
293 if (Node->Start < This->End) {\r
294 if (This->Start == Node->Start) {\r
295 RemoveEntryList (&Packet->List);\r
296 goto Error;\r
297 }\r
298\r
299 Ip6TrimPacket (Packet, This->Start, Node->Start);\r
300 }\r
301\r
302 break;\r
303 }\r
304\r
305 //\r
306 // Update the assemble info: increase the current length. If it is\r
307 // the frist fragment, update the packet's IP head and per packet\r
308 // info. If it is the last fragment, update the total length.\r
309 //\r
310 Assemble->CurLen += This->Length;\r
311\r
312 if (This->Start == 0) {\r
313 //\r
314 // Once the first fragment is enqueued, it can't be removed\r
315 // from the fragment list. So, Assemble->Head always point\r
316 // to valid memory area.\r
317 //\r
318 if ((Assemble->Head != NULL) || (Assemble->Packet != NULL)) {\r
319 goto Error;\r
320 }\r
321\r
322 //\r
7de8045a 323 // Backup the first fragment in case the reassembly of that packet fail.\r
a3bcde70
HT
324 //\r
325 Duplicate = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));\r
326 if (Duplicate == NULL) {\r
327 goto Error;\r
328 }\r
329\r
330 //\r
331 // Revert IP head to network order.\r
332 //\r
333 DupHead = NetbufGetByte (Duplicate, 0, NULL);\r
334 ASSERT (DupHead != NULL);\r
d1050b9d 335 Duplicate->Ip.Ip6 = Ip6NtohHead ((EFI_IP6_HEADER *)DupHead);\r
a3bcde70
HT
336 Assemble->Packet = Duplicate;\r
337\r
338 //\r
339 // Adjust the unfragmentable part in first fragment\r
340 //\r
d1050b9d 341 UnFragmentLen = (UINT16)(This->HeadLen - sizeof (EFI_IP6_HEADER));\r
a3bcde70
HT
342 if (UnFragmentLen == 0) {\r
343 //\r
344 // There is not any unfragmentable extension header.\r
345 //\r
346 ASSERT (Head->NextHeader == IP6_FRAGMENT);\r
347 Head->NextHeader = This->NextHeader;\r
348 } else {\r
349 NextHeader = NetbufGetByte (\r
350 Packet,\r
351 This->FormerNextHeader + sizeof (EFI_IP6_HEADER),\r
352 0\r
353 );\r
354 if (NextHeader == NULL) {\r
355 goto Error;\r
356 }\r
357\r
358 *NextHeader = This->NextHeader;\r
359 }\r
360\r
361 Assemble->Head = Head;\r
362 Assemble->Info = IP6_GET_CLIP_INFO (Packet);\r
363 }\r
364\r
365 //\r
366 // Don't update the length more than once.\r
367 //\r
368 if ((This->LastFrag != 0) && (Assemble->TotalLen == 0)) {\r
369 Assemble->TotalLen = This->End;\r
370 }\r
371\r
372 //\r
373 // Deliver the whole packet if all the fragments received.\r
374 // All fragments received if:\r
7de8045a 375 // 1. received the last one, so, the total length is known\r
a3bcde70
HT
376 // 2. received all the data. If the last fragment on the\r
377 // queue ends at the total length, all data is received.\r
378 //\r
379 if ((Assemble->TotalLen != 0) && (Assemble->CurLen >= Assemble->TotalLen)) {\r
a3bcde70
HT
380 RemoveEntryList (&Assemble->Link);\r
381\r
382 //\r
7de8045a 383 // If the packet is properly formatted, the last fragment's End\r
a3bcde70
HT
384 // equals to the packet's total length. Otherwise, the packet\r
385 // is a fake, drop it now.\r
386 //\r
387 Fragment = NET_LIST_USER_STRUCT (ListHead->BackLink, NET_BUF, List);\r
d1050b9d 388 if (IP6_GET_CLIP_INFO (Fragment)->End != (INTN)Assemble->TotalLen) {\r
a3bcde70
HT
389 Ip6FreeAssembleEntry (Assemble);\r
390 goto Error;\r
391 }\r
392\r
393 Fragment = NET_LIST_HEAD (ListHead, NET_BUF, List);\r
394 This = Assemble->Info;\r
395\r
396 //\r
397 // This TmpPacket is used to hold the unfragmentable part, i.e.,\r
398 // the IPv6 header and the unfragmentable extension headers. Be noted that\r
7de8045a 399 // the Fragment Header is excluded.\r
a3bcde70
HT
400 //\r
401 TmpPacket = NetbufGetFragment (Fragment, 0, This->HeadLen, 0);\r
402 ASSERT (TmpPacket != NULL);\r
403\r
404 NET_LIST_FOR_EACH (Cur, ListHead) {\r
405 //\r
406 // Trim off the unfragment part plus the fragment header from all fragments.\r
407 //\r
408 Fragment = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);\r
409 NetbufTrim (Fragment, This->HeadLen + sizeof (IP6_FRAGMENT_HEADER), TRUE);\r
410 }\r
411\r
412 InsertHeadList (ListHead, &TmpPacket->List);\r
413\r
414 //\r
415 // Wrap the packet in a net buffer then deliver it up\r
416 //\r
417 NewPacket = NetbufFromBufList (\r
418 &Assemble->Fragments,\r
419 0,\r
420 0,\r
421 Ip6OnFreeFragments,\r
422 Assemble\r
423 );\r
424\r
425 if (NewPacket == NULL) {\r
426 Ip6FreeAssembleEntry (Assemble);\r
427 goto Error;\r
428 }\r
429\r
430 NewPacket->Ip.Ip6 = Assemble->Head;\r
431\r
432 CopyMem (IP6_GET_CLIP_INFO (NewPacket), Assemble->Info, sizeof (IP6_CLIP_INFO));\r
433\r
434 return NewPacket;\r
435 }\r
436\r
437 return NULL;\r
438\r
439Error:\r
440 NetbufFree (Packet);\r
441 return NULL;\r
442}\r
443\r
a3bcde70
HT
444/**\r
445 The callback function for the net buffer that wraps the packet processed by\r
446 IPsec. It releases the wrap packet and also signals IPsec to free the resources.\r
447\r
448 @param[in] Arg The wrap context.\r
449\r
450**/\r
451VOID\r
452EFIAPI\r
453Ip6IpSecFree (\r
d1050b9d 454 IN VOID *Arg\r
a3bcde70
HT
455 )\r
456{\r
d1050b9d 457 IP6_IPSEC_WRAP *Wrap;\r
a3bcde70 458\r
d1050b9d 459 Wrap = (IP6_IPSEC_WRAP *)Arg;\r
a3bcde70
HT
460\r
461 if (Wrap->IpSecRecycleSignal != NULL) {\r
462 gBS->SignalEvent (Wrap->IpSecRecycleSignal);\r
463 }\r
464\r
465 NetbufFree (Wrap->Packet);\r
466\r
467 FreePool (Wrap);\r
468\r
469 return;\r
470}\r
471\r
472/**\r
473 The work function to locate the IPsec protocol to process the inbound or\r
474 outbound IP packets. The process routine handles the packet with the following\r
475 actions: bypass the packet, discard the packet, or protect the packet.\r
476\r
477 @param[in] IpSb The IP6 service instance.\r
68d3f2fb 478 @param[in, out] Head The caller-supplied IP6 header.\r
a3bcde70
HT
479 @param[in, out] LastHead The next header field of last IP header.\r
480 @param[in, out] Netbuf The IP6 packet to be processed by IPsec.\r
68d3f2fb 481 @param[in, out] ExtHdrs The caller-supplied options.\r
482 @param[in, out] ExtHdrsLen The length of the option.\r
a3bcde70
HT
483 @param[in] Direction The directionality in an SPD entry,\r
484 EfiIPsecInBound, or EfiIPsecOutBound.\r
485 @param[in] Context The token's wrap.\r
486\r
487 @retval EFI_SUCCESS The IPsec protocol is not available or disabled.\r
488 @retval EFI_SUCCESS The packet was bypassed, and all buffers remain the same.\r
489 @retval EFI_SUCCESS The packet was protected.\r
490 @retval EFI_ACCESS_DENIED The packet was discarded.\r
7de8045a 491 @retval EFI_OUT_OF_RESOURCES There are not sufficient resources to complete the operation.\r
a3bcde70
HT
492 @retval EFI_BUFFER_TOO_SMALL The number of non-empty blocks is bigger than the\r
493 number of input data blocks when building a fragment table.\r
494\r
495**/\r
496EFI_STATUS\r
497Ip6IpSecProcessPacket (\r
68d3f2fb 498 IN IP6_SERVICE *IpSb,\r
499 IN OUT EFI_IP6_HEADER **Head,\r
500 IN OUT UINT8 *LastHead,\r
501 IN OUT NET_BUF **Netbuf,\r
502 IN OUT UINT8 **ExtHdrs,\r
503 IN OUT UINT32 *ExtHdrsLen,\r
504 IN EFI_IPSEC_TRAFFIC_DIR Direction,\r
505 IN VOID *Context\r
a3bcde70
HT
506 )\r
507{\r
d1050b9d
MK
508 NET_FRAGMENT *FragmentTable;\r
509 NET_FRAGMENT *OriginalFragmentTable;\r
510 UINT32 FragmentCount;\r
511 UINT32 OriginalFragmentCount;\r
512 EFI_EVENT RecycleEvent;\r
513 NET_BUF *Packet;\r
514 IP6_TXTOKEN_WRAP *TxWrap;\r
515 IP6_IPSEC_WRAP *IpSecWrap;\r
516 EFI_STATUS Status;\r
517 EFI_IP6_HEADER *PacketHead;\r
518 UINT8 *Buf;\r
519 EFI_IP6_HEADER ZeroHead;\r
520\r
521 Status = EFI_SUCCESS;\r
c79de074
SEHM
522\r
523 if (!mIpSec2Installed) {\r
524 goto ON_EXIT;\r
525 }\r
d1050b9d 526\r
9a04dcff 527 ASSERT (mIpSec != NULL);\r
f75a7f56 528\r
a3bcde70
HT
529 Packet = *Netbuf;\r
530 RecycleEvent = NULL;\r
531 IpSecWrap = NULL;\r
532 FragmentTable = NULL;\r
533 PacketHead = NULL;\r
534 Buf = NULL;\r
d1050b9d 535 TxWrap = (IP6_TXTOKEN_WRAP *)Context;\r
a3bcde70 536 FragmentCount = Packet->BlockOpNum;\r
68d3f2fb 537 ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));\r
a3bcde70 538\r
a3bcde70
HT
539 //\r
540 // Check whether the ipsec enable variable is set.\r
541 //\r
542 if (mIpSec->DisabledFlag) {\r
543 //\r
544 // If IPsec is disabled, restore the original MTU\r
545 //\r
546 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize;\r
547 goto ON_EXIT;\r
548 } else {\r
549 //\r
550 // If IPsec is enabled, use the MTU which reduce the IPsec header length.\r
551 //\r
552 IpSb->MaxPacketSize = IpSb->OldMaxPacketSize - IP6_MAX_IPSEC_HEADLEN;\r
553 }\r
554\r
a3bcde70
HT
555 //\r
556 // Bypass all multicast inbound or outbound traffic.\r
557 //\r
68d3f2fb 558 if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress) || IP6_IS_MULTICAST (&(*Head)->SourceAddress)) {\r
a3bcde70
HT
559 goto ON_EXIT;\r
560 }\r
561\r
562 //\r
563 // Rebuild fragment table from netbuf to ease ipsec process.\r
564 //\r
565 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (NET_FRAGMENT));\r
566\r
567 if (FragmentTable == NULL) {\r
568 Status = EFI_OUT_OF_RESOURCES;\r
569 goto ON_EXIT;\r
570 }\r
571\r
d1050b9d 572 Status = NetbufBuildExt (Packet, FragmentTable, &FragmentCount);\r
68d3f2fb 573 OriginalFragmentTable = FragmentTable;\r
574 OriginalFragmentCount = FragmentCount;\r
a3bcde70 575\r
d1050b9d 576 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
577 FreePool (FragmentTable);\r
578 goto ON_EXIT;\r
579 }\r
580\r
581 //\r
582 // Convert host byte order to network byte order\r
583 //\r
68d3f2fb 584 Ip6NtohHead (*Head);\r
a3bcde70 585\r
68d3f2fb 586 Status = mIpSec->ProcessExt (\r
a3bcde70
HT
587 mIpSec,\r
588 IpSb->Controller,\r
589 IP_VERSION_6,\r
d1050b9d 590 (VOID *)(*Head),\r
a3bcde70 591 LastHead,\r
d1050b9d 592 (VOID **)ExtHdrs,\r
68d3f2fb 593 ExtHdrsLen,\r
d1050b9d 594 (EFI_IPSEC_FRAGMENT_DATA **)(&FragmentTable),\r
a3bcde70
HT
595 &FragmentCount,\r
596 Direction,\r
597 &RecycleEvent\r
598 );\r
599 //\r
600 // Convert back to host byte order\r
601 //\r
68d3f2fb 602 Ip6NtohHead (*Head);\r
a3bcde70
HT
603\r
604 if (EFI_ERROR (Status)) {\r
94b928ca 605 FreePool (OriginalFragmentTable);\r
a3bcde70
HT
606 goto ON_EXIT;\r
607 }\r
608\r
d1050b9d 609 if ((OriginalFragmentCount == FragmentCount) && (OriginalFragmentTable == FragmentTable)) {\r
68d3f2fb 610 //\r
611 // For ByPass Packet\r
612 //\r
94b928ca 613 FreePool (FragmentTable);\r
68d3f2fb 614 goto ON_EXIT;\r
94b928ca 615 } else {\r
616 //\r
617 // Free the FragmentTable which allocated before calling the IPsec.\r
618 //\r
619 FreePool (OriginalFragmentTable);\r
68d3f2fb 620 }\r
a3bcde70 621\r
d1050b9d 622 if ((Direction == EfiIPsecOutBound) && (TxWrap != NULL)) {\r
a3bcde70
HT
623 TxWrap->IpSecRecycleSignal = RecycleEvent;\r
624 TxWrap->Packet = NetbufFromExt (\r
625 FragmentTable,\r
626 FragmentCount,\r
627 IP6_MAX_HEADLEN,\r
628 0,\r
629 Ip6FreeTxToken,\r
630 TxWrap\r
631 );\r
632 if (TxWrap->Packet == NULL) {\r
94b928ca 633 TxWrap->Packet = *Netbuf;\r
d1050b9d 634 Status = EFI_OUT_OF_RESOURCES;\r
a3bcde70
HT
635 goto ON_EXIT;\r
636 }\r
637\r
68d3f2fb 638 CopyMem (\r
639 IP6_GET_CLIP_INFO (TxWrap->Packet),\r
640 IP6_GET_CLIP_INFO (Packet),\r
641 sizeof (IP6_CLIP_INFO)\r
642 );\r
f75a7f56 643\r
d1050b9d 644 NetIpSecNetbufFree (Packet);\r
a3bcde70 645 *Netbuf = TxWrap->Packet;\r
a3bcde70 646 } else {\r
a3bcde70
HT
647 IpSecWrap = AllocateZeroPool (sizeof (IP6_IPSEC_WRAP));\r
648\r
649 if (IpSecWrap == NULL) {\r
94b928ca 650 Status = EFI_OUT_OF_RESOURCES;\r
651 gBS->SignalEvent (RecycleEvent);\r
a3bcde70
HT
652 goto ON_EXIT;\r
653 }\r
654\r
655 IpSecWrap->IpSecRecycleSignal = RecycleEvent;\r
656 IpSecWrap->Packet = Packet;\r
657 Packet = NetbufFromExt (\r
658 FragmentTable,\r
659 FragmentCount,\r
660 IP6_MAX_HEADLEN,\r
661 0,\r
662 Ip6IpSecFree,\r
663 IpSecWrap\r
664 );\r
665\r
666 if (Packet == NULL) {\r
94b928ca 667 Packet = IpSecWrap->Packet;\r
668 gBS->SignalEvent (RecycleEvent);\r
669 FreePool (IpSecWrap);\r
a3bcde70
HT
670 Status = EFI_OUT_OF_RESOURCES;\r
671 goto ON_EXIT;\r
672 }\r
673\r
d1050b9d
MK
674 if ((Direction == EfiIPsecInBound) && (0 != CompareMem (&ZeroHead, *Head, sizeof (EFI_IP6_HEADER)))) {\r
675 PacketHead = (EFI_IP6_HEADER *)NetbufAllocSpace (\r
676 Packet,\r
677 sizeof (EFI_IP6_HEADER) + *ExtHdrsLen,\r
678 NET_BUF_HEAD\r
679 );\r
a3bcde70 680 if (PacketHead == NULL) {\r
94b928ca 681 *Netbuf = Packet;\r
682 Status = EFI_OUT_OF_RESOURCES;\r
a3bcde70
HT
683 goto ON_EXIT;\r
684 }\r
685\r
68d3f2fb 686 CopyMem (PacketHead, *Head, sizeof (EFI_IP6_HEADER));\r
d1050b9d 687 *Head = PacketHead;\r
a3bcde70
HT
688 Packet->Ip.Ip6 = PacketHead;\r
689\r
68d3f2fb 690 if (*ExtHdrs != NULL) {\r
d1050b9d 691 Buf = (UINT8 *)(PacketHead + 1);\r
68d3f2fb 692 CopyMem (Buf, *ExtHdrs, *ExtHdrsLen);\r
a3bcde70
HT
693 }\r
694\r
68d3f2fb 695 NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);\r
a3bcde70
HT
696 CopyMem (\r
697 IP6_GET_CLIP_INFO (Packet),\r
698 IP6_GET_CLIP_INFO (IpSecWrap->Packet),\r
699 sizeof (IP6_CLIP_INFO)\r
700 );\r
701 }\r
d1050b9d 702\r
a3bcde70
HT
703 *Netbuf = Packet;\r
704 }\r
705\r
706ON_EXIT:\r
707 return Status;\r
708}\r
709\r
710/**\r
68d3f2fb 711 Pre-process the IPv6 packet. First validates the IPv6 packet, and\r
712 then reassembles packet if it is necessary.\r
713\r
714 @param[in] IpSb The IP6 service instance.\r
715 @param[in, out] Packet The received IP6 packet to be processed.\r
716 @param[in] Flag The link layer flag for the packet received, such\r
717 as multicast.\r
7de8045a 718 @param[out] Payload The pointer to the payload of the received packet.\r
f75a7f56 719 it starts from the first byte of the extension header.\r
68d3f2fb 720 @param[out] LastHead The pointer of NextHeader of the last extension\r
721 header processed by IP6.\r
722 @param[out] ExtHdrsLen The length of the whole option.\r
723 @param[out] UnFragmentLen The length of unfragmented length of extension headers.\r
f75a7f56 724 @param[out] Fragmented Indicate whether the packet is fragmented.\r
68d3f2fb 725 @param[out] Head The pointer to the EFI_IP6_Header.\r
726\r
727 @retval EFI_SUCCESS The received packet is well format.\r
728 @retval EFI_INVALID_PARAMETER The received packet is malformed.\r
a3bcde70
HT
729\r
730**/\r
68d3f2fb 731EFI_STATUS\r
732Ip6PreProcessPacket (\r
d1050b9d
MK
733 IN IP6_SERVICE *IpSb,\r
734 IN OUT NET_BUF **Packet,\r
735 IN UINT32 Flag,\r
736 OUT UINT8 **Payload,\r
737 OUT UINT8 **LastHead,\r
738 OUT UINT32 *ExtHdrsLen,\r
739 OUT UINT32 *UnFragmentLen,\r
740 OUT BOOLEAN *Fragmented,\r
741 OUT EFI_IP6_HEADER **Head\r
a3bcde70
HT
742 )\r
743{\r
d1050b9d
MK
744 UINT16 PayloadLen;\r
745 UINT16 TotalLen;\r
746 UINT32 FormerHeadOffset;\r
747 UINT32 HeadLen;\r
748 IP6_FRAGMENT_HEADER *FragmentHead;\r
749 UINT16 FragmentOffset;\r
750 IP6_CLIP_INFO *Info;\r
751 EFI_IPv6_ADDRESS Loopback;\r
a3bcde70 752\r
68d3f2fb 753 HeadLen = 0;\r
754 PayloadLen = 0;\r
a3bcde70
HT
755 //\r
756 // Check whether the input packet is a valid packet\r
757 //\r
68d3f2fb 758 if ((*Packet)->TotalSize < IP6_MIN_HEADLEN) {\r
759 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
760 }\r
761\r
762 //\r
763 // Get header information of the packet.\r
764 //\r
d1050b9d 765 *Head = (EFI_IP6_HEADER *)NetbufGetByte (*Packet, 0, NULL);\r
68d3f2fb 766 if (*Head == NULL) {\r
767 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
768 }\r
769\r
770 //\r
771 // Multicast addresses must not be used as source addresses in IPv6 packets.\r
772 //\r
68d3f2fb 773 if (((*Head)->Version != 6) || (IP6_IS_MULTICAST (&(*Head)->SourceAddress))) {\r
774 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
775 }\r
776\r
777 //\r
778 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.\r
779 //\r
780 ZeroMem (&Loopback, sizeof (EFI_IPv6_ADDRESS));\r
781 Loopback.Addr[15] = 0x1;\r
68d3f2fb 782 if ((CompareMem (&Loopback, &(*Head)->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) ||\r
d1050b9d
MK
783 (NetIp6IsUnspecifiedAddr (&(*Head)->DestinationAddress)))\r
784 {\r
68d3f2fb 785 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
786 }\r
787\r
788 //\r
789 // Convert the IP header to host byte order.\r
790 //\r
68d3f2fb 791 (*Packet)->Ip.Ip6 = Ip6NtohHead (*Head);\r
a3bcde70
HT
792\r
793 //\r
794 // Get the per packet info.\r
795 //\r
68d3f2fb 796 Info = IP6_GET_CLIP_INFO (*Packet);\r
a3bcde70
HT
797 Info->LinkFlag = Flag;\r
798 Info->CastType = 0;\r
799\r
800 if (IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
801 Info->CastType = Ip6Promiscuous;\r
802 }\r
803\r
68d3f2fb 804 if (Ip6IsOneOfSetAddress (IpSb, &(*Head)->DestinationAddress, NULL, NULL)) {\r
a3bcde70 805 Info->CastType = Ip6Unicast;\r
68d3f2fb 806 } else if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress)) {\r
807 if (Ip6FindMldEntry (IpSb, &(*Head)->DestinationAddress) != NULL) {\r
a3bcde70
HT
808 Info->CastType = Ip6Multicast;\r
809 }\r
810 }\r
811\r
812 //\r
813 // Drop the packet that is not delivered to us.\r
814 //\r
815 if (Info->CastType == 0) {\r
68d3f2fb 816 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
817 }\r
818\r
68d3f2fb 819 PayloadLen = (*Head)->PayloadLength;\r
a3bcde70
HT
820\r
821 Info->Start = 0;\r
822 Info->Length = PayloadLen;\r
823 Info->End = Info->Start + Info->Length;\r
d1050b9d 824 Info->HeadLen = (UINT16)sizeof (EFI_IP6_HEADER);\r
a3bcde70
HT
825 Info->Status = EFI_SUCCESS;\r
826 Info->LastFrag = FALSE;\r
827\r
d1050b9d 828 TotalLen = (UINT16)(PayloadLen + sizeof (EFI_IP6_HEADER));\r
a3bcde70
HT
829\r
830 //\r
831 // Mnp may deliver frame trailer sequence up, trim it off.\r
832 //\r
68d3f2fb 833 if (TotalLen < (*Packet)->TotalSize) {\r
834 NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);\r
a3bcde70
HT
835 }\r
836\r
68d3f2fb 837 if (TotalLen != (*Packet)->TotalSize) {\r
838 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
839 }\r
840\r
841 //\r
842 // Check the extension headers, if exist validate them\r
843 //\r
844 if (PayloadLen != 0) {\r
d1050b9d 845 *Payload = AllocatePool ((UINTN)PayloadLen);\r
68d3f2fb 846 if (*Payload == NULL) {\r
847 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
848 }\r
849\r
68d3f2fb 850 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);\r
a3bcde70
HT
851 }\r
852\r
a3bcde70
HT
853 if (!Ip6IsExtsValid (\r
854 IpSb,\r
68d3f2fb 855 *Packet,\r
856 &(*Head)->NextHeader,\r
857 *Payload,\r
d1050b9d 858 (UINT32)PayloadLen,\r
a3bcde70
HT
859 TRUE,\r
860 &FormerHeadOffset,\r
68d3f2fb 861 LastHead,\r
862 ExtHdrsLen,\r
863 UnFragmentLen,\r
864 Fragmented\r
d1050b9d
MK
865 ))\r
866 {\r
68d3f2fb 867 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
868 }\r
869\r
d1050b9d 870 HeadLen = sizeof (EFI_IP6_HEADER) + *UnFragmentLen;\r
a3bcde70 871\r
68d3f2fb 872 if (*Fragmented) {\r
a3bcde70
HT
873 //\r
874 // Get the fragment offset from the Fragment header\r
875 //\r
d1050b9d 876 FragmentHead = (IP6_FRAGMENT_HEADER *)NetbufGetByte (*Packet, HeadLen, NULL);\r
a3bcde70 877 if (FragmentHead == NULL) {\r
68d3f2fb 878 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
879 }\r
880\r
881 FragmentOffset = NTOHS (FragmentHead->FragmentOffset);\r
882\r
883 if ((FragmentOffset & 0x1) == 0) {\r
884 Info->LastFrag = TRUE;\r
885 }\r
886\r
887 FragmentOffset &= (~0x1);\r
888\r
889 //\r
890 // This is the first fragment of the packet\r
891 //\r
892 if (FragmentOffset == 0) {\r
893 Info->NextHeader = FragmentHead->NextHeader;\r
894 }\r
895\r
d1050b9d
MK
896 Info->HeadLen = (UINT16)HeadLen;\r
897 HeadLen += sizeof (IP6_FRAGMENT_HEADER);\r
a3bcde70 898 Info->Start = FragmentOffset;\r
d1050b9d 899 Info->Length = TotalLen - (UINT16)HeadLen;\r
a3bcde70
HT
900 Info->End = Info->Start + Info->Length;\r
901 Info->Id = FragmentHead->Identification;\r
902 Info->FormerNextHeader = FormerHeadOffset;\r
903\r
904 //\r
905 // Fragments should in the unit of 8 octets long except the last one.\r
906 //\r
907 if ((Info->LastFrag == 0) && (Info->Length % 8 != 0)) {\r
68d3f2fb 908 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
909 }\r
910\r
911 //\r
912 // Reassemble the packet.\r
913 //\r
68d3f2fb 914 *Packet = Ip6Reassemble (&IpSb->Assemble, *Packet);\r
915 if (*Packet == NULL) {\r
916 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
917 }\r
918\r
919 //\r
920 // Re-check the assembled packet to get the right values.\r
921 //\r
d1050b9d
MK
922 *Head = (*Packet)->Ip.Ip6;\r
923 PayloadLen = (*Head)->PayloadLength;\r
a3bcde70 924 if (PayloadLen != 0) {\r
68d3f2fb 925 if (*Payload != NULL) {\r
926 FreePool (*Payload);\r
a3bcde70
HT
927 }\r
928\r
d1050b9d 929 *Payload = AllocatePool ((UINTN)PayloadLen);\r
68d3f2fb 930 if (*Payload == NULL) {\r
931 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
932 }\r
933\r
68d3f2fb 934 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);\r
a3bcde70
HT
935 }\r
936\r
937 if (!Ip6IsExtsValid (\r
938 IpSb,\r
68d3f2fb 939 *Packet,\r
940 &(*Head)->NextHeader,\r
941 *Payload,\r
d1050b9d 942 (UINT32)PayloadLen,\r
a3bcde70
HT
943 TRUE,\r
944 NULL,\r
68d3f2fb 945 LastHead,\r
946 ExtHdrsLen,\r
947 UnFragmentLen,\r
948 Fragmented\r
d1050b9d
MK
949 ))\r
950 {\r
68d3f2fb 951 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
952 }\r
953 }\r
954\r
955 //\r
956 // Trim the head off, after this point, the packet is headless.\r
957 // and Packet->TotalLen == Info->Length.\r
958 //\r
68d3f2fb 959 NetbufTrim (*Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);\r
f75a7f56 960\r
68d3f2fb 961 return EFI_SUCCESS;\r
962}\r
963\r
964/**\r
965 The IP6 input routine. It is called by the IP6_INTERFACE when an\r
966 IP6 fragment is received from MNP.\r
967\r
968 @param[in] Packet The IP6 packet received.\r
969 @param[in] IoStatus The return status of receive request.\r
970 @param[in] Flag The link layer flag for the packet received, such\r
971 as multicast.\r
972 @param[in] Context The IP6 service instance that owns the MNP.\r
a3bcde70 973\r
68d3f2fb 974**/\r
975VOID\r
976Ip6AcceptFrame (\r
d1050b9d
MK
977 IN NET_BUF *Packet,\r
978 IN EFI_STATUS IoStatus,\r
979 IN UINT32 Flag,\r
980 IN VOID *Context\r
68d3f2fb 981 )\r
982{\r
d1050b9d
MK
983 IP6_SERVICE *IpSb;\r
984 EFI_IP6_HEADER *Head;\r
985 UINT8 *Payload;\r
986 UINT8 *LastHead;\r
987 UINT32 UnFragmentLen;\r
988 UINT32 ExtHdrsLen;\r
989 BOOLEAN Fragmented;\r
990 EFI_STATUS Status;\r
991 EFI_IP6_HEADER ZeroHead;\r
992\r
993 IpSb = (IP6_SERVICE *)Context;\r
68d3f2fb 994 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
995\r
996 Payload = NULL;\r
997 LastHead = NULL;\r
998\r
999 //\r
1000 // Check input parameters\r
1001 //\r
1002 if (EFI_ERROR (IoStatus) || (IpSb->State == IP6_SERVICE_DESTROY)) {\r
1003 goto Drop;\r
1004 }\r
f75a7f56 1005\r
68d3f2fb 1006 //\r
1007 // Pre-Process the Ipv6 Packet and then reassemble if it is necessary.\r
1008 //\r
1009 Status = Ip6PreProcessPacket (\r
f75a7f56
LG
1010 IpSb,\r
1011 &Packet,\r
1012 Flag,\r
1013 &Payload,\r
1014 &LastHead,\r
1015 &ExtHdrsLen,\r
1016 &UnFragmentLen,\r
68d3f2fb 1017 &Fragmented,\r
1018 &Head\r
1019 );\r
1020 if (EFI_ERROR (Status)) {\r
1021 goto Restart;\r
1022 }\r
d1050b9d 1023\r
a3bcde70
HT
1024 //\r
1025 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,\r
1026 // and no need consider any other ahead ext headers.\r
1027 //\r
1028 Status = Ip6IpSecProcessPacket (\r
1029 IpSb,\r
68d3f2fb 1030 &Head,\r
a3bcde70
HT
1031 LastHead, // need get the lasthead value for input\r
1032 &Packet,\r
68d3f2fb 1033 &Payload,\r
1034 &ExtHdrsLen,\r
a3bcde70
HT
1035 EfiIPsecInBound,\r
1036 NULL\r
1037 );\r
1038\r
68d3f2fb 1039 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
1040 goto Restart;\r
1041 }\r
1042\r
1043 //\r
68d3f2fb 1044 // If the packet is protected by IPsec Tunnel Mode, Check the Inner Ip Packet.\r
a3bcde70 1045 //\r
68d3f2fb 1046 ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));\r
1047 if (0 == CompareMem (Head, &ZeroHead, sizeof (EFI_IP6_HEADER))) {\r
1048 Status = Ip6PreProcessPacket (\r
f75a7f56
LG
1049 IpSb,\r
1050 &Packet,\r
1051 Flag,\r
1052 &Payload,\r
1053 &LastHead,\r
1054 &ExtHdrsLen,\r
1055 &UnFragmentLen,\r
1056 &Fragmented,\r
68d3f2fb 1057 &Head\r
1058 );\r
1059 if (EFI_ERROR (Status)) {\r
1060 goto Restart;\r
1061 }\r
1062 }\r
a3bcde70 1063\r
90e529e2 1064 //\r
1065 // Check the Packet again.\r
1066 //\r
1067 if (Packet == NULL) {\r
1068 goto Restart;\r
1069 }\r
f75a7f56 1070\r
a3bcde70
HT
1071 //\r
1072 // Packet may have been changed. The ownership of the packet\r
7de8045a 1073 // is transferred to the packet process logic.\r
a3bcde70 1074 //\r
d1050b9d 1075 Head = Packet->Ip.Ip6;\r
a3bcde70
HT
1076 IP6_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;\r
1077\r
1078 switch (*LastHead) {\r
d1050b9d
MK
1079 case IP6_ICMP:\r
1080 Ip6IcmpHandle (IpSb, Head, Packet);\r
1081 break;\r
1082 default:\r
1083 Ip6Demultiplex (IpSb, Head, Packet);\r
a3bcde70
HT
1084 }\r
1085\r
1086 Packet = NULL;\r
1087\r
1088 //\r
1089 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events\r
1090 // which are signaled with received data.\r
1091 //\r
1092 DispatchDpc ();\r
1093\r
1094Restart:\r
1095 if (Payload != NULL) {\r
1096 FreePool (Payload);\r
1097 }\r
1098\r
1099 Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);\r
1100\r
1101Drop:\r
1102 if (Packet != NULL) {\r
1103 NetbufFree (Packet);\r
1104 }\r
1105\r
d1050b9d 1106 return;\r
a3bcde70
HT
1107}\r
1108\r
1109/**\r
1110 Initialize an already allocated assemble table. This is generally\r
1111 the assemble table embedded in the IP6 service instance.\r
1112\r
1113 @param[in, out] Table The assemble table to initialize.\r
1114\r
1115**/\r
1116VOID\r
1117Ip6CreateAssembleTable (\r
d1050b9d 1118 IN OUT IP6_ASSEMBLE_TABLE *Table\r
a3bcde70
HT
1119 )\r
1120{\r
d1050b9d 1121 UINT32 Index;\r
a3bcde70
HT
1122\r
1123 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1124 InitializeListHead (&Table->Bucket[Index]);\r
1125 }\r
1126}\r
1127\r
1128/**\r
1129 Clean up the assemble table by removing all of the fragments\r
1130 and assemble entries.\r
1131\r
1132 @param[in, out] Table The assemble table to clean up.\r
1133\r
1134**/\r
1135VOID\r
1136Ip6CleanAssembleTable (\r
d1050b9d 1137 IN OUT IP6_ASSEMBLE_TABLE *Table\r
a3bcde70
HT
1138 )\r
1139{\r
d1050b9d
MK
1140 LIST_ENTRY *Entry;\r
1141 LIST_ENTRY *Next;\r
1142 IP6_ASSEMBLE_ENTRY *Assemble;\r
1143 UINT32 Index;\r
a3bcde70
HT
1144\r
1145 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1146 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {\r
1147 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);\r
1148\r
1149 RemoveEntryList (Entry);\r
1150 Ip6FreeAssembleEntry (Assemble);\r
1151 }\r
1152 }\r
1153}\r
1154\r
a3bcde70
HT
1155/**\r
1156 The signal handle of IP6's recycle event. It is called back\r
1157 when the upper layer releases the packet.\r
1158\r
1159 @param[in] Event The IP6's recycle event.\r
1160 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.\r
1161\r
1162**/\r
1163VOID\r
1164EFIAPI\r
1165Ip6OnRecyclePacket (\r
d1050b9d
MK
1166 IN EFI_EVENT Event,\r
1167 IN VOID *Context\r
a3bcde70
HT
1168 )\r
1169{\r
d1050b9d 1170 IP6_RXDATA_WRAP *Wrap;\r
a3bcde70 1171\r
d1050b9d 1172 Wrap = (IP6_RXDATA_WRAP *)Context;\r
a3bcde70
HT
1173\r
1174 EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);\r
1175 RemoveEntryList (&Wrap->Link);\r
1176 EfiReleaseLock (&Wrap->IpInstance->RecycleLock);\r
1177\r
1178 ASSERT (!NET_BUF_SHARED (Wrap->Packet));\r
1179 NetbufFree (Wrap->Packet);\r
1180\r
1181 gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
1182 FreePool (Wrap);\r
1183}\r
1184\r
1185/**\r
1186 Wrap the received packet to a IP6_RXDATA_WRAP, which will be\r
1187 delivered to the upper layer. Each IP6 child that accepts the\r
1188 packet will get a not-shared copy of the packet which is wrapped\r
1189 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed\r
1190 to the upper layer. The upper layer will signal the recycle event in\r
1191 it when it is done with the packet.\r
1192\r
1193 @param[in] IpInstance The IP6 child to receive the packet.\r
1194 @param[in] Packet The packet to deliver up.\r
1195\r
1196 @return NULL if it failed to wrap the packet; otherwise, the wrapper.\r
1197\r
1198**/\r
1199IP6_RXDATA_WRAP *\r
1200Ip6WrapRxData (\r
d1050b9d
MK
1201 IN IP6_PROTOCOL *IpInstance,\r
1202 IN NET_BUF *Packet\r
a3bcde70
HT
1203 )\r
1204{\r
d1050b9d
MK
1205 IP6_RXDATA_WRAP *Wrap;\r
1206 EFI_IP6_RECEIVE_DATA *RxData;\r
1207 EFI_STATUS Status;\r
a3bcde70
HT
1208\r
1209 Wrap = AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet->BlockOpNum));\r
1210\r
1211 if (Wrap == NULL) {\r
1212 return NULL;\r
1213 }\r
1214\r
1215 InitializeListHead (&Wrap->Link);\r
1216\r
d1050b9d
MK
1217 Wrap->IpInstance = IpInstance;\r
1218 Wrap->Packet = Packet;\r
1219 RxData = &Wrap->RxData;\r
a3bcde70
HT
1220\r
1221 ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));\r
1222\r
1223 Status = gBS->CreateEvent (\r
1224 EVT_NOTIFY_SIGNAL,\r
1225 TPL_NOTIFY,\r
1226 Ip6OnRecyclePacket,\r
1227 Wrap,\r
1228 &RxData->RecycleSignal\r
1229 );\r
1230\r
1231 if (EFI_ERROR (Status)) {\r
1232 FreePool (Wrap);\r
1233 return NULL;\r
1234 }\r
1235\r
1236 ASSERT (Packet->Ip.Ip6 != NULL);\r
1237\r
1238 //\r
1239 // The application expects a network byte order header.\r
1240 //\r
d1050b9d
MK
1241 RxData->HeaderLength = sizeof (EFI_IP6_HEADER);\r
1242 RxData->Header = (EFI_IP6_HEADER *)Ip6NtohHead (Packet->Ip.Ip6);\r
1243 RxData->DataLength = Packet->TotalSize;\r
a3bcde70
HT
1244\r
1245 //\r
1246 // Build the fragment table to be delivered up.\r
1247 //\r
1248 RxData->FragmentCount = Packet->BlockOpNum;\r
d1050b9d 1249 NetbufBuildExt (Packet, (NET_FRAGMENT *)RxData->FragmentTable, &RxData->FragmentCount);\r
a3bcde70
HT
1250\r
1251 return Wrap;\r
1252}\r
1253\r
1254/**\r
1255 Check whether this IP child accepts the packet.\r
1256\r
1257 @param[in] IpInstance The IP child to check.\r
1258 @param[in] Head The IP header of the packet.\r
1259 @param[in] Packet The data of the packet.\r
1260\r
1261 @retval TRUE The child wants to receive the packet.\r
1262 @retval FALSE The child does not want to receive the packet.\r
1263\r
1264**/\r
1265BOOLEAN\r
1266Ip6InstanceFrameAcceptable (\r
d1050b9d
MK
1267 IN IP6_PROTOCOL *IpInstance,\r
1268 IN EFI_IP6_HEADER *Head,\r
1269 IN NET_BUF *Packet\r
a3bcde70
HT
1270 )\r
1271{\r
d1050b9d
MK
1272 IP6_ICMP_ERROR_HEAD Icmp;\r
1273 EFI_IP6_CONFIG_DATA *Config;\r
1274 IP6_CLIP_INFO *Info;\r
1275 UINT8 *Proto;\r
1276 UINT32 Index;\r
1277 UINT8 *ExtHdrs;\r
1278 UINT16 ErrMsgPayloadLen;\r
1279 UINT8 *ErrMsgPayload;\r
a3bcde70
HT
1280\r
1281 Config = &IpInstance->ConfigData;\r
1282 Proto = NULL;\r
1283\r
1284 //\r
7de8045a 1285 // Dirty trick for the Tiano UEFI network stack implementation. If\r
a3bcde70
HT
1286 // ReceiveTimeout == -1, the receive of the packet for this instance\r
1287 // is disabled. The UEFI spec don't have such captibility. We add\r
1288 // this to improve the performance because IP will make a copy of\r
1289 // the received packet for each accepting instance. Some IP instances\r
1290 // used by UDP/TCP only send packets, they don't wants to receive.\r
1291 //\r
1292 if (Config->ReceiveTimeout == (UINT32)(-1)) {\r
1293 return FALSE;\r
1294 }\r
1295\r
1296 if (Config->AcceptPromiscuous) {\r
1297 return TRUE;\r
1298 }\r
1299\r
1300 //\r
1301 // Check whether the protocol is acceptable.\r
1302 //\r
1303 ExtHdrs = NetbufGetByte (Packet, 0, NULL);\r
1304\r
1305 if (!Ip6IsExtsValid (\r
1306 IpInstance->Service,\r
1307 Packet,\r
1308 &Head->NextHeader,\r
1309 ExtHdrs,\r
d1050b9d 1310 (UINT32)Head->PayloadLength,\r
a3bcde70
HT
1311 TRUE,\r
1312 NULL,\r
1313 &Proto,\r
1314 NULL,\r
1315 NULL,\r
1316 NULL\r
d1050b9d
MK
1317 ))\r
1318 {\r
a3bcde70
HT
1319 return FALSE;\r
1320 }\r
1321\r
1322 //\r
1323 // The upper layer driver may want to receive the ICMPv6 error packet\r
1324 // invoked by its packet, like UDP.\r
1325 //\r
1326 if ((*Proto == IP6_ICMP) && (!Config->AcceptAnyProtocol) && (*Proto != Config->DefaultProtocol)) {\r
d1050b9d 1327 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *)&Icmp);\r
a3bcde70
HT
1328\r
1329 if (Icmp.Head.Type <= ICMP_V6_ERROR_MAX) {\r
1330 if (!Config->AcceptIcmpErrors) {\r
1331 return FALSE;\r
1332 }\r
1333\r
1334 //\r
1335 // Get the protocol of the invoking packet of ICMPv6 error packet.\r
1336 //\r
1337 ErrMsgPayloadLen = NTOHS (Icmp.IpHead.PayloadLength);\r
1338 ErrMsgPayload = NetbufGetByte (Packet, sizeof (Icmp), NULL);\r
1339\r
1340 if (!Ip6IsExtsValid (\r
1341 NULL,\r
1342 NULL,\r
1343 &Icmp.IpHead.NextHeader,\r
1344 ErrMsgPayload,\r
1345 ErrMsgPayloadLen,\r
1346 TRUE,\r
1347 NULL,\r
1348 &Proto,\r
1349 NULL,\r
1350 NULL,\r
1351 NULL\r
d1050b9d
MK
1352 ))\r
1353 {\r
a3bcde70
HT
1354 return FALSE;\r
1355 }\r
1356 }\r
1357 }\r
1358\r
1359 //\r
1360 // Match the protocol\r
1361 //\r
1362 if (!Config->AcceptAnyProtocol && (*Proto != Config->DefaultProtocol)) {\r
1363 return FALSE;\r
1364 }\r
1365\r
1366 //\r
1367 // Check for broadcast, the caller has computed the packet's\r
1368 // cast type for this child's interface.\r
1369 //\r
1370 Info = IP6_GET_CLIP_INFO (Packet);\r
1371\r
1372 //\r
1373 // If it is a multicast packet, check whether we are in the group.\r
1374 //\r
1375 if (Info->CastType == Ip6Multicast) {\r
1376 //\r
1377 // Receive the multicast if the instance wants to receive all packets.\r
1378 //\r
1379 if (NetIp6IsUnspecifiedAddr (&IpInstance->ConfigData.StationAddress)) {\r
1380 return TRUE;\r
1381 }\r
1382\r
1383 for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
1384 if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, &Head->DestinationAddress)) {\r
1385 break;\r
1386 }\r
1387 }\r
1388\r
1389 return (BOOLEAN)(Index < IpInstance->GroupCount);\r
1390 }\r
1391\r
1392 return TRUE;\r
1393}\r
1394\r
1395/**\r
1396 Enqueue a shared copy of the packet to the IP6 child if the\r
1397 packet is acceptable to it. Here the data of the packet is\r
1398 shared, but the net buffer isn't.\r
1399\r
1400 @param IpInstance The IP6 child to enqueue the packet to.\r
1401 @param Head The IP header of the received packet.\r
1402 @param Packet The data of the received packet.\r
1403\r
1404 @retval EFI_NOT_STARTED The IP child hasn't been configured.\r
1405 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.\r
1406 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources\r
1407 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.\r
1408\r
1409**/\r
1410EFI_STATUS\r
1411Ip6InstanceEnquePacket (\r
d1050b9d
MK
1412 IN IP6_PROTOCOL *IpInstance,\r
1413 IN EFI_IP6_HEADER *Head,\r
1414 IN NET_BUF *Packet\r
a3bcde70
HT
1415 )\r
1416{\r
d1050b9d
MK
1417 IP6_CLIP_INFO *Info;\r
1418 NET_BUF *Clone;\r
a3bcde70
HT
1419\r
1420 //\r
1421 // Check whether the packet is acceptable to this instance.\r
1422 //\r
1423 if (IpInstance->State != IP6_STATE_CONFIGED) {\r
1424 return EFI_NOT_STARTED;\r
1425 }\r
1426\r
1427 if (!Ip6InstanceFrameAcceptable (IpInstance, Head, Packet)) {\r
1428 return EFI_INVALID_PARAMETER;\r
1429 }\r
1430\r
1431 //\r
7de8045a 1432 // Enqueue a shared copy of the packet.\r
a3bcde70
HT
1433 //\r
1434 Clone = NetbufClone (Packet);\r
1435\r
1436 if (Clone == NULL) {\r
1437 return EFI_OUT_OF_RESOURCES;\r
1438 }\r
1439\r
1440 //\r
1441 // Set the receive time out for the assembled packet. If it expires,\r
1442 // packet will be removed from the queue.\r
1443 //\r
d1050b9d
MK
1444 Info = IP6_GET_CLIP_INFO (Clone);\r
1445 Info->Life = IP6_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);\r
a3bcde70
HT
1446\r
1447 InsertTailList (&IpInstance->Received, &Clone->List);\r
1448 return EFI_SUCCESS;\r
1449}\r
1450\r
1451/**\r
1452 Deliver the received packets to the upper layer if there are both received\r
1453 requests and enqueued packets. If the enqueued packet is shared, it will\r
1454 duplicate it to a non-shared packet, release the shared packet, then\r
1455 deliver the non-shared packet up.\r
1456\r
1457 @param[in] IpInstance The IP child to deliver the packet up.\r
1458\r
1459 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the\r
1460 packets.\r
1461 @retval EFI_SUCCESS All the enqueued packets that can be delivered\r
1462 are delivered up.\r
1463\r
1464**/\r
1465EFI_STATUS\r
1466Ip6InstanceDeliverPacket (\r
d1050b9d 1467 IN IP6_PROTOCOL *IpInstance\r
a3bcde70
HT
1468 )\r
1469{\r
1470 EFI_IP6_COMPLETION_TOKEN *Token;\r
1471 IP6_RXDATA_WRAP *Wrap;\r
1472 NET_BUF *Packet;\r
1473 NET_BUF *Dup;\r
1474 UINT8 *Head;\r
1475\r
1476 //\r
1477 // Deliver a packet if there are both a packet and a receive token.\r
1478 //\r
1479 while (!IsListEmpty (&IpInstance->Received) && !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
a3bcde70
HT
1480 Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);\r
1481\r
1482 if (!NET_BUF_SHARED (Packet)) {\r
1483 //\r
1484 // If this is the only instance that wants the packet, wrap it up.\r
1485 //\r
1486 Wrap = Ip6WrapRxData (IpInstance, Packet);\r
1487\r
1488 if (Wrap == NULL) {\r
1489 return EFI_OUT_OF_RESOURCES;\r
1490 }\r
1491\r
1492 RemoveEntryList (&Packet->List);\r
a3bcde70
HT
1493 } else {\r
1494 //\r
1495 // Create a duplicated packet if this packet is shared\r
1496 //\r
1497 Dup = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));\r
1498\r
1499 if (Dup == NULL) {\r
1500 return EFI_OUT_OF_RESOURCES;\r
1501 }\r
1502\r
1503 //\r
1504 // Copy the IP head over. The packet to deliver up is\r
1505 // headless. Trim the head off after copy. The IP head\r
1506 // may be not continuous before the data.\r
1507 //\r
d1050b9d 1508 Head = NetbufAllocSpace (Dup, sizeof (EFI_IP6_HEADER), NET_BUF_HEAD);\r
a3bcde70 1509 ASSERT (Head != NULL);\r
d1050b9d 1510 Dup->Ip.Ip6 = (EFI_IP6_HEADER *)Head;\r
a3bcde70
HT
1511\r
1512 CopyMem (Head, Packet->Ip.Ip6, sizeof (EFI_IP6_HEADER));\r
1513 NetbufTrim (Dup, sizeof (EFI_IP6_HEADER), TRUE);\r
1514\r
1515 Wrap = Ip6WrapRxData (IpInstance, Dup);\r
1516\r
1517 if (Wrap == NULL) {\r
1518 NetbufFree (Dup);\r
1519 return EFI_OUT_OF_RESOURCES;\r
1520 }\r
1521\r
1522 RemoveEntryList (&Packet->List);\r
1523 NetbufFree (Packet);\r
1524\r
1525 Packet = Dup;\r
1526 }\r
1527\r
1528 //\r
1529 // Insert it into the delivered packet, then get a user's\r
1530 // receive token, pass the wrapped packet up.\r
1531 //\r
1532 EfiAcquireLockOrFail (&IpInstance->RecycleLock);\r
1533 InsertHeadList (&IpInstance->Delivered, &Wrap->Link);\r
1534 EfiReleaseLock (&IpInstance->RecycleLock);\r
1535\r
1536 Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);\r
1537 Token->Status = IP6_GET_CLIP_INFO (Packet)->Status;\r
1538 Token->Packet.RxData = &Wrap->RxData;\r
1539\r
1540 gBS->SignalEvent (Token->Event);\r
1541 }\r
1542\r
1543 return EFI_SUCCESS;\r
1544}\r
1545\r
1546/**\r
1547 Enqueue a received packet to all the IP children that share\r
1548 the same interface.\r
1549\r
1550 @param[in] IpSb The IP6 service instance that receive the packet.\r
1551 @param[in] Head The header of the received packet.\r
1552 @param[in] Packet The data of the received packet.\r
1553 @param[in] IpIf The interface to enqueue the packet to.\r
1554\r
1555 @return The number of the IP6 children that accepts the packet.\r
1556\r
1557**/\r
1558INTN\r
1559Ip6InterfaceEnquePacket (\r
d1050b9d
MK
1560 IN IP6_SERVICE *IpSb,\r
1561 IN EFI_IP6_HEADER *Head,\r
1562 IN NET_BUF *Packet,\r
1563 IN IP6_INTERFACE *IpIf\r
a3bcde70
HT
1564 )\r
1565{\r
d1050b9d
MK
1566 IP6_PROTOCOL *IpInstance;\r
1567 IP6_CLIP_INFO *Info;\r
1568 LIST_ENTRY *Entry;\r
1569 INTN Enqueued;\r
1570 INTN LocalType;\r
1571 INTN SavedType;\r
a3bcde70
HT
1572\r
1573 //\r
1574 // First, check that the packet is acceptable to this interface\r
1575 // and find the local cast type for the interface.\r
1576 //\r
1577 LocalType = 0;\r
1578 Info = IP6_GET_CLIP_INFO (Packet);\r
1579\r
1580 if (IpIf->PromiscRecv) {\r
1581 LocalType = Ip6Promiscuous;\r
1582 } else {\r
1583 LocalType = Info->CastType;\r
1584 }\r
1585\r
1586 //\r
1587 // Iterate through the ip instances on the interface, enqueue\r
1588 // the packet if filter passed. Save the original cast type,\r
1589 // and pass the local cast type to the IP children on the\r
1590 // interface. The global cast type will be restored later.\r
1591 //\r
d1050b9d
MK
1592 SavedType = Info->CastType;\r
1593 Info->CastType = (UINT32)LocalType;\r
a3bcde70 1594\r
d1050b9d 1595 Enqueued = 0;\r
a3bcde70
HT
1596\r
1597 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1598 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);\r
1599 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);\r
1600\r
1601 if (Ip6InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {\r
1602 Enqueued++;\r
1603 }\r
1604 }\r
1605\r
d1050b9d 1606 Info->CastType = (UINT32)SavedType;\r
a3bcde70
HT
1607 return Enqueued;\r
1608}\r
1609\r
1610/**\r
1611 Deliver the packet for each IP6 child on the interface.\r
1612\r
1613 @param[in] IpSb The IP6 service instance that received the packet.\r
1614 @param[in] IpIf The IP6 interface to deliver the packet.\r
1615\r
1616**/\r
1617VOID\r
1618Ip6InterfaceDeliverPacket (\r
d1050b9d
MK
1619 IN IP6_SERVICE *IpSb,\r
1620 IN IP6_INTERFACE *IpIf\r
a3bcde70
HT
1621 )\r
1622{\r
d1050b9d
MK
1623 IP6_PROTOCOL *IpInstance;\r
1624 LIST_ENTRY *Entry;\r
a3bcde70
HT
1625\r
1626 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1627 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);\r
1628 Ip6InstanceDeliverPacket (IpInstance);\r
1629 }\r
1630}\r
1631\r
1632/**\r
1633 De-multiplex the packet. the packet delivery is processed in two\r
1634 passes. The first pass will enqueue a shared copy of the packet\r
1635 to each IP6 child that accepts the packet. The second pass will\r
1636 deliver a non-shared copy of the packet to each IP6 child that\r
1637 has pending receive requests. Data is copied if more than one\r
1638 child wants to consume the packet, because each IP child needs\r
1639 its own copy of the packet to make changes.\r
1640\r
1641 @param[in] IpSb The IP6 service instance that received the packet.\r
1642 @param[in] Head The header of the received packet.\r
1643 @param[in] Packet The data of the received packet.\r
1644\r
1645 @retval EFI_NOT_FOUND No IP child accepts the packet.\r
1646 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP\r
1647 children.\r
1648\r
1649**/\r
1650EFI_STATUS\r
1651Ip6Demultiplex (\r
d1050b9d
MK
1652 IN IP6_SERVICE *IpSb,\r
1653 IN EFI_IP6_HEADER *Head,\r
1654 IN NET_BUF *Packet\r
a3bcde70
HT
1655 )\r
1656{\r
d1050b9d
MK
1657 LIST_ENTRY *Entry;\r
1658 IP6_INTERFACE *IpIf;\r
1659 INTN Enqueued;\r
a3bcde70
HT
1660\r
1661 //\r
7de8045a 1662 // Two pass delivery: first, enqueue a shared copy of the packet\r
a3bcde70
HT
1663 // to each instance that accept the packet.\r
1664 //\r
1665 Enqueued = 0;\r
1666\r
1667 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1668 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);\r
1669\r
1670 if (IpIf->Configured) {\r
1671 Enqueued += Ip6InterfaceEnquePacket (IpSb, Head, Packet, IpIf);\r
1672 }\r
1673 }\r
1674\r
1675 //\r
1676 // Second: deliver a duplicate of the packet to each instance.\r
1677 // Release the local reference first, so that the last instance\r
1678 // getting the packet will not copy the data.\r
1679 //\r
1680 NetbufFree (Packet);\r
1681 Packet = NULL;\r
1682\r
1683 if (Enqueued == 0) {\r
1684 return EFI_NOT_FOUND;\r
1685 }\r
1686\r
1687 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1688 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);\r
1689\r
1690 if (IpIf->Configured) {\r
1691 Ip6InterfaceDeliverPacket (IpSb, IpIf);\r
1692 }\r
1693 }\r
1694\r
1695 return EFI_SUCCESS;\r
1696}\r
1697\r
1698/**\r
1699 Decrease the life of the transmitted packets. If it is\r
1700 decreased to zero, cancel the packet. This function is\r
1701 called by Ip6packetTimerTicking that provides timeout for both the\r
1702 received-but-not-delivered and transmitted-but-not-recycle\r
1703 packets.\r
1704\r
1705 @param[in] Map The IP6 child's transmit map.\r
1706 @param[in] Item Current transmitted packet.\r
1707 @param[in] Context Not used.\r
1708\r
1709 @retval EFI_SUCCESS Always returns EFI_SUCCESS.\r
1710\r
1711**/\r
1712EFI_STATUS\r
1713EFIAPI\r
1714Ip6SentPacketTicking (\r
d1050b9d
MK
1715 IN NET_MAP *Map,\r
1716 IN NET_MAP_ITEM *Item,\r
1717 IN VOID *Context\r
a3bcde70
HT
1718 )\r
1719{\r
d1050b9d 1720 IP6_TXTOKEN_WRAP *Wrap;\r
a3bcde70 1721\r
d1050b9d 1722 Wrap = (IP6_TXTOKEN_WRAP *)Item->Value;\r
a3bcde70
HT
1723 ASSERT (Wrap != NULL);\r
1724\r
1725 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {\r
1726 Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
1727 }\r
1728\r
1729 return EFI_SUCCESS;\r
1730}\r
1731\r
1732/**\r
1733 Timeout the fragments, and the enqueued, and transmitted packets.\r
1734\r
1735 @param[in] IpSb The IP6 service instance to timeout.\r
1736\r
1737**/\r
1738VOID\r
1739Ip6PacketTimerTicking (\r
d1050b9d 1740 IN IP6_SERVICE *IpSb\r
a3bcde70
HT
1741 )\r
1742{\r
d1050b9d
MK
1743 LIST_ENTRY *InstanceEntry;\r
1744 LIST_ENTRY *Entry;\r
1745 LIST_ENTRY *Next;\r
1746 IP6_PROTOCOL *IpInstance;\r
1747 IP6_ASSEMBLE_ENTRY *Assemble;\r
1748 NET_BUF *Packet;\r
1749 IP6_CLIP_INFO *Info;\r
1750 UINT32 Index;\r
a3bcde70
HT
1751\r
1752 //\r
1753 // First, time out the fragments. The packet's life is counting down\r
1754 // once the first-arriving fragment of that packet was received.\r
1755 //\r
1756 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1757 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(IpSb->Assemble.Bucket[Index])) {\r
1758 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);\r
1759\r
1760 if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {\r
1761 //\r
1762 // If the first fragment (the one with a Fragment Offset of zero)\r
1763 // has been received, an ICMP Time Exceeded - Fragment Reassembly\r
1764 // Time Exceeded message should be sent to the source of that fragment.\r
1765 //\r
1766 if ((Assemble->Packet != NULL) &&\r
d1050b9d
MK
1767 !IP6_IS_MULTICAST (&Assemble->Head->DestinationAddress))\r
1768 {\r
a3bcde70
HT
1769 Ip6SendIcmpError (\r
1770 IpSb,\r
1771 Assemble->Packet,\r
1772 NULL,\r
1773 &Assemble->Head->SourceAddress,\r
1774 ICMP_V6_TIME_EXCEEDED,\r
1775 ICMP_V6_TIMEOUT_REASSEMBLE,\r
1776 NULL\r
1777 );\r
1778 }\r
1779\r
1780 //\r
1781 // If reassembly of a packet is not completed within 60 seconds of\r
1782 // the reception of the first-arriving fragment of that packet, the\r
1783 // reassembly must be abandoned and all the fragments that have been\r
1784 // received for that packet must be discarded.\r
1785 //\r
1786 RemoveEntryList (Entry);\r
1787 Ip6FreeAssembleEntry (Assemble);\r
1788 }\r
1789 }\r
1790 }\r
1791\r
1792 NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {\r
1793 IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP6_PROTOCOL, Link);\r
1794\r
1795 //\r
1796 // Second, time out the assembled packets enqueued on each IP child.\r
1797 //\r
1798 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {\r
1799 Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1800 Info = IP6_GET_CLIP_INFO (Packet);\r
1801\r
1802 if ((Info->Life > 0) && (--Info->Life == 0)) {\r
1803 RemoveEntryList (Entry);\r
1804 NetbufFree (Packet);\r
1805 }\r
1806 }\r
1807\r
1808 //\r
1809 // Third: time out the transmitted packets.\r
1810 //\r
1811 NetMapIterate (&IpInstance->TxTokens, Ip6SentPacketTicking, NULL);\r
1812 }\r
1813}\r