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