]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Input.c
Update the relevant drivers to use the correct GUID for EFI_IPSEC2_PROTOCOL.
[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
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
246 if ((Cur != ListHead) && ((Prev = Cur->BackLink) != ListHead)) {\r
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
616 goto ON_EXIT;\r
617 }\r
618\r
68d3f2fb 619 if (OriginalFragmentCount == FragmentCount && OriginalFragmentTable == FragmentTable) {\r
620 //\r
621 // For ByPass Packet\r
622 //\r
623 goto ON_EXIT;\r
624 }\r
a3bcde70 625\r
68d3f2fb 626 if (Direction == EfiIPsecOutBound && TxWrap != NULL) {\r
a3bcde70
HT
627 TxWrap->IpSecRecycleSignal = RecycleEvent;\r
628 TxWrap->Packet = NetbufFromExt (\r
629 FragmentTable,\r
630 FragmentCount,\r
631 IP6_MAX_HEADLEN,\r
632 0,\r
633 Ip6FreeTxToken,\r
634 TxWrap\r
635 );\r
636 if (TxWrap->Packet == NULL) {\r
637 Status = EFI_OUT_OF_RESOURCES;\r
638 goto ON_EXIT;\r
639 }\r
640\r
68d3f2fb 641 CopyMem (\r
642 IP6_GET_CLIP_INFO (TxWrap->Packet),\r
643 IP6_GET_CLIP_INFO (Packet),\r
644 sizeof (IP6_CLIP_INFO)\r
645 );\r
646 \r
647 NetIpSecNetbufFree(Packet);\r
a3bcde70
HT
648 *Netbuf = TxWrap->Packet;\r
649\r
650 } else {\r
651\r
652 IpSecWrap = AllocateZeroPool (sizeof (IP6_IPSEC_WRAP));\r
653\r
654 if (IpSecWrap == NULL) {\r
655 goto ON_EXIT;\r
656 }\r
657\r
658 IpSecWrap->IpSecRecycleSignal = RecycleEvent;\r
659 IpSecWrap->Packet = Packet;\r
660 Packet = NetbufFromExt (\r
661 FragmentTable,\r
662 FragmentCount,\r
663 IP6_MAX_HEADLEN,\r
664 0,\r
665 Ip6IpSecFree,\r
666 IpSecWrap\r
667 );\r
668\r
669 if (Packet == NULL) {\r
670 Status = EFI_OUT_OF_RESOURCES;\r
671 goto ON_EXIT;\r
672 }\r
673\r
68d3f2fb 674 if (Direction == EfiIPsecInBound && 0 != CompareMem (&ZeroHead, *Head, sizeof (EFI_IP6_HEADER))) {\r
a3bcde70
HT
675\r
676 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (\r
677 Packet,\r
68d3f2fb 678 sizeof (EFI_IP6_HEADER) + *ExtHdrsLen,\r
a3bcde70
HT
679 NET_BUF_HEAD\r
680 );\r
681 if (PacketHead == NULL) {\r
682 Status = EFI_OUT_OF_RESOURCES;\r
683 goto ON_EXIT;\r
684 }\r
685\r
68d3f2fb 686 CopyMem (PacketHead, *Head, sizeof (EFI_IP6_HEADER));\r
687 *Head = PacketHead;\r
a3bcde70
HT
688 Packet->Ip.Ip6 = PacketHead;\r
689\r
68d3f2fb 690 if (*ExtHdrs != NULL) {\r
a3bcde70 691 Buf = (UINT8 *) (PacketHead + 1);\r
68d3f2fb 692 CopyMem (Buf, *ExtHdrs, *ExtHdrsLen);\r
a3bcde70
HT
693 }\r
694\r
68d3f2fb 695 NetbufTrim (Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);\r
a3bcde70
HT
696 CopyMem (\r
697 IP6_GET_CLIP_INFO (Packet),\r
698 IP6_GET_CLIP_INFO (IpSecWrap->Packet),\r
699 sizeof (IP6_CLIP_INFO)\r
700 );\r
701 }\r
a3bcde70
HT
702 *Netbuf = Packet;\r
703 }\r
704\r
705ON_EXIT:\r
706 return Status;\r
707}\r
708\r
709/**\r
68d3f2fb 710 Pre-process the IPv6 packet. First validates the IPv6 packet, and\r
711 then reassembles packet if it is necessary.\r
712\r
713 @param[in] IpSb The IP6 service instance.\r
714 @param[in, out] Packet The received IP6 packet to be processed.\r
715 @param[in] Flag The link layer flag for the packet received, such\r
716 as multicast.\r
717 @param[out] Payload The pointer to the payload of the recieved packet. \r
718 it starts from the first byte of the extension header. \r
719 @param[out] LastHead The pointer of NextHeader of the last extension\r
720 header processed by IP6.\r
721 @param[out] ExtHdrsLen The length of the whole option.\r
722 @param[out] UnFragmentLen The length of unfragmented length of extension headers.\r
723 @param[out] Fragmented Indicate whether the packet is fragmented. \r
724 @param[out] Head The pointer to the EFI_IP6_Header.\r
725\r
726 @retval EFI_SUCCESS The received packet is well format.\r
727 @retval EFI_INVALID_PARAMETER The received packet is malformed.\r
a3bcde70
HT
728\r
729**/\r
68d3f2fb 730EFI_STATUS\r
731Ip6PreProcessPacket (\r
732 IN IP6_SERVICE *IpSb,\r
733 IN OUT NET_BUF **Packet,\r
734 IN UINT32 Flag,\r
735 OUT UINT8 **Payload,\r
736 OUT UINT8 **LastHead,\r
737 OUT UINT32 *ExtHdrsLen,\r
738 OUT UINT32 *UnFragmentLen,\r
739 OUT BOOLEAN *Fragmented, \r
740 OUT EFI_IP6_HEADER **Head\r
a3bcde70
HT
741 )\r
742{\r
a3bcde70 743 UINT16 PayloadLen;\r
a3bcde70 744 UINT16 TotalLen;\r
a3bcde70 745 UINT32 FormerHeadOffset;\r
a3bcde70 746 UINT32 HeadLen;\r
a3bcde70
HT
747 IP6_FRAGMENT_HEADER *FragmentHead;\r
748 UINT16 FragmentOffset;\r
68d3f2fb 749 IP6_CLIP_INFO *Info;\r
a3bcde70
HT
750 EFI_IPv6_ADDRESS Loopback;\r
751\r
68d3f2fb 752 HeadLen = 0;\r
753 PayloadLen = 0;\r
a3bcde70
HT
754 //\r
755 // Check whether the input packet is a valid packet\r
756 //\r
68d3f2fb 757 if ((*Packet)->TotalSize < IP6_MIN_HEADLEN) {\r
758 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
759 }\r
760\r
761 //\r
762 // Get header information of the packet.\r
763 //\r
68d3f2fb 764 *Head = (EFI_IP6_HEADER *) NetbufGetByte (*Packet, 0, NULL);\r
765 if (*Head == NULL) {\r
766 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
767 }\r
768\r
769 //\r
770 // Multicast addresses must not be used as source addresses in IPv6 packets.\r
771 //\r
68d3f2fb 772 if (((*Head)->Version != 6) || (IP6_IS_MULTICAST (&(*Head)->SourceAddress))) {\r
773 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
774 }\r
775\r
776 //\r
777 // A packet with a destination address of loopback ::1/128 or unspecified must be dropped.\r
778 //\r
779 ZeroMem (&Loopback, sizeof (EFI_IPv6_ADDRESS));\r
780 Loopback.Addr[15] = 0x1;\r
68d3f2fb 781 if ((CompareMem (&Loopback, &(*Head)->DestinationAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) ||\r
782 (NetIp6IsUnspecifiedAddr (&(*Head)->DestinationAddress))) {\r
783 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
784 }\r
785\r
786 //\r
787 // Convert the IP header to host byte order.\r
788 //\r
68d3f2fb 789 (*Packet)->Ip.Ip6 = Ip6NtohHead (*Head);\r
a3bcde70
HT
790\r
791 //\r
792 // Get the per packet info.\r
793 //\r
68d3f2fb 794 Info = IP6_GET_CLIP_INFO (*Packet);\r
a3bcde70
HT
795 Info->LinkFlag = Flag;\r
796 Info->CastType = 0;\r
797\r
798 if (IpSb->MnpConfigData.EnablePromiscuousReceive) {\r
799 Info->CastType = Ip6Promiscuous;\r
800 }\r
801\r
68d3f2fb 802 if (Ip6IsOneOfSetAddress (IpSb, &(*Head)->DestinationAddress, NULL, NULL)) {\r
a3bcde70 803 Info->CastType = Ip6Unicast;\r
68d3f2fb 804 } else if (IP6_IS_MULTICAST (&(*Head)->DestinationAddress)) {\r
805 if (Ip6FindMldEntry (IpSb, &(*Head)->DestinationAddress) != NULL) {\r
a3bcde70
HT
806 Info->CastType = Ip6Multicast;\r
807 }\r
808 }\r
809\r
810 //\r
811 // Drop the packet that is not delivered to us.\r
812 //\r
813 if (Info->CastType == 0) {\r
68d3f2fb 814 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
815 }\r
816\r
817\r
68d3f2fb 818 PayloadLen = (*Head)->PayloadLength;\r
a3bcde70
HT
819\r
820 Info->Start = 0;\r
821 Info->Length = PayloadLen;\r
822 Info->End = Info->Start + Info->Length;\r
823 Info->HeadLen = (UINT16) sizeof (EFI_IP6_HEADER);\r
824 Info->Status = EFI_SUCCESS;\r
825 Info->LastFrag = FALSE;\r
826\r
827 TotalLen = (UINT16) (PayloadLen + sizeof (EFI_IP6_HEADER));\r
828\r
829 //\r
830 // Mnp may deliver frame trailer sequence up, trim it off.\r
831 //\r
68d3f2fb 832 if (TotalLen < (*Packet)->TotalSize) {\r
833 NetbufTrim (*Packet, (*Packet)->TotalSize - TotalLen, FALSE);\r
a3bcde70
HT
834 }\r
835\r
68d3f2fb 836 if (TotalLen != (*Packet)->TotalSize) {\r
837 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
838 }\r
839\r
840 //\r
841 // Check the extension headers, if exist validate them\r
842 //\r
843 if (PayloadLen != 0) {\r
68d3f2fb 844 *Payload = AllocatePool ((UINTN) PayloadLen);\r
845 if (*Payload == NULL) {\r
846 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
847 }\r
848\r
68d3f2fb 849 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);\r
a3bcde70
HT
850 }\r
851\r
a3bcde70
HT
852 if (!Ip6IsExtsValid (\r
853 IpSb,\r
68d3f2fb 854 *Packet,\r
855 &(*Head)->NextHeader,\r
856 *Payload,\r
a3bcde70
HT
857 (UINT32) PayloadLen,\r
858 TRUE,\r
859 &FormerHeadOffset,\r
68d3f2fb 860 LastHead,\r
861 ExtHdrsLen,\r
862 UnFragmentLen,\r
863 Fragmented\r
a3bcde70 864 )) {\r
68d3f2fb 865 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
866 }\r
867\r
68d3f2fb 868 HeadLen = sizeof (EFI_IP6_HEADER) + *UnFragmentLen;\r
a3bcde70 869\r
68d3f2fb 870 if (*Fragmented) {\r
a3bcde70
HT
871 //\r
872 // Get the fragment offset from the Fragment header\r
873 //\r
68d3f2fb 874 FragmentHead = (IP6_FRAGMENT_HEADER *) NetbufGetByte (*Packet, HeadLen, NULL);\r
a3bcde70 875 if (FragmentHead == NULL) {\r
68d3f2fb 876 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
877 }\r
878\r
879 FragmentOffset = NTOHS (FragmentHead->FragmentOffset);\r
880\r
881 if ((FragmentOffset & 0x1) == 0) {\r
882 Info->LastFrag = TRUE;\r
883 }\r
884\r
885 FragmentOffset &= (~0x1);\r
886\r
887 //\r
888 // This is the first fragment of the packet\r
889 //\r
890 if (FragmentOffset == 0) {\r
891 Info->NextHeader = FragmentHead->NextHeader;\r
892 }\r
893\r
894 Info->HeadLen = (UINT16) HeadLen;\r
895 HeadLen += sizeof (IP6_FRAGMENT_HEADER);\r
896 Info->Start = FragmentOffset;\r
897 Info->Length = TotalLen - (UINT16) HeadLen;\r
898 Info->End = Info->Start + Info->Length;\r
899 Info->Id = FragmentHead->Identification;\r
900 Info->FormerNextHeader = FormerHeadOffset;\r
901\r
902 //\r
903 // Fragments should in the unit of 8 octets long except the last one.\r
904 //\r
905 if ((Info->LastFrag == 0) && (Info->Length % 8 != 0)) {\r
68d3f2fb 906 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
907 }\r
908\r
909 //\r
910 // Reassemble the packet.\r
911 //\r
68d3f2fb 912 *Packet = Ip6Reassemble (&IpSb->Assemble, *Packet);\r
913 if (*Packet == NULL) {\r
914 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
915 }\r
916\r
917 //\r
918 // Re-check the assembled packet to get the right values.\r
919 //\r
68d3f2fb 920 *Head = (*Packet)->Ip.Ip6;\r
921 PayloadLen = (*Head)->PayloadLength;\r
a3bcde70 922 if (PayloadLen != 0) {\r
68d3f2fb 923 if (*Payload != NULL) {\r
924 FreePool (*Payload);\r
a3bcde70
HT
925 }\r
926\r
68d3f2fb 927 *Payload = AllocatePool ((UINTN) PayloadLen);\r
928 if (*Payload == NULL) {\r
929 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
930 }\r
931\r
68d3f2fb 932 NetbufCopy (*Packet, sizeof (EFI_IP6_HEADER), PayloadLen, *Payload);\r
a3bcde70
HT
933 }\r
934\r
935 if (!Ip6IsExtsValid (\r
936 IpSb,\r
68d3f2fb 937 *Packet,\r
938 &(*Head)->NextHeader,\r
939 *Payload,\r
a3bcde70
HT
940 (UINT32) PayloadLen,\r
941 TRUE,\r
942 NULL,\r
68d3f2fb 943 LastHead,\r
944 ExtHdrsLen,\r
945 UnFragmentLen,\r
946 Fragmented\r
a3bcde70 947 )) {\r
68d3f2fb 948 return EFI_INVALID_PARAMETER;\r
a3bcde70
HT
949 }\r
950 }\r
951\r
952 //\r
953 // Trim the head off, after this point, the packet is headless.\r
954 // and Packet->TotalLen == Info->Length.\r
955 //\r
68d3f2fb 956 NetbufTrim (*Packet, sizeof (EFI_IP6_HEADER) + *ExtHdrsLen, TRUE);\r
957 \r
958 return EFI_SUCCESS;\r
959}\r
960\r
961/**\r
962 The IP6 input routine. It is called by the IP6_INTERFACE when an\r
963 IP6 fragment is received from MNP.\r
964\r
965 @param[in] Packet The IP6 packet received.\r
966 @param[in] IoStatus The return status of receive request.\r
967 @param[in] Flag The link layer flag for the packet received, such\r
968 as multicast.\r
969 @param[in] Context The IP6 service instance that owns the MNP.\r
a3bcde70 970\r
68d3f2fb 971**/\r
972VOID\r
973Ip6AcceptFrame (\r
974 IN NET_BUF *Packet,\r
975 IN EFI_STATUS IoStatus,\r
976 IN UINT32 Flag,\r
977 IN VOID *Context\r
978 )\r
979{\r
980 IP6_SERVICE *IpSb;\r
981 EFI_IP6_HEADER *Head;\r
982 UINT8 *Payload;\r
983 UINT8 *LastHead;\r
984 UINT32 UnFragmentLen;\r
985 UINT32 ExtHdrsLen;\r
986 BOOLEAN Fragmented;\r
987 EFI_STATUS Status;\r
988 EFI_IP6_HEADER ZeroHead;\r
989\r
990 IpSb = (IP6_SERVICE *) Context;\r
991 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
992\r
993 Payload = NULL;\r
994 LastHead = NULL;\r
995\r
996 //\r
997 // Check input parameters\r
998 //\r
999 if (EFI_ERROR (IoStatus) || (IpSb->State == IP6_SERVICE_DESTROY)) {\r
1000 goto Drop;\r
1001 }\r
1002 \r
1003 //\r
1004 // Pre-Process the Ipv6 Packet and then reassemble if it is necessary.\r
1005 //\r
1006 Status = Ip6PreProcessPacket (\r
1007 IpSb, \r
1008 &Packet, \r
1009 Flag, \r
1010 &Payload, \r
1011 &LastHead, \r
1012 &ExtHdrsLen, \r
1013 &UnFragmentLen, \r
1014 &Fragmented,\r
1015 &Head\r
1016 );\r
1017 if (EFI_ERROR (Status)) {\r
1018 goto Restart;\r
1019 }\r
a3bcde70
HT
1020 //\r
1021 // After trim off, the packet is a esp/ah/udp/tcp/icmp6 net buffer,\r
1022 // and no need consider any other ahead ext headers.\r
1023 //\r
1024 Status = Ip6IpSecProcessPacket (\r
1025 IpSb,\r
68d3f2fb 1026 &Head,\r
a3bcde70
HT
1027 LastHead, // need get the lasthead value for input\r
1028 &Packet,\r
68d3f2fb 1029 &Payload,\r
1030 &ExtHdrsLen,\r
a3bcde70
HT
1031 EfiIPsecInBound,\r
1032 NULL\r
1033 );\r
1034\r
68d3f2fb 1035 if (EFI_ERROR (Status)) {\r
a3bcde70
HT
1036 goto Restart;\r
1037 }\r
1038\r
1039 //\r
68d3f2fb 1040 // If the packet is protected by IPsec Tunnel Mode, Check the Inner Ip Packet.\r
a3bcde70 1041 //\r
68d3f2fb 1042 ZeroMem (&ZeroHead, sizeof (EFI_IP6_HEADER));\r
1043 if (0 == CompareMem (Head, &ZeroHead, sizeof (EFI_IP6_HEADER))) {\r
1044 Status = Ip6PreProcessPacket (\r
1045 IpSb, \r
1046 &Packet, \r
1047 Flag, \r
1048 &Payload, \r
1049 &LastHead, \r
1050 &ExtHdrsLen, \r
1051 &UnFragmentLen, \r
1052 &Fragmented, \r
1053 &Head\r
1054 );\r
1055 if (EFI_ERROR (Status)) {\r
1056 goto Restart;\r
1057 }\r
1058 }\r
a3bcde70 1059\r
90e529e2 1060 //\r
1061 // Check the Packet again.\r
1062 //\r
1063 if (Packet == NULL) {\r
1064 goto Restart;\r
1065 }\r
1066 \r
a3bcde70
HT
1067 //\r
1068 // Packet may have been changed. The ownership of the packet\r
1069 // is transfered to the packet process logic.\r
1070 //\r
1071 Head = Packet->Ip.Ip6;\r
1072 IP6_GET_CLIP_INFO (Packet)->Status = EFI_SUCCESS;\r
1073\r
1074 switch (*LastHead) {\r
1075 case IP6_ICMP:\r
1076 Ip6IcmpHandle (IpSb, Head, Packet);\r
1077 break;\r
1078 default:\r
1079 Ip6Demultiplex (IpSb, Head, Packet);\r
1080 }\r
1081\r
1082 Packet = NULL;\r
1083\r
1084 //\r
1085 // Dispatch the DPCs queued by the NotifyFunction of the rx token's events\r
1086 // which are signaled with received data.\r
1087 //\r
1088 DispatchDpc ();\r
1089\r
1090Restart:\r
1091 if (Payload != NULL) {\r
1092 FreePool (Payload);\r
1093 }\r
1094\r
1095 Ip6ReceiveFrame (Ip6AcceptFrame, IpSb);\r
1096\r
1097Drop:\r
1098 if (Packet != NULL) {\r
1099 NetbufFree (Packet);\r
1100 }\r
1101\r
1102 return ;\r
1103}\r
1104\r
1105/**\r
1106 Initialize an already allocated assemble table. This is generally\r
1107 the assemble table embedded in the IP6 service instance.\r
1108\r
1109 @param[in, out] Table The assemble table to initialize.\r
1110\r
1111**/\r
1112VOID\r
1113Ip6CreateAssembleTable (\r
1114 IN OUT IP6_ASSEMBLE_TABLE *Table\r
1115 )\r
1116{\r
1117 UINT32 Index;\r
1118\r
1119 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1120 InitializeListHead (&Table->Bucket[Index]);\r
1121 }\r
1122}\r
1123\r
1124/**\r
1125 Clean up the assemble table by removing all of the fragments\r
1126 and assemble entries.\r
1127\r
1128 @param[in, out] Table The assemble table to clean up.\r
1129\r
1130**/\r
1131VOID\r
1132Ip6CleanAssembleTable (\r
1133 IN OUT IP6_ASSEMBLE_TABLE *Table\r
1134 )\r
1135{\r
1136 LIST_ENTRY *Entry;\r
1137 LIST_ENTRY *Next;\r
1138 IP6_ASSEMBLE_ENTRY *Assemble;\r
1139 UINT32 Index;\r
1140\r
1141 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1142 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Table->Bucket[Index]) {\r
1143 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);\r
1144\r
1145 RemoveEntryList (Entry);\r
1146 Ip6FreeAssembleEntry (Assemble);\r
1147 }\r
1148 }\r
1149}\r
1150\r
1151\r
1152/**\r
1153 The signal handle of IP6's recycle event. It is called back\r
1154 when the upper layer releases the packet.\r
1155\r
1156 @param[in] Event The IP6's recycle event.\r
1157 @param[in] Context The context of the handle, which is a IP6_RXDATA_WRAP.\r
1158\r
1159**/\r
1160VOID\r
1161EFIAPI\r
1162Ip6OnRecyclePacket (\r
1163 IN EFI_EVENT Event,\r
1164 IN VOID *Context\r
1165 )\r
1166{\r
1167 IP6_RXDATA_WRAP *Wrap;\r
1168\r
1169 Wrap = (IP6_RXDATA_WRAP *) Context;\r
1170\r
1171 EfiAcquireLockOrFail (&Wrap->IpInstance->RecycleLock);\r
1172 RemoveEntryList (&Wrap->Link);\r
1173 EfiReleaseLock (&Wrap->IpInstance->RecycleLock);\r
1174\r
1175 ASSERT (!NET_BUF_SHARED (Wrap->Packet));\r
1176 NetbufFree (Wrap->Packet);\r
1177\r
1178 gBS->CloseEvent (Wrap->RxData.RecycleSignal);\r
1179 FreePool (Wrap);\r
1180}\r
1181\r
1182/**\r
1183 Wrap the received packet to a IP6_RXDATA_WRAP, which will be\r
1184 delivered to the upper layer. Each IP6 child that accepts the\r
1185 packet will get a not-shared copy of the packet which is wrapped\r
1186 in the IP6_RXDATA_WRAP. The IP6_RXDATA_WRAP->RxData is passed\r
1187 to the upper layer. The upper layer will signal the recycle event in\r
1188 it when it is done with the packet.\r
1189\r
1190 @param[in] IpInstance The IP6 child to receive the packet.\r
1191 @param[in] Packet The packet to deliver up.\r
1192\r
1193 @return NULL if it failed to wrap the packet; otherwise, the wrapper.\r
1194\r
1195**/\r
1196IP6_RXDATA_WRAP *\r
1197Ip6WrapRxData (\r
1198 IN IP6_PROTOCOL *IpInstance,\r
1199 IN NET_BUF *Packet\r
1200 )\r
1201{\r
1202 IP6_RXDATA_WRAP *Wrap;\r
1203 EFI_IP6_RECEIVE_DATA *RxData;\r
1204 EFI_STATUS Status;\r
1205\r
1206 Wrap = AllocatePool (IP6_RXDATA_WRAP_SIZE (Packet->BlockOpNum));\r
1207\r
1208 if (Wrap == NULL) {\r
1209 return NULL;\r
1210 }\r
1211\r
1212 InitializeListHead (&Wrap->Link);\r
1213\r
1214 Wrap->IpInstance = IpInstance;\r
1215 Wrap->Packet = Packet;\r
1216 RxData = &Wrap->RxData;\r
1217\r
1218 ZeroMem (&RxData->TimeStamp, sizeof (EFI_TIME));\r
1219\r
1220 Status = gBS->CreateEvent (\r
1221 EVT_NOTIFY_SIGNAL,\r
1222 TPL_NOTIFY,\r
1223 Ip6OnRecyclePacket,\r
1224 Wrap,\r
1225 &RxData->RecycleSignal\r
1226 );\r
1227\r
1228 if (EFI_ERROR (Status)) {\r
1229 FreePool (Wrap);\r
1230 return NULL;\r
1231 }\r
1232\r
1233 ASSERT (Packet->Ip.Ip6 != NULL);\r
1234\r
1235 //\r
1236 // The application expects a network byte order header.\r
1237 //\r
1238 RxData->HeaderLength = sizeof (EFI_IP6_HEADER);\r
1239 RxData->Header = (EFI_IP6_HEADER *) Ip6NtohHead (Packet->Ip.Ip6);\r
1240 RxData->DataLength = Packet->TotalSize;\r
1241\r
1242 //\r
1243 // Build the fragment table to be delivered up.\r
1244 //\r
1245 RxData->FragmentCount = Packet->BlockOpNum;\r
1246 NetbufBuildExt (Packet, (NET_FRAGMENT *) RxData->FragmentTable, &RxData->FragmentCount);\r
1247\r
1248 return Wrap;\r
1249}\r
1250\r
1251/**\r
1252 Check whether this IP child accepts the packet.\r
1253\r
1254 @param[in] IpInstance The IP child to check.\r
1255 @param[in] Head The IP header of the packet.\r
1256 @param[in] Packet The data of the packet.\r
1257\r
1258 @retval TRUE The child wants to receive the packet.\r
1259 @retval FALSE The child does not want to receive the packet.\r
1260\r
1261**/\r
1262BOOLEAN\r
1263Ip6InstanceFrameAcceptable (\r
1264 IN IP6_PROTOCOL *IpInstance,\r
1265 IN EFI_IP6_HEADER *Head,\r
1266 IN NET_BUF *Packet\r
1267 )\r
1268{\r
1269 IP6_ICMP_ERROR_HEAD Icmp;\r
1270 EFI_IP6_CONFIG_DATA *Config;\r
1271 IP6_CLIP_INFO *Info;\r
1272 UINT8 *Proto;\r
1273 UINT32 Index;\r
1274 UINT8 *ExtHdrs;\r
1275 UINT16 ErrMsgPayloadLen;\r
1276 UINT8 *ErrMsgPayload;\r
1277\r
1278 Config = &IpInstance->ConfigData;\r
1279 Proto = NULL;\r
1280\r
1281 //\r
1282 // Dirty trick for the Tiano UEFI network stack implmentation. If\r
1283 // ReceiveTimeout == -1, the receive of the packet for this instance\r
1284 // is disabled. The UEFI spec don't have such captibility. We add\r
1285 // this to improve the performance because IP will make a copy of\r
1286 // the received packet for each accepting instance. Some IP instances\r
1287 // used by UDP/TCP only send packets, they don't wants to receive.\r
1288 //\r
1289 if (Config->ReceiveTimeout == (UINT32)(-1)) {\r
1290 return FALSE;\r
1291 }\r
1292\r
1293 if (Config->AcceptPromiscuous) {\r
1294 return TRUE;\r
1295 }\r
1296\r
1297 //\r
1298 // Check whether the protocol is acceptable.\r
1299 //\r
1300 ExtHdrs = NetbufGetByte (Packet, 0, NULL);\r
1301\r
1302 if (!Ip6IsExtsValid (\r
1303 IpInstance->Service,\r
1304 Packet,\r
1305 &Head->NextHeader,\r
1306 ExtHdrs,\r
1307 (UINT32) Head->PayloadLength,\r
1308 TRUE,\r
1309 NULL,\r
1310 &Proto,\r
1311 NULL,\r
1312 NULL,\r
1313 NULL\r
1314 )) {\r
1315 return FALSE;\r
1316 }\r
1317\r
1318 //\r
1319 // The upper layer driver may want to receive the ICMPv6 error packet\r
1320 // invoked by its packet, like UDP.\r
1321 //\r
1322 if ((*Proto == IP6_ICMP) && (!Config->AcceptAnyProtocol) && (*Proto != Config->DefaultProtocol)) {\r
1323 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
1324\r
1325 if (Icmp.Head.Type <= ICMP_V6_ERROR_MAX) {\r
1326 if (!Config->AcceptIcmpErrors) {\r
1327 return FALSE;\r
1328 }\r
1329\r
1330 //\r
1331 // Get the protocol of the invoking packet of ICMPv6 error packet.\r
1332 //\r
1333 ErrMsgPayloadLen = NTOHS (Icmp.IpHead.PayloadLength);\r
1334 ErrMsgPayload = NetbufGetByte (Packet, sizeof (Icmp), NULL);\r
1335\r
1336 if (!Ip6IsExtsValid (\r
1337 NULL,\r
1338 NULL,\r
1339 &Icmp.IpHead.NextHeader,\r
1340 ErrMsgPayload,\r
1341 ErrMsgPayloadLen,\r
1342 TRUE,\r
1343 NULL,\r
1344 &Proto,\r
1345 NULL,\r
1346 NULL,\r
1347 NULL\r
1348 )) {\r
1349 return FALSE;\r
1350 }\r
1351 }\r
1352 }\r
1353\r
1354 //\r
1355 // Match the protocol\r
1356 //\r
1357 if (!Config->AcceptAnyProtocol && (*Proto != Config->DefaultProtocol)) {\r
1358 return FALSE;\r
1359 }\r
1360\r
1361 //\r
1362 // Check for broadcast, the caller has computed the packet's\r
1363 // cast type for this child's interface.\r
1364 //\r
1365 Info = IP6_GET_CLIP_INFO (Packet);\r
1366\r
1367 //\r
1368 // If it is a multicast packet, check whether we are in the group.\r
1369 //\r
1370 if (Info->CastType == Ip6Multicast) {\r
1371 //\r
1372 // Receive the multicast if the instance wants to receive all packets.\r
1373 //\r
1374 if (NetIp6IsUnspecifiedAddr (&IpInstance->ConfigData.StationAddress)) {\r
1375 return TRUE;\r
1376 }\r
1377\r
1378 for (Index = 0; Index < IpInstance->GroupCount; Index++) {\r
1379 if (EFI_IP6_EQUAL (IpInstance->GroupList + Index, &Head->DestinationAddress)) {\r
1380 break;\r
1381 }\r
1382 }\r
1383\r
1384 return (BOOLEAN)(Index < IpInstance->GroupCount);\r
1385 }\r
1386\r
1387 return TRUE;\r
1388}\r
1389\r
1390/**\r
1391 Enqueue a shared copy of the packet to the IP6 child if the\r
1392 packet is acceptable to it. Here the data of the packet is\r
1393 shared, but the net buffer isn't.\r
1394\r
1395 @param IpInstance The IP6 child to enqueue the packet to.\r
1396 @param Head The IP header of the received packet.\r
1397 @param Packet The data of the received packet.\r
1398\r
1399 @retval EFI_NOT_STARTED The IP child hasn't been configured.\r
1400 @retval EFI_INVALID_PARAMETER The child doesn't want to receive the packet.\r
1401 @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources\r
1402 @retval EFI_SUCCESS A shared copy the packet is enqueued to the child.\r
1403\r
1404**/\r
1405EFI_STATUS\r
1406Ip6InstanceEnquePacket (\r
1407 IN IP6_PROTOCOL *IpInstance,\r
1408 IN EFI_IP6_HEADER *Head,\r
1409 IN NET_BUF *Packet\r
1410 )\r
1411{\r
1412 IP6_CLIP_INFO *Info;\r
1413 NET_BUF *Clone;\r
1414\r
1415 //\r
1416 // Check whether the packet is acceptable to this instance.\r
1417 //\r
1418 if (IpInstance->State != IP6_STATE_CONFIGED) {\r
1419 return EFI_NOT_STARTED;\r
1420 }\r
1421\r
1422 if (!Ip6InstanceFrameAcceptable (IpInstance, Head, Packet)) {\r
1423 return EFI_INVALID_PARAMETER;\r
1424 }\r
1425\r
1426 //\r
1427 // Enque a shared copy of the packet.\r
1428 //\r
1429 Clone = NetbufClone (Packet);\r
1430\r
1431 if (Clone == NULL) {\r
1432 return EFI_OUT_OF_RESOURCES;\r
1433 }\r
1434\r
1435 //\r
1436 // Set the receive time out for the assembled packet. If it expires,\r
1437 // packet will be removed from the queue.\r
1438 //\r
1439 Info = IP6_GET_CLIP_INFO (Clone);\r
1440 Info->Life = IP6_US_TO_SEC (IpInstance->ConfigData.ReceiveTimeout);\r
1441\r
1442 InsertTailList (&IpInstance->Received, &Clone->List);\r
1443 return EFI_SUCCESS;\r
1444}\r
1445\r
1446/**\r
1447 Deliver the received packets to the upper layer if there are both received\r
1448 requests and enqueued packets. If the enqueued packet is shared, it will\r
1449 duplicate it to a non-shared packet, release the shared packet, then\r
1450 deliver the non-shared packet up.\r
1451\r
1452 @param[in] IpInstance The IP child to deliver the packet up.\r
1453\r
1454 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to deliver the\r
1455 packets.\r
1456 @retval EFI_SUCCESS All the enqueued packets that can be delivered\r
1457 are delivered up.\r
1458\r
1459**/\r
1460EFI_STATUS\r
1461Ip6InstanceDeliverPacket (\r
1462 IN IP6_PROTOCOL *IpInstance\r
1463 )\r
1464{\r
1465 EFI_IP6_COMPLETION_TOKEN *Token;\r
1466 IP6_RXDATA_WRAP *Wrap;\r
1467 NET_BUF *Packet;\r
1468 NET_BUF *Dup;\r
1469 UINT8 *Head;\r
1470\r
1471 //\r
1472 // Deliver a packet if there are both a packet and a receive token.\r
1473 //\r
1474 while (!IsListEmpty (&IpInstance->Received) && !NetMapIsEmpty (&IpInstance->RxTokens)) {\r
1475\r
1476 Packet = NET_LIST_HEAD (&IpInstance->Received, NET_BUF, List);\r
1477\r
1478 if (!NET_BUF_SHARED (Packet)) {\r
1479 //\r
1480 // If this is the only instance that wants the packet, wrap it up.\r
1481 //\r
1482 Wrap = Ip6WrapRxData (IpInstance, Packet);\r
1483\r
1484 if (Wrap == NULL) {\r
1485 return EFI_OUT_OF_RESOURCES;\r
1486 }\r
1487\r
1488 RemoveEntryList (&Packet->List);\r
1489\r
1490 } else {\r
1491 //\r
1492 // Create a duplicated packet if this packet is shared\r
1493 //\r
1494 Dup = NetbufDuplicate (Packet, NULL, sizeof (EFI_IP6_HEADER));\r
1495\r
1496 if (Dup == NULL) {\r
1497 return EFI_OUT_OF_RESOURCES;\r
1498 }\r
1499\r
1500 //\r
1501 // Copy the IP head over. The packet to deliver up is\r
1502 // headless. Trim the head off after copy. The IP head\r
1503 // may be not continuous before the data.\r
1504 //\r
1505 Head = NetbufAllocSpace (Dup, sizeof (EFI_IP6_HEADER), NET_BUF_HEAD);\r
1506 ASSERT (Head != NULL);\r
1507 Dup->Ip.Ip6 = (EFI_IP6_HEADER *) Head;\r
1508\r
1509 CopyMem (Head, Packet->Ip.Ip6, sizeof (EFI_IP6_HEADER));\r
1510 NetbufTrim (Dup, sizeof (EFI_IP6_HEADER), TRUE);\r
1511\r
1512 Wrap = Ip6WrapRxData (IpInstance, Dup);\r
1513\r
1514 if (Wrap == NULL) {\r
1515 NetbufFree (Dup);\r
1516 return EFI_OUT_OF_RESOURCES;\r
1517 }\r
1518\r
1519 RemoveEntryList (&Packet->List);\r
1520 NetbufFree (Packet);\r
1521\r
1522 Packet = Dup;\r
1523 }\r
1524\r
1525 //\r
1526 // Insert it into the delivered packet, then get a user's\r
1527 // receive token, pass the wrapped packet up.\r
1528 //\r
1529 EfiAcquireLockOrFail (&IpInstance->RecycleLock);\r
1530 InsertHeadList (&IpInstance->Delivered, &Wrap->Link);\r
1531 EfiReleaseLock (&IpInstance->RecycleLock);\r
1532\r
1533 Token = NetMapRemoveHead (&IpInstance->RxTokens, NULL);\r
1534 Token->Status = IP6_GET_CLIP_INFO (Packet)->Status;\r
1535 Token->Packet.RxData = &Wrap->RxData;\r
1536\r
1537 gBS->SignalEvent (Token->Event);\r
1538 }\r
1539\r
1540 return EFI_SUCCESS;\r
1541}\r
1542\r
1543/**\r
1544 Enqueue a received packet to all the IP children that share\r
1545 the same interface.\r
1546\r
1547 @param[in] IpSb The IP6 service instance that receive the packet.\r
1548 @param[in] Head The header of the received packet.\r
1549 @param[in] Packet The data of the received packet.\r
1550 @param[in] IpIf The interface to enqueue the packet to.\r
1551\r
1552 @return The number of the IP6 children that accepts the packet.\r
1553\r
1554**/\r
1555INTN\r
1556Ip6InterfaceEnquePacket (\r
1557 IN IP6_SERVICE *IpSb,\r
1558 IN EFI_IP6_HEADER *Head,\r
1559 IN NET_BUF *Packet,\r
1560 IN IP6_INTERFACE *IpIf\r
1561 )\r
1562{\r
1563 IP6_PROTOCOL *IpInstance;\r
1564 IP6_CLIP_INFO *Info;\r
1565 LIST_ENTRY *Entry;\r
1566 INTN Enqueued;\r
1567 INTN LocalType;\r
1568 INTN SavedType;\r
1569\r
1570 //\r
1571 // First, check that the packet is acceptable to this interface\r
1572 // and find the local cast type for the interface.\r
1573 //\r
1574 LocalType = 0;\r
1575 Info = IP6_GET_CLIP_INFO (Packet);\r
1576\r
1577 if (IpIf->PromiscRecv) {\r
1578 LocalType = Ip6Promiscuous;\r
1579 } else {\r
1580 LocalType = Info->CastType;\r
1581 }\r
1582\r
1583 //\r
1584 // Iterate through the ip instances on the interface, enqueue\r
1585 // the packet if filter passed. Save the original cast type,\r
1586 // and pass the local cast type to the IP children on the\r
1587 // interface. The global cast type will be restored later.\r
1588 //\r
1589 SavedType = Info->CastType;\r
1590 Info->CastType = (UINT32) LocalType;\r
1591\r
1592 Enqueued = 0;\r
1593\r
1594 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1595 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);\r
1596 NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);\r
1597\r
1598 if (Ip6InstanceEnquePacket (IpInstance, Head, Packet) == EFI_SUCCESS) {\r
1599 Enqueued++;\r
1600 }\r
1601 }\r
1602\r
1603 Info->CastType = (UINT32) SavedType;\r
1604 return Enqueued;\r
1605}\r
1606\r
1607/**\r
1608 Deliver the packet for each IP6 child on the interface.\r
1609\r
1610 @param[in] IpSb The IP6 service instance that received the packet.\r
1611 @param[in] IpIf The IP6 interface to deliver the packet.\r
1612\r
1613**/\r
1614VOID\r
1615Ip6InterfaceDeliverPacket (\r
1616 IN IP6_SERVICE *IpSb,\r
1617 IN IP6_INTERFACE *IpIf\r
1618 )\r
1619{\r
1620 IP6_PROTOCOL *IpInstance;\r
1621 LIST_ENTRY *Entry;\r
1622\r
1623 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
1624 IpInstance = NET_LIST_USER_STRUCT (Entry, IP6_PROTOCOL, AddrLink);\r
1625 Ip6InstanceDeliverPacket (IpInstance);\r
1626 }\r
1627}\r
1628\r
1629/**\r
1630 De-multiplex the packet. the packet delivery is processed in two\r
1631 passes. The first pass will enqueue a shared copy of the packet\r
1632 to each IP6 child that accepts the packet. The second pass will\r
1633 deliver a non-shared copy of the packet to each IP6 child that\r
1634 has pending receive requests. Data is copied if more than one\r
1635 child wants to consume the packet, because each IP child needs\r
1636 its own copy of the packet to make changes.\r
1637\r
1638 @param[in] IpSb The IP6 service instance that received the packet.\r
1639 @param[in] Head The header of the received packet.\r
1640 @param[in] Packet The data of the received packet.\r
1641\r
1642 @retval EFI_NOT_FOUND No IP child accepts the packet.\r
1643 @retval EFI_SUCCESS The packet is enqueued or delivered to some IP\r
1644 children.\r
1645\r
1646**/\r
1647EFI_STATUS\r
1648Ip6Demultiplex (\r
1649 IN IP6_SERVICE *IpSb,\r
1650 IN EFI_IP6_HEADER *Head,\r
1651 IN NET_BUF *Packet\r
1652 )\r
1653{\r
1654\r
1655 LIST_ENTRY *Entry;\r
1656 IP6_INTERFACE *IpIf;\r
1657 INTN Enqueued;\r
1658\r
1659 //\r
1660 // Two pass delivery: first, enque a shared copy of the packet\r
1661 // to each instance that accept the packet.\r
1662 //\r
1663 Enqueued = 0;\r
1664\r
1665 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
1666 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);\r
1667\r
1668 if (IpIf->Configured) {\r
1669 Enqueued += Ip6InterfaceEnquePacket (IpSb, Head, Packet, IpIf);\r
1670 }\r
1671 }\r
1672\r
1673 //\r
1674 // Second: deliver a duplicate of the packet to each instance.\r
1675 // Release the local reference first, so that the last instance\r
1676 // getting the packet will not copy the data.\r
1677 //\r
1678 NetbufFree (Packet);\r
1679 Packet = NULL;\r
1680\r
1681 if (Enqueued == 0) {\r
1682 return EFI_NOT_FOUND;\r
1683 }\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 Ip6InterfaceDeliverPacket (IpSb, IpIf);\r
1690 }\r
1691 }\r
1692\r
1693 return EFI_SUCCESS;\r
1694}\r
1695\r
1696/**\r
1697 Decrease the life of the transmitted packets. If it is\r
1698 decreased to zero, cancel the packet. This function is\r
1699 called by Ip6packetTimerTicking that provides timeout for both the\r
1700 received-but-not-delivered and transmitted-but-not-recycle\r
1701 packets.\r
1702\r
1703 @param[in] Map The IP6 child's transmit map.\r
1704 @param[in] Item Current transmitted packet.\r
1705 @param[in] Context Not used.\r
1706\r
1707 @retval EFI_SUCCESS Always returns EFI_SUCCESS.\r
1708\r
1709**/\r
1710EFI_STATUS\r
1711EFIAPI\r
1712Ip6SentPacketTicking (\r
1713 IN NET_MAP *Map,\r
1714 IN NET_MAP_ITEM *Item,\r
1715 IN VOID *Context\r
1716 )\r
1717{\r
1718 IP6_TXTOKEN_WRAP *Wrap;\r
1719\r
1720 Wrap = (IP6_TXTOKEN_WRAP *) Item->Value;\r
1721 ASSERT (Wrap != NULL);\r
1722\r
1723 if ((Wrap->Life > 0) && (--Wrap->Life == 0)) {\r
1724 Ip6CancelPacket (Wrap->IpInstance->Interface, Wrap->Packet, EFI_ABORTED);\r
1725 }\r
1726\r
1727 return EFI_SUCCESS;\r
1728}\r
1729\r
1730/**\r
1731 Timeout the fragments, and the enqueued, and transmitted packets.\r
1732\r
1733 @param[in] IpSb The IP6 service instance to timeout.\r
1734\r
1735**/\r
1736VOID\r
1737Ip6PacketTimerTicking (\r
1738 IN IP6_SERVICE *IpSb\r
1739 )\r
1740{\r
1741 LIST_ENTRY *InstanceEntry;\r
1742 LIST_ENTRY *Entry;\r
1743 LIST_ENTRY *Next;\r
1744 IP6_PROTOCOL *IpInstance;\r
1745 IP6_ASSEMBLE_ENTRY *Assemble;\r
1746 NET_BUF *Packet;\r
1747 IP6_CLIP_INFO *Info;\r
1748 UINT32 Index;\r
1749\r
1750 //\r
1751 // First, time out the fragments. The packet's life is counting down\r
1752 // once the first-arriving fragment of that packet was received.\r
1753 //\r
1754 for (Index = 0; Index < IP6_ASSEMLE_HASH_SIZE; Index++) {\r
1755 NET_LIST_FOR_EACH_SAFE (Entry, Next, &(IpSb->Assemble.Bucket[Index])) {\r
1756 Assemble = NET_LIST_USER_STRUCT (Entry, IP6_ASSEMBLE_ENTRY, Link);\r
1757\r
1758 if ((Assemble->Life > 0) && (--Assemble->Life == 0)) {\r
1759 //\r
1760 // If the first fragment (the one with a Fragment Offset of zero)\r
1761 // has been received, an ICMP Time Exceeded - Fragment Reassembly\r
1762 // Time Exceeded message should be sent to the source of that fragment.\r
1763 //\r
1764 if ((Assemble->Packet != NULL) &&\r
1765 !IP6_IS_MULTICAST (&Assemble->Head->DestinationAddress)) {\r
1766 Ip6SendIcmpError (\r
1767 IpSb,\r
1768 Assemble->Packet,\r
1769 NULL,\r
1770 &Assemble->Head->SourceAddress,\r
1771 ICMP_V6_TIME_EXCEEDED,\r
1772 ICMP_V6_TIMEOUT_REASSEMBLE,\r
1773 NULL\r
1774 );\r
1775 }\r
1776\r
1777 //\r
1778 // If reassembly of a packet is not completed within 60 seconds of\r
1779 // the reception of the first-arriving fragment of that packet, the\r
1780 // reassembly must be abandoned and all the fragments that have been\r
1781 // received for that packet must be discarded.\r
1782 //\r
1783 RemoveEntryList (Entry);\r
1784 Ip6FreeAssembleEntry (Assemble);\r
1785 }\r
1786 }\r
1787 }\r
1788\r
1789 NET_LIST_FOR_EACH (InstanceEntry, &IpSb->Children) {\r
1790 IpInstance = NET_LIST_USER_STRUCT (InstanceEntry, IP6_PROTOCOL, Link);\r
1791\r
1792 //\r
1793 // Second, time out the assembled packets enqueued on each IP child.\r
1794 //\r
1795 NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpInstance->Received) {\r
1796 Packet = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);\r
1797 Info = IP6_GET_CLIP_INFO (Packet);\r
1798\r
1799 if ((Info->Life > 0) && (--Info->Life == 0)) {\r
1800 RemoveEntryList (Entry);\r
1801 NetbufFree (Packet);\r
1802 }\r
1803 }\r
1804\r
1805 //\r
1806 // Third: time out the transmitted packets.\r
1807 //\r
1808 NetMapIterate (&IpInstance->TxTokens, Ip6SentPacketTicking, NULL);\r
1809 }\r
1810}\r
1811\r