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