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