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