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