]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Output.c
Fix the comments to follow UEFI Spec regarding how to check an EFI_HANDLE is valid...
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Output.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The internal functions and routines to transmit the IP6 packet.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php.\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Ip6Impl.h"\r
17\r
18UINT32 mIp6Id;\r
19\r
20/**\r
21 Output all the available source addresses to a list entry head SourceList. The\r
22 number of source addresses are also returned.\r
23\r
24 @param[in] IpSb Points to an IP6 service binding instance.\r
25 @param[out] SourceList The list entry head of all source addresses.\r
26 It is the caller's responsiblity to free the\r
27 resources.\r
28 @param[out] SourceCount The number of source addresses.\r
29\r
30 @retval EFI_SUCCESS The source addresses were copied to a list entry head\r
31 SourceList.\r
32 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
33\r
34**/\r
35EFI_STATUS\r
36Ip6CandidateSource (\r
37 IN IP6_SERVICE *IpSb,\r
38 OUT LIST_ENTRY *SourceList,\r
39 OUT UINT32 *SourceCount\r
40 )\r
41{\r
42 IP6_INTERFACE *IpIf;\r
43 LIST_ENTRY *Entry;\r
44 LIST_ENTRY *Entry2;\r
45 IP6_ADDRESS_INFO *AddrInfo;\r
46 IP6_ADDRESS_INFO *Copy;\r
47\r
48 *SourceCount = 0;\r
49\r
50 if (IpSb->LinkLocalOk) {\r
51 Copy = AllocatePool (sizeof (IP6_ADDRESS_INFO));\r
52 if (Copy == NULL) {\r
53 return EFI_OUT_OF_RESOURCES;\r
54 }\r
55\r
56 Copy->Signature = IP6_ADDR_INFO_SIGNATURE;\r
57 IP6_COPY_ADDRESS (&Copy->Address, &IpSb->LinkLocalAddr);\r
58 Copy->IsAnycast = FALSE;\r
59 Copy->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;\r
60 Copy->ValidLifetime = (UINT32) IP6_INFINIT_LIFETIME;\r
61 Copy->PreferredLifetime = (UINT32) IP6_INFINIT_LIFETIME;\r
62\r
63 InsertTailList (SourceList, &Copy->Link);\r
64 (*SourceCount)++;\r
65 }\r
66\r
67 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {\r
68 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);\r
69\r
70 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {\r
71 AddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
72\r
73 if (AddrInfo->IsAnycast) {\r
74 //\r
75 // Never use an anycast address.\r
76 //\r
77 continue;\r
78 }\r
79\r
80 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), AddrInfo);\r
81 if (Copy == NULL) {\r
82 return EFI_OUT_OF_RESOURCES;\r
83 }\r
84\r
85 InsertTailList (SourceList, &Copy->Link);\r
86 (*SourceCount)++;\r
87 }\r
88 }\r
89\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93/**\r
94 Caculate how many bits are the same between two IPv6 addresses.\r
95\r
96 @param[in] AddressA Points to an IPv6 address.\r
97 @param[in] AddressB Points to another IPv6 address.\r
98\r
99 @return The common bits of the AddressA and AddressB.\r
100\r
101**/\r
102UINT8\r
103Ip6CommonPrefixLen (\r
104 IN EFI_IPv6_ADDRESS *AddressA,\r
105 IN EFI_IPv6_ADDRESS *AddressB\r
106 )\r
107{\r
108 UINT8 Count;\r
109 UINT8 Index;\r
110 UINT8 ByteA;\r
111 UINT8 ByteB;\r
112 UINT8 NumBits;\r
113\r
114 Count = 0;\r
115 Index = 0;\r
116\r
117 while (Index < 16) {\r
118 ByteA = AddressA->Addr[Index];\r
119 ByteB = AddressB->Addr[Index];\r
120\r
121 if (ByteA == ByteB) {\r
122 Count += 8;\r
123 Index++;\r
124 continue;\r
125 }\r
126\r
127 //\r
128 // Check how many bits are common between the two bytes.\r
129 //\r
130 NumBits = 8;\r
131 ByteA = (UINT8) (ByteA ^ ByteB);\r
132\r
133 while (ByteA != 0) {\r
134 NumBits--;\r
135 ByteA = (UINT8) (ByteA >> 1);\r
136 }\r
137\r
138 return (UINT8) (Count + NumBits);\r
139 }\r
140\r
141 return Count;\r
142}\r
143\r
144/**\r
145 Output all the available source addresses to a list entry head SourceList. The\r
146 number of source addresses are also returned.\r
147\r
148 @param[in] IpSb Points to a IP6 service binding instance.\r
149 @param[in] Destination The IPv6 destination address.\r
150 @param[out] Source The selected IPv6 source address according to\r
151 the Destination.\r
152\r
153 @retval EFI_SUCCESS The source addresses were copied to a list entry\r
154 head SourceList.\r
155 @retval EFI_NO_MAPPING The IPv6 stack is not auto configured.\r
156\r
157**/\r
158EFI_STATUS\r
159Ip6SelectSourceAddress (\r
160 IN IP6_SERVICE *IpSb,\r
161 IN EFI_IPv6_ADDRESS *Destination,\r
162 OUT EFI_IPv6_ADDRESS *Source\r
163 )\r
164{\r
165 EFI_STATUS Status;\r
166 LIST_ENTRY SourceList;\r
167 UINT32 SourceCount;\r
168 UINT8 ScopeD;\r
169 LIST_ENTRY *Entry;\r
170 IP6_ADDRESS_INFO *AddrInfo;\r
171 IP6_PREFIX_LIST_ENTRY *Prefix;\r
172 UINT8 LastCommonLength;\r
173 UINT8 CurrentCommonLength;\r
174 EFI_IPv6_ADDRESS *TmpAddress;\r
175\r
176 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
177\r
178 Status = EFI_SUCCESS;\r
179 InitializeListHead (&SourceList);\r
180\r
181 if (!IpSb->LinkLocalOk) {\r
182 return EFI_NO_MAPPING;\r
183 }\r
184\r
185 //\r
186 // Rule 1: Prefer same address.\r
187 //\r
188 if (Ip6IsOneOfSetAddress (IpSb, Destination, NULL, NULL)) {\r
189 IP6_COPY_ADDRESS (Source, Destination);\r
190 goto Exit;\r
191 }\r
192\r
193 //\r
194 // Rule 2: Prefer appropriate scope.\r
195 //\r
196 if (IP6_IS_MULTICAST (Destination)) {\r
197 ScopeD = (UINT8) (Destination->Addr[1] >> 4);\r
198 } else if (NetIp6IsLinkLocalAddr (Destination)) {\r
199 ScopeD = 0x2;\r
200 } else {\r
201 ScopeD = 0xE;\r
202 }\r
203\r
204 if (ScopeD <= 0x2) {\r
205 //\r
206 // Return the link-local address if it exists\r
207 // One IP6_SERVICE only has one link-local address.\r
208 //\r
209 IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);\r
210 goto Exit;\r
211 }\r
212\r
213 //\r
214 // All candidate source addresses are global unicast address.\r
215 //\r
216 Ip6CandidateSource (IpSb, &SourceList, &SourceCount);\r
217\r
218 if (SourceCount == 0) {\r
219 Status = EFI_NO_MAPPING;\r
220 goto Exit;\r
221 }\r
222\r
223 IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);\r
224\r
225 if (SourceCount == 1) {\r
226 goto Exit;\r
227 }\r
228\r
229 //\r
230 // Rule 3: Avoid deprecated addresses.\r
231 // TODO: check the "deprecated" state of the stateful configured address\r
232 //\r
233 NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {\r
234 Prefix = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);\r
235 if (Prefix->PreferredLifetime == 0) {\r
236 Ip6RemoveAddr (NULL, &SourceList, &SourceCount, &Prefix->Prefix, Prefix->PrefixLength);\r
237\r
238 if (SourceCount == 1) {\r
239 goto Exit;\r
240 }\r
241 }\r
242 }\r
243\r
244 //\r
245 // TODO: Rule 4: Prefer home addresses.\r
246 // TODO: Rule 5: Prefer outgoing interface.\r
247 // TODO: Rule 6: Prefer matching label.\r
248 // TODO: Rule 7: Prefer public addresses.\r
249 //\r
250\r
251 //\r
252 // Rule 8: Use longest matching prefix.\r
253 //\r
254 LastCommonLength = Ip6CommonPrefixLen (Source, Destination);\r
255 TmpAddress = NULL;\r
256\r
257 for (Entry = SourceList.ForwardLink; Entry != &SourceList; Entry = Entry->ForwardLink) {\r
258 AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);\r
259\r
260 CurrentCommonLength = Ip6CommonPrefixLen (&AddrInfo->Address, Destination);\r
261 if (CurrentCommonLength > LastCommonLength) {\r
262 LastCommonLength = CurrentCommonLength;\r
263 TmpAddress = &AddrInfo->Address;\r
264 }\r
265 }\r
266\r
267 if (TmpAddress != NULL) {\r
268 IP6_COPY_ADDRESS (Source, TmpAddress);\r
269 }\r
270\r
271Exit:\r
272\r
273 Ip6RemoveAddr (NULL, &SourceList, &SourceCount, NULL, 0);\r
274\r
275 return Status;\r
276}\r
277\r
278/**\r
279 Select an interface to send the packet generated in the IP6 driver\r
280 itself: that is, not by the requests of the IP6 child's consumer. Such\r
281 packets include the ICMPv6 echo replies and other ICMPv6 error packets.\r
282\r
283 @param[in] IpSb The IP4 service that wants to send the packets.\r
284 @param[in] Destination The destination of the packet.\r
285 @param[in, out] Source The source of the packet.\r
286\r
287 @return NULL if no proper interface is found, otherwise, the interface that\r
288 can be used to send the system packet from.\r
289\r
290**/\r
291IP6_INTERFACE *\r
292Ip6SelectInterface (\r
293 IN IP6_SERVICE *IpSb,\r
294 IN EFI_IPv6_ADDRESS *Destination,\r
295 IN OUT EFI_IPv6_ADDRESS *Source\r
296 )\r
297{\r
298 EFI_STATUS Status;\r
299 EFI_IPv6_ADDRESS SelectedSource;\r
300 IP6_INTERFACE *IpIf;\r
301 BOOLEAN Exist;\r
302\r
303 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
304 ASSERT (Destination != NULL && Source != NULL);\r
305\r
306 if (NetIp6IsUnspecifiedAddr (Destination)) {\r
307 return NULL;\r
308 }\r
309\r
310 if (!NetIp6IsUnspecifiedAddr (Source)) {\r
311 Exist = Ip6IsOneOfSetAddress (IpSb, Source, &IpIf, NULL);\r
312 ASSERT (Exist);\r
313\r
314 return IpIf;\r
315 }\r
316\r
317 //\r
318 // If source is unspecified, select a source according to the destination.\r
319 //\r
320 Status = Ip6SelectSourceAddress (IpSb, Destination, &SelectedSource);\r
321 if (EFI_ERROR (Status)) {\r
322 return IpSb->DefaultInterface;\r
323 }\r
324\r
325 Ip6IsOneOfSetAddress (IpSb, &SelectedSource, &IpIf, NULL);\r
326 IP6_COPY_ADDRESS (Source, &SelectedSource);\r
327\r
328 return IpIf;\r
329}\r
330\r
331/**\r
332 The default callback function for the system generated packet.\r
333 It will free the packet.\r
334\r
335 @param[in] Packet The packet that transmitted.\r
336 @param[in] IoStatus The result of the transmission, succeeded or failed.\r
337 @param[in] LinkFlag Not used when transmitted. Check IP6_FRAME_CALLBACK\r
338 for reference.\r
339 @param[in] Context The context provided by us.\r
340\r
341**/\r
342VOID\r
343Ip6SysPacketSent (\r
344 NET_BUF *Packet,\r
345 EFI_STATUS IoStatus,\r
346 UINT32 LinkFlag,\r
347 VOID *Context\r
348 )\r
349{\r
350 NetbufFree (Packet);\r
351 Packet = NULL;\r
352}\r
353\r
354/**\r
355 Prefix an IP6 basic head and unfragmentable extension headers and a fragment header\r
356 to the Packet. Used for IP6 fragmentation.\r
357\r
358 @param[in] IpSb The IP6 service instance to transmit the packet.\r
359 @param[in] Packet The packet to prefix the IP6 header to.\r
360 @param[in] Head The caller supplied header.\r
361 @param[in] FragmentOffset The fragment offset of the data following the header.\r
362 @param[in] ExtHdrs The length of the original extension header.\r
363 @param[in] ExtHdrsLen The length of the extension headers.\r
364 @param[in] LastHeader The pointer of next header of last extension header.\r
365 @param[in] HeadLen The length of the unfragmented part of the IP6 header.\r
366\r
367 @retval EFI_BAD_BUFFER_SIZE There is no enought room in the head space of\r
368 Packet.\r
369 @retval EFI_SUCCESS The operation performed successfully.\r
370\r
371**/\r
372EFI_STATUS\r
373Ip6PrependHead (\r
374 IN IP6_SERVICE *IpSb,\r
375 IN NET_BUF *Packet,\r
376 IN EFI_IP6_HEADER *Head,\r
377 IN UINT16 FragmentOffset,\r
378 IN UINT8 *ExtHdrs,\r
379 IN UINT32 ExtHdrsLen,\r
380 IN UINT8 LastHeader,\r
381 IN UINT32 HeadLen\r
382 )\r
383{\r
384 UINT32 Len;\r
385 UINT32 UnFragExtHdrsLen;\r
386 EFI_IP6_HEADER *PacketHead;\r
387 UINT8 *UpdatedExtHdrs;\r
388 EFI_STATUS Status;\r
389 UINT8 NextHeader;\r
390\r
391 //\r
392 // HeadLen is the length of the fixed part of the sequences of fragments, i.e.\r
393 // the unfragment part.\r
394 //\r
395 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);\r
396 if (PacketHead == NULL) {\r
397 return EFI_BAD_BUFFER_SIZE;\r
398 }\r
399\r
400 //\r
401 // Set the head up, convert the host byte order to network byte order\r
402 //\r
403 CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));\r
404 PacketHead->PayloadLength = HTONS ((UINT16) (Packet->TotalSize - sizeof (EFI_IP6_HEADER)));\r
405 Packet->Ip.Ip6 = PacketHead;\r
406\r
407 Len = HeadLen - sizeof (EFI_IP6_HEADER);\r
408 UnFragExtHdrsLen = Len - sizeof (IP6_FRAGMENT_HEADER);\r
409\r
410 if (UnFragExtHdrsLen == 0) {\r
411 PacketHead->NextHeader = IP6_FRAGMENT;\r
412 }\r
413\r
414 //\r
415 // Append the extension headers: firstly copy the unfragmentable headers, then append\r
416 // fragmentation header.\r
417 //\r
418 if ((FragmentOffset & IP6_FRAGMENT_OFFSET_MASK) == 0) {\r
419 NextHeader = Head->NextHeader;\r
420 } else {\r
421 NextHeader = PacketHead->NextHeader;\r
422 }\r
423\r
424 Status = Ip6FillFragmentHeader (\r
425 IpSb,\r
426 NextHeader,\r
427 LastHeader,\r
428 ExtHdrs,\r
429 ExtHdrsLen,\r
430 FragmentOffset,\r
431 &UpdatedExtHdrs\r
432 );\r
433 if (EFI_ERROR (Status)) {\r
434 return Status;\r
435 }\r
436\r
437 CopyMem (\r
438 (UINT8 *) (PacketHead + 1),\r
439 UpdatedExtHdrs,\r
440 UnFragExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER)\r
441 );\r
442\r
443 FreePool (UpdatedExtHdrs);\r
444 return EFI_SUCCESS;\r
445}\r
446\r
447/**\r
448 Transmit an IP6 packet. The packet comes either from the IP6\r
449 child's consumer (IpInstance != NULL) or the IP6 driver itself\r
450 (IpInstance == NULL). It will route the packet, fragment it,\r
451 then transmit all the fragments through an interface.\r
452\r
453 @param[in] IpSb The IP6 service instance to transmit the packet.\r
454 @param[in] Interface The IP6 interface to transmit the packet. Ignored\r
455 if NULL.\r
456 @param[in] IpInstance The IP6 child that issues the transmission. It is\r
457 NULL if the packet is from the system.\r
458 @param[in] Packet The user data to send, excluding the IP header.\r
459 @param[in] Head The caller supplied header. The caller should set\r
460 the following header fields: NextHeader, HopLimit,\r
461 Src, Dest, FlowLabel, PayloadLength. This function\r
462 will fill in the Ver, TrafficClass.\r
463 @param[in] ExtHdrs The extension headers to append to the IPv6 basic\r
464 header.\r
465 @param[in] ExtHdrsLen The length of the extension headers.\r
466 @param[in] Callback The callback function to issue when transmission\r
467 completed.\r
468 @param[in] Context The opaque context for the callback.\r
469\r
470 @retval EFI_INVALID_PARAMETER Any input parameter or the packet is invalid.\r
471 @retval EFI_NO_MAPPING There is no interface to the destination.\r
472 @retval EFI_NOT_FOUND There is no route to the destination.\r
473 @retval EFI_SUCCESS The packet successfully transmitted.\r
474 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of\r
475 resources.\r
476 @retval Others Failed to transmit the packet.\r
477\r
478**/\r
479EFI_STATUS\r
480Ip6Output (\r
481 IN IP6_SERVICE *IpSb,\r
482 IN IP6_INTERFACE *Interface OPTIONAL,\r
483 IN IP6_PROTOCOL *IpInstance OPTIONAL,\r
484 IN NET_BUF *Packet,\r
485 IN EFI_IP6_HEADER *Head,\r
486 IN UINT8 *ExtHdrs,\r
487 IN UINT32 ExtHdrsLen,\r
488 IN IP6_FRAME_CALLBACK Callback,\r
489 IN VOID *Context\r
490 )\r
491{\r
492 IP6_INTERFACE *IpIf;\r
493 EFI_IPv6_ADDRESS NextHop;\r
494 IP6_NEIGHBOR_ENTRY *NeighborCache;\r
495 IP6_ROUTE_CACHE_ENTRY *RouteCache;\r
496 EFI_STATUS Status;\r
497 UINT32 Mtu;\r
498 UINT32 HeadLen;\r
499 UINT16 FragmentOffset;\r
500 UINT8 *LastHeader;\r
501 UINT32 UnFragmentLen;\r
502 UINT32 UnFragmentHdrsLen;\r
503 UINT32 FragmentHdrsLen;\r
504 UINT16 *Checksum;\r
505 UINT16 PacketChecksum;\r
506 UINT16 PseudoChecksum;\r
507 UINT32 Index;\r
508 UINT32 PacketLen;\r
509 UINT32 RealExtLen;\r
510 UINT32 Offset;\r
511 NET_BUF *TmpPacket;\r
512 NET_BUF *Fragment;\r
513 UINT32 Num;\r
514 UINT8 *Buf;\r
515 EFI_IP6_HEADER *PacketHead;\r
516 IP6_ICMP_HEAD *IcmpHead;\r
517 IP6_TXTOKEN_WRAP *Wrap;\r
518 IP6_ROUTE_ENTRY *RouteEntry;\r
519 UINT8 *UpdatedExtHdrs;\r
520 UINT8 NextHeader;\r
521 UINT8 LastHeaderBackup;\r
522 BOOLEAN FragmentHeadInserted;\r
523 UINT8 *ExtHdrsBackup;\r
524 UINT8 NextHeaderBackup;\r
525 EFI_IPv6_ADDRESS Source;\r
526 EFI_IPv6_ADDRESS Destination;\r
527\r
528 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
529\r
530 //\r
531 // RFC2460: Each extension header is an integer multiple of 8 octets long,\r
532 // in order to retain 8-octet alignment for subsequent headers.\r
533 //\r
534 if ((ExtHdrsLen & 0x7) != 0) {\r
535 return EFI_INVALID_PARAMETER;\r
536 }\r
537\r
538 LastHeader = NULL;\r
539\r
540 Ip6IsExtsValid (\r
541 NULL,\r
542 NULL,\r
543 &Head->NextHeader,\r
544 ExtHdrs,\r
545 ExtHdrsLen,\r
546 FALSE,\r
547 NULL,\r
548 &LastHeader,\r
549 NULL,\r
550 NULL,\r
551 NULL\r
552 );\r
553\r
554 //\r
555 // Select an interface/source for system packet, application\r
556 // should select them itself.\r
557 //\r
558 IpIf = Interface;\r
559 if (IpIf == NULL) {\r
560 //\r
561 // IpInstance->Interface is NULL when IpInstance is configured with both stationaddress\r
562 // and destinationaddress is unspecified.\r
563 //\r
564 if (IpInstance == NULL || IpInstance->Interface == NULL) {\r
565 IpIf = Ip6SelectInterface (IpSb, &Head->DestinationAddress, &Head->SourceAddress);\r
566 if (IpInstance != NULL) {\r
567 IpInstance->Interface = IpIf;\r
568 }\r
569 } else {\r
570 IpIf = IpInstance->Interface;\r
571 }\r
572 }\r
573\r
574 if (IpIf == NULL) {\r
575 return EFI_NO_MAPPING;\r
576 }\r
577\r
578 //\r
579 // Update the common field in Head here.\r
580 //\r
581 Head->Version = 6;\r
582 Head->TrafficClassL = 0;\r
583 Head->TrafficClassH = 0;\r
584\r
585 Checksum = NULL;\r
586 NextHeader = *LastHeader;\r
587\r
588 switch (NextHeader) {\r
589 case EFI_IP_PROTO_UDP:\r
590 Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);\r
591 ASSERT (Packet->Udp != NULL);\r
592 if (Packet->Udp->Checksum == 0) {\r
593 Checksum = &Packet->Udp->Checksum;\r
594 }\r
595 break;\r
596\r
597 case EFI_IP_PROTO_TCP:\r
598 Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
599 ASSERT (Packet->Tcp != NULL);\r
600 if (Packet->Tcp->Checksum == 0) {\r
601 Checksum = &Packet->Tcp->Checksum;\r
602 }\r
603 break;\r
604\r
605 case IP6_ICMP:\r
606 //\r
607 // Don't send ICMP packet to an IPv6 anycast address.\r
608 //\r
609 if (Ip6IsAnycast (IpSb, &Head->DestinationAddress)) {\r
610 return EFI_INVALID_PARAMETER;\r
611 }\r
612\r
613 IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);\r
614 ASSERT (IcmpHead != NULL);\r
615 if (IcmpHead->Checksum == 0) {\r
616 Checksum = &IcmpHead->Checksum;\r
617 }\r
618 break;\r
619\r
620 default:\r
621 break;\r
622 }\r
623\r
624 if (Checksum != NULL) {\r
625 //\r
626 // Calculate the checksum for upper layer protocol if it is not calculated due to lack of\r
627 // IPv6 source address.\r
628 //\r
629 PacketChecksum = NetbufChecksum (Packet);\r
630 PseudoChecksum = NetIp6PseudoHeadChecksum (\r
631 &Head->SourceAddress,\r
632 &Head->DestinationAddress,\r
633 NextHeader,\r
634 Packet->TotalSize\r
635 );\r
636 *Checksum = (UINT16) ~NetAddChecksum (PacketChecksum, PseudoChecksum);\r
637 }\r
638\r
639 Status = Ip6IpSecProcessPacket (\r
640 IpSb,\r
68d3f2fb 641 &Head,\r
a3bcde70
HT
642 LastHeader, // no need get the lasthead value for output\r
643 &Packet,\r
68d3f2fb 644 &ExtHdrs,\r
645 &ExtHdrsLen,\r
a3bcde70
HT
646 EfiIPsecOutBound,\r
647 Context\r
648 );\r
649\r
650 if (EFI_ERROR(Status)) {\r
651 return Status;\r
652 }\r
653\r
654 LastHeader = NULL;\r
655 //\r
656 // Check incoming parameters.\r
657 //\r
658 if (!Ip6IsExtsValid (\r
659 IpSb,\r
660 Packet,\r
661 &Head->NextHeader,\r
662 ExtHdrs,\r
663 ExtHdrsLen,\r
664 FALSE,\r
665 NULL,\r
666 &LastHeader,\r
667 &RealExtLen,\r
668 &UnFragmentHdrsLen,\r
669 NULL\r
670 )) {\r
671 return EFI_INVALID_PARAMETER;\r
672 }\r
673\r
674 if ((RealExtLen & 0x7) != 0) {\r
675 return EFI_INVALID_PARAMETER;\r
676 }\r
677\r
678 LastHeaderBackup = *LastHeader;\r
679\r
680 //\r
681 // Perform next hop determination:\r
682 // For multicast packets, the next-hop is always the destination address and\r
683 // is considered to be on-link.\r
684 //\r
685 if (IP6_IS_MULTICAST (&Head->DestinationAddress)) {\r
686 IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress);\r
687 } else {\r
688 //\r
689 // For unicast packets, use a combination of the Destination Cache, the Prefix List\r
690 // and the Default Router List to determine the IP address of the appropriate next hop.\r
691 //\r
692 RouteCache = Ip6Route (IpSb, &Head->DestinationAddress, &Head->SourceAddress);\r
693 if (RouteCache == NULL) {\r
694 return EFI_NOT_FOUND;\r
695 }\r
696\r
697 IP6_COPY_ADDRESS (&NextHop, &RouteCache->NextHop);\r
698 Ip6FreeRouteCacheEntry (RouteCache);\r
699 }\r
700\r
701 //\r
702 // Examines the Neighbor Cache for link-layer information about that neighbor.\r
703 // DO NOT create neighbor cache if neighbor is itself - when reporting ICMP error.\r
704 //\r
705 if (!IP6_IS_MULTICAST (&NextHop) && !EFI_IP6_EQUAL (&Head->DestinationAddress, &Head->SourceAddress)) {\r
706 NeighborCache = Ip6FindNeighborEntry (IpSb, &NextHop);\r
707 if (NeighborCache == NULL) {\r
708 NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &NextHop, NULL);\r
709\r
710 if (NeighborCache == NULL) {\r
711 return EFI_OUT_OF_RESOURCES;\r
712 }\r
713\r
714 //\r
715 // Send out multicast neighbor solicitation for address resolution immediatly.\r
716 //\r
717 Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);\r
718 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);\r
719 if (EFI_ERROR (Status)) {\r
720 return Status;\r
721 }\r
722\r
723 Status = Ip6SendNeighborSolicit (\r
724 IpSb,\r
725 &Source,\r
726 &Destination,\r
727 &NeighborCache->Neighbor,\r
728 &IpSb->SnpMode.CurrentAddress\r
729 );\r
730 if (EFI_ERROR (Status)) {\r
731 return Status;\r
732 }\r
733\r
734 --NeighborCache->Transmit;\r
735 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer) + 1;\r
736 }\r
737\r
738 NeighborCache->Interface = IpIf;\r
739 }\r
740\r
741 UpdatedExtHdrs = NULL;\r
742 ExtHdrsBackup = NULL;\r
743 NextHeaderBackup = 0;\r
744 FragmentHeadInserted = FALSE;\r
745\r
746 //\r
747 // Check whether we received Packet Too Big message for the packet sent to the\r
748 // Destination. If yes include a Fragment Header in the subsequent packets.\r
749 //\r
750 RouteEntry = Ip6FindRouteEntry (\r
751 IpSb->RouteTable,\r
752 &Head->DestinationAddress,\r
753 NULL\r
754 );\r
755 if (RouteEntry != NULL) {\r
756 if ((RouteEntry->Flag & IP6_PACKET_TOO_BIG) == IP6_PACKET_TOO_BIG) {\r
757\r
758 //\r
759 // FragmentHead is inserted after Hop-by-Hop Options header, Destination\r
760 // Options header (first occur), Routing header, and before Fragment header,\r
761 // Authentication header, Encapsulating Security Payload header, and\r
762 // Destination Options header (last occur), and upper-layer header.\r
763 //\r
764 Status = Ip6FillFragmentHeader (\r
765 IpSb,\r
766 Head->NextHeader,\r
767 LastHeaderBackup,\r
768 ExtHdrs,\r
769 ExtHdrsLen,\r
770 0,\r
771 &UpdatedExtHdrs\r
772 );\r
773 if (EFI_ERROR (Status)) {\r
774 return Status;\r
775 }\r
776\r
777 if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {\r
778 NextHeaderBackup = Head->NextHeader;\r
779 Head->NextHeader = IP6_FRAGMENT;\r
780 }\r
781\r
782 ExtHdrsBackup = ExtHdrs;\r
783 ExtHdrs = UpdatedExtHdrs;\r
784 ExtHdrsLen = ExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER);\r
785 RealExtLen = RealExtLen + sizeof (IP6_FRAGMENT_HEADER);\r
786\r
787 mIp6Id++;\r
788\r
789 FragmentHeadInserted = TRUE;\r
790 }\r
791\r
792 Ip6FreeRouteEntry (RouteEntry);\r
793 }\r
794\r
795 //\r
796 // OK, selected the source and route, fragment the packet then send\r
797 // them. Tag each fragment other than the first one as spawn from it.\r
798 // Each extension header is an integar multiple of 8 octets long, in\r
799 // order to retain 8-octet alignment for subsequent headers.\r
800 //\r
801 Mtu = IpSb->MaxPacketSize + sizeof (EFI_IP6_HEADER);\r
802 HeadLen = sizeof (EFI_IP6_HEADER) + RealExtLen;\r
803\r
804 if (Packet->TotalSize + HeadLen > Mtu) {\r
805 //\r
806 // Remove the inserted Fragment Header since we need fragment the packet.\r
807 //\r
808 if (FragmentHeadInserted) {\r
809 ExtHdrs = ExtHdrsBackup;\r
810 ExtHdrsLen = ExtHdrsLen - sizeof (IP6_FRAGMENT_HEADER);\r
811\r
812 if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {\r
813 Head->NextHeader = NextHeaderBackup;\r
814 }\r
815 }\r
816\r
817 FragmentHdrsLen = ExtHdrsLen - UnFragmentHdrsLen;\r
818\r
819 //\r
820 // The packet is beyond the maximum which can be described through the\r
821 // fragment offset field in Fragment header.\r
822 //\r
823 if ((((Packet->TotalSize + FragmentHdrsLen) >> 3) & (~0x1fff)) != 0) {\r
824 Status = EFI_BAD_BUFFER_SIZE;\r
825 goto Error;\r
826 }\r
827\r
828 if (FragmentHdrsLen != 0) {\r
829 //\r
830 // Append the fragmentable extension hdrs before the upper layer payload\r
831 // to form a new NET_BUF. This NET_BUF contains all the buffer which will\r
832 // be fragmented below.\r
833 //\r
834 TmpPacket = NetbufGetFragment (Packet, 0, Packet->TotalSize, FragmentHdrsLen);\r
835 ASSERT (TmpPacket != NULL);\r
836\r
837 //\r
838 // Allocate the space to contain the fragmentable hdrs and copy the data.\r
839 //\r
840 Buf = NetbufAllocSpace (TmpPacket, FragmentHdrsLen, TRUE);\r
841 ASSERT (Buf != NULL);\r
842 CopyMem (Buf, ExtHdrs + UnFragmentHdrsLen, FragmentHdrsLen);\r
843\r
844 //\r
845 // Free the old Packet.\r
846 //\r
847 NetbufFree (Packet);\r
848 Packet = TmpPacket;\r
849 }\r
850\r
851 //\r
852 // The unfragment part which appears in every fragmented IPv6 packet includes\r
853 // the IPv6 header, the unfragmentable extension hdrs and the fragment header.\r
854 //\r
855 UnFragmentLen = sizeof (EFI_IP6_HEADER) + UnFragmentHdrsLen + sizeof (IP6_FRAGMENT_HEADER);\r
856\r
857 //\r
858 // Mtu now is the length of the fragment part in a full-length fragment.\r
859 //\r
860 Mtu = (Mtu - UnFragmentLen) & (~0x07);\r
861 Num = (Packet->TotalSize + Mtu - 1) / Mtu;\r
862\r
863 for (Index = 0, Offset = 0, PacketLen = Mtu; Index < Num; Index++) {\r
864 //\r
865 // Get fragment from the Packet, append UnFragnmentLen spare buffer\r
866 // before the fragmented data, the corresponding data is filled in later.\r
867 //\r
868 Fragment = NetbufGetFragment (Packet, Offset, PacketLen, UnFragmentLen);\r
869 if (Fragment == NULL) {\r
870 Status = EFI_OUT_OF_RESOURCES;\r
871 goto Error;\r
872 }\r
873\r
874 FragmentOffset = (UINT16) ((UINT16) Offset | 0x1);\r
875 if (Index == Num - 1){\r
876 //\r
877 // The last fragment, clear the M flag.\r
878 //\r
879 FragmentOffset &= (~0x1);\r
880 }\r
881\r
882 Status = Ip6PrependHead (\r
883 IpSb,\r
884 Fragment,\r
885 Head,\r
886 FragmentOffset,\r
887 ExtHdrs,\r
888 ExtHdrsLen,\r
889 LastHeaderBackup,\r
890 UnFragmentLen\r
891 );\r
892 ASSERT (Status == EFI_SUCCESS);\r
893\r
894 Status = Ip6SendFrame (\r
895 IpIf,\r
896 IpInstance,\r
897 Fragment,\r
898 &NextHop,\r
899 Ip6SysPacketSent,\r
900 Packet\r
901 );\r
902 if (EFI_ERROR (Status)) {\r
903 goto Error;\r
904 }\r
905\r
906 //\r
907 // The last fragment of upper layer packet, update the IP6 token status.\r
908 //\r
909 if ((Index == Num -1) && (Context != NULL)) {\r
910 Wrap = (IP6_TXTOKEN_WRAP *) Context;\r
911 Wrap->Token->Status = Status;\r
912 }\r
913\r
914 Offset += PacketLen;\r
915 PacketLen = Packet->TotalSize - Offset;\r
916 if (PacketLen > Mtu) {\r
917 PacketLen = Mtu;\r
918 }\r
919 }\r
920\r
921 NetbufFree (Packet);\r
922 mIp6Id++;\r
923\r
924 if (UpdatedExtHdrs != NULL) {\r
925 FreePool (UpdatedExtHdrs);\r
926 }\r
927\r
928 return EFI_SUCCESS;\r
929 }\r
930\r
931 //\r
932 // Need not fragment the packet, send it in one frame.\r
933 //\r
934 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);\r
935 if (PacketHead == NULL) {\r
936 Status = EFI_BAD_BUFFER_SIZE;\r
937 goto Error;\r
938 }\r
939\r
940 CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));\r
941 Packet->Ip.Ip6 = PacketHead;\r
942\r
943 if (ExtHdrs != NULL) {\r
944 Buf = (UINT8 *) (PacketHead + 1);\r
945 CopyMem (Buf, ExtHdrs, ExtHdrsLen);\r
946 }\r
947\r
948 if (UpdatedExtHdrs != NULL) {\r
949 //\r
950 // A Fragment Header is inserted to the packet, update the payload length.\r
951 //\r
952 PacketHead->PayloadLength = (UINT16) (NTOHS (PacketHead->PayloadLength) +\r
953 sizeof (IP6_FRAGMENT_HEADER));\r
954 PacketHead->PayloadLength = HTONS (PacketHead->PayloadLength);\r
955 FreePool (UpdatedExtHdrs);\r
956 }\r
957\r
958 return Ip6SendFrame (\r
959 IpIf,\r
960 IpInstance,\r
961 Packet,\r
962 &NextHop,\r
963 Callback,\r
964 Context\r
965 );\r
966\r
967Error:\r
968 if (UpdatedExtHdrs != NULL) {\r
969 FreePool (UpdatedExtHdrs);\r
970 }\r
971 Ip6CancelPacket (IpIf, Packet, Status);\r
972 return Status;\r
973}\r
974\r
975/**\r
976 The filter function to find a packet and all its fragments.\r
977 The packet's fragments have their Context set to the packet.\r
978\r
979 @param[in] Frame The frames hold by the low level interface.\r
980 @param[in] Context Context to the function, which is the packet.\r
981\r
982 @retval TRUE This is the packet to cancel or its fragments.\r
983 @retval FALSE This is an unrelated packet.\r
984\r
985**/\r
986BOOLEAN\r
987Ip6CancelPacketFragments (\r
988 IN IP6_LINK_TX_TOKEN *Frame,\r
989 IN VOID *Context\r
990 )\r
991{\r
992 if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {\r
993 return TRUE;\r
994 }\r
995\r
996 return FALSE;\r
997}\r
998\r
999/**\r
1000 Remove all the frames on the interface that pass the FrameToCancel,\r
1001 either queued on ARP queues or that have already been delivered to\r
1002 MNP and not yet recycled.\r
1003\r
1004 @param[in] Interface Interface to remove the frames from.\r
1005 @param[in] IoStatus The transmit status returned to the frames' callback.\r
1006 @param[in] FrameToCancel Function to select the frame to cancel; NULL to select all.\r
1007 @param[in] Context Opaque parameters passed to FrameToCancel. Ignored if\r
1008 FrameToCancel is NULL.\r
1009\r
1010**/\r
1011VOID\r
1012Ip6CancelFrames (\r
1013 IN IP6_INTERFACE *Interface,\r
1014 IN EFI_STATUS IoStatus,\r
1015 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,\r
1016 IN VOID *Context OPTIONAL\r
1017 )\r
1018{\r
1019 LIST_ENTRY *Entry;\r
1020 LIST_ENTRY *Next;\r
1021 IP6_LINK_TX_TOKEN *Token;\r
1022 IP6_SERVICE *IpSb;\r
1023 IP6_NEIGHBOR_ENTRY *ArpQue;\r
1024 EFI_STATUS Status;\r
1025\r
1026 IpSb = Interface->Service;\r
1027 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
1028\r
1029 //\r
1030 // Cancel all the pending frames on ARP requests\r
1031 //\r
1032 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {\r
1033 ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);\r
1034\r
1035 Status = Ip6FreeNeighborEntry (\r
1036 IpSb,\r
1037 ArpQue,\r
1038 FALSE,\r
1039 FALSE,\r
1040 IoStatus,\r
1041 FrameToCancel,\r
1042 Context\r
1043 );\r
1044 ASSERT_EFI_ERROR (Status);\r
1045 }\r
1046\r
1047 //\r
1048 // Cancel all the frames that have been delivered to MNP\r
1049 // but not yet recycled.\r
1050 //\r
1051 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {\r
1052 Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);\r
1053\r
1054 if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {\r
1055 IpSb->Mnp->Cancel (IpSb->Mnp, &Token->MnpToken);\r
1056 }\r
1057 }\r
1058}\r
1059\r
1060/**\r
1061 Cancel the Packet and all its fragments.\r
1062\r
1063 @param[in] IpIf The interface from which the Packet is sent.\r
1064 @param[in] Packet The Packet to cancel.\r
1065 @param[in] IoStatus The status returns to the sender.\r
1066\r
1067**/\r
1068VOID\r
1069Ip6CancelPacket (\r
1070 IN IP6_INTERFACE *IpIf,\r
1071 IN NET_BUF *Packet,\r
1072 IN EFI_STATUS IoStatus\r
1073 )\r
1074{\r
1075 Ip6CancelFrames (IpIf, IoStatus, Ip6CancelPacketFragments, Packet);\r
1076}\r
1077\r