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