VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/Ip6Dxe/Ip6Input.c@ 77662

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette