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