]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/Ip4Dxe/Ip4Output.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / NetworkPkg / Ip4Dxe / Ip4Output.c
1 /** @file
2 Transmit the IP4 packet.
3
4 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "Ip4Impl.h"
10
11 UINT16 mIp4Id;
12
13 /**
14 Prepend an IP4 head to the Packet. It will copy the options and
15 build the IP4 header fields. Used for IP4 fragmentation.
16
17 @param Packet The packet to prepend IP4 header to
18 @param Head The caller supplied header. The caller should set
19 the following header fields: Tos, TotalLen, Id,
20 Fragment, Ttl, Protocol, Src and Dst. All the fields
21 are in host byte order. This function will fill in
22 the Ver, HeadLen, and checksum.
23 @param Option The original IP4 option to copy from
24 @param OptLen The length of the IP4 option
25
26 @retval EFI_BAD_BUFFER_SIZE There is no enough room in the head space of
27 Packet.
28 @retval EFI_SUCCESS The IP4 header is successfully added to the packet.
29
30 **/
31 EFI_STATUS
32 Ip4PrependHead (
33 IN OUT NET_BUF *Packet,
34 IN IP4_HEAD *Head,
35 IN UINT8 *Option,
36 IN UINT32 OptLen
37 )
38 {
39 UINT32 HeadLen;
40 UINT32 Len;
41 IP4_HEAD *PacketHead;
42 BOOLEAN FirstFragment;
43
44 //
45 // Prepend the options: first get the option length, then copy it over.
46 //
47 HeadLen = 0;
48 FirstFragment = IP4_FIRST_FRAGMENT (Head->Fragment);
49
50 Ip4CopyOption (Option, OptLen, FirstFragment, NULL, &Len);
51
52 HeadLen = IP4_MIN_HEADLEN + Len;
53 ASSERT (((Len % 4) == 0) && (HeadLen <= IP4_MAX_HEADLEN));
54
55 PacketHead = (IP4_HEAD *)NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
56
57 if (PacketHead == NULL) {
58 return EFI_BAD_BUFFER_SIZE;
59 }
60
61 Ip4CopyOption (Option, OptLen, FirstFragment, (UINT8 *)(PacketHead + 1), &Len);
62
63 //
64 // Set the head up, convert the host byte order to network byte order
65 //
66 PacketHead->Ver = 4;
67 PacketHead->HeadLen = (UINT8)(HeadLen >> 2);
68 PacketHead->Tos = Head->Tos;
69 PacketHead->TotalLen = HTONS ((UINT16)Packet->TotalSize);
70 PacketHead->Id = HTONS (Head->Id);
71 PacketHead->Fragment = HTONS (Head->Fragment);
72 PacketHead->Checksum = 0;
73 PacketHead->Ttl = Head->Ttl;
74 PacketHead->Protocol = Head->Protocol;
75 PacketHead->Src = HTONL (Head->Src);
76 PacketHead->Dst = HTONL (Head->Dst);
77 PacketHead->Checksum = (UINT16)(~NetblockChecksum ((UINT8 *)PacketHead, HeadLen));
78
79 Packet->Ip.Ip4 = PacketHead;
80 return EFI_SUCCESS;
81 }
82
83 /**
84 Select an interface to send the packet generated in the IP4 driver
85 itself, that is, not by the requests of IP4 child's consumer. Such
86 packets include the ICMP echo replies, and other ICMP error packets.
87
88 @param[in] IpSb The IP4 service that wants to send the packets.
89 @param[in] Dst The destination of the packet
90 @param[in] Src The source of the packet
91
92 @return NULL if no proper interface is found, otherwise the interface that
93 can be used to send the system packet from.
94
95 **/
96 IP4_INTERFACE *
97 Ip4SelectInterface (
98 IN IP4_SERVICE *IpSb,
99 IN IP4_ADDR Dst,
100 IN IP4_ADDR Src
101 )
102 {
103 IP4_INTERFACE *IpIf;
104 IP4_INTERFACE *Selected;
105 LIST_ENTRY *Entry;
106
107 //
108 // Select the interface the Dst is on if one of the connected
109 // network. Some IP instance may be configured with 0.0.0.0/0,
110 // don't select that interface now.
111 //
112 IpIf = Ip4FindNet (IpSb, Dst);
113
114 if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
115 return IpIf;
116 }
117
118 //
119 // If source is one of the interface address, select it.
120 //
121 IpIf = Ip4FindInterface (IpSb, Src);
122
123 if ((IpIf != NULL) && (IpIf->Ip != IP4_ALLZERO_ADDRESS)) {
124 return IpIf;
125 }
126
127 //
128 // Select a configured interface as the fall back. Always prefer
129 // an interface with non-zero address.
130 //
131 Selected = NULL;
132
133 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
134 IpIf = NET_LIST_USER_STRUCT (Entry, IP4_INTERFACE, Link);
135
136 if (IpIf->Configured && ((Selected == NULL) || (Selected->Ip == 0))) {
137 Selected = IpIf;
138 }
139 }
140
141 return Selected;
142 }
143
144 /**
145 The default callback function for system generated packet.
146 It will free the packet.
147
148 @param Ip4Instance The IP4 child that issued the transmission. It most
149 like is NULL.
150 @param Packet The packet that transmitted.
151 @param IoStatus The result of the transmission, succeeded or failed.
152 @param LinkFlag Not used when transmission. check IP4_FRAME_CALLBACK
153 for reference.
154 @param Context The context provided by us
155
156 **/
157 VOID
158 Ip4SysPacketSent (
159 IP4_PROTOCOL *Ip4Instance,
160 NET_BUF *Packet,
161 EFI_STATUS IoStatus,
162 UINT32 LinkFlag,
163 VOID *Context
164 )
165 {
166 NetbufFree (Packet);
167 }
168
169 /**
170 Transmit an IP4 packet. The packet comes either from the IP4
171 child's consumer (IpInstance != NULL) or the IP4 driver itself
172 (IpInstance == NULL). It will route the packet, fragment it,
173 then transmit all the fragments through some interface.
174
175 @param[in] IpSb The IP4 service instance to transmit the packet
176 @param[in] IpInstance The IP4 child that issues the transmission. It is
177 NULL if the packet is from the system.
178 @param[in] Packet The user data to send, excluding the IP header.
179 @param[in] Head The caller supplied header. The caller should set
180 the following header fields: Tos, TotalLen, Id, tl,
181 Fragment, Protocol, Src and Dst. All the fields are
182 in host byte order. This function will fill in the
183 Ver, HeadLen, Fragment, and checksum. The Fragment
184 only need to include the DF flag. Ip4Output will
185 compute the MF and offset for you.
186 @param[in] Option The original option to append to the IP headers
187 @param[in] OptLen The length of the option
188 @param[in] GateWay The next hop address to transmit packet to.
189 255.255.255.255 means broadcast.
190 @param[in] Callback The callback function to issue when transmission
191 completed.
192 @param[in] Context The opaque context for the callback
193
194 @retval EFI_NO_MAPPING There is no interface to the destination.
195 @retval EFI_NOT_FOUND There is no route to the destination
196 @retval EFI_SUCCESS The packet is successfully transmitted.
197 @retval EFI_BAD_BUFFER_SIZE The length of the IPv4 header + option length +
198 total data length is greater than MTU (or greater
199 than the maximum packet size if Token.Packet.TxData.
200 OverrideData.DoNotFragment is TRUE.)
201 @retval Others Failed to transmit the packet.
202
203 **/
204 EFI_STATUS
205 Ip4Output (
206 IN IP4_SERVICE *IpSb,
207 IN IP4_PROTOCOL *IpInstance OPTIONAL,
208 IN NET_BUF *Packet,
209 IN IP4_HEAD *Head,
210 IN UINT8 *Option,
211 IN UINT32 OptLen,
212 IN IP4_ADDR GateWay,
213 IN IP4_FRAME_CALLBACK Callback,
214 IN VOID *Context
215 )
216 {
217 IP4_INTERFACE *IpIf;
218 IP4_ROUTE_CACHE_ENTRY *CacheEntry;
219 IP4_ADDR Dest;
220 EFI_STATUS Status;
221 NET_BUF *Fragment;
222 UINT32 Index;
223 UINT32 HeadLen;
224 UINT32 PacketLen;
225 UINT32 Offset;
226 UINT32 Mtu;
227 UINT32 Num;
228 BOOLEAN RawData;
229
230 //
231 // Select an interface/source for system packet, application
232 // should select them itself.
233 //
234 if (IpInstance == NULL) {
235 IpIf = Ip4SelectInterface (IpSb, Head->Dst, Head->Src);
236 } else {
237 IpIf = IpInstance->Interface;
238 }
239
240 if (IpIf == NULL) {
241 return EFI_NO_MAPPING;
242 }
243
244 if ((Head->Src == IP4_ALLZERO_ADDRESS) && (IpInstance == NULL)) {
245 Head->Src = IpIf->Ip;
246 }
247
248 //
249 // Before IPsec process, prepared the IP head.
250 // If Ip4Output is transmitting RawData, don't update IPv4 header.
251 //
252 HeadLen = sizeof (IP4_HEAD) + ((OptLen + 3) & (~0x03));
253
254 if ((IpInstance != NULL) && IpInstance->ConfigData.RawData) {
255 RawData = TRUE;
256 } else {
257 Head->HeadLen = (UINT8)(HeadLen >> 2);
258 Head->Id = mIp4Id++;
259 Head->Ver = 4;
260 RawData = FALSE;
261 }
262
263 //
264 // Call IPsec process.
265 //
266 Status = Ip4IpSecProcessPacket (
267 IpSb,
268 &Head,
269 &Packet,
270 &Option,
271 &OptLen,
272 EfiIPsecOutBound,
273 Context
274 );
275
276 if (EFI_ERROR (Status)) {
277 return Status;
278 }
279
280 Dest = Head->Dst;
281 if (IP4_IS_BROADCAST (Ip4GetNetCast (Dest, IpIf)) || (Dest == IP4_ALLONE_ADDRESS)) {
282 //
283 // Set the gateway to local broadcast if the Dest is
284 // the broadcast address for the connected network or
285 // it is local broadcast.
286 //
287 GateWay = IP4_ALLONE_ADDRESS;
288 } else if (IP4_IS_MULTICAST (Dest)) {
289 //
290 // Set the gateway to the destination if it is an multicast
291 // address. The IP4_INTERFACE won't consult ARP to send local
292 // broadcast and multicast.
293 //
294 GateWay = Head->Dst;
295 } else if (GateWay == IP4_ALLZERO_ADDRESS) {
296 //
297 // Route the packet unless overridden, that is, GateWay isn't zero.
298 //
299 if (IpInstance == NULL) {
300 CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
301 } else {
302 CacheEntry = Ip4Route (IpInstance->RouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, FALSE);
303 //
304 // If failed to route the packet by using the instance's route table,
305 // try to use the default route table.
306 //
307 if (CacheEntry == NULL) {
308 CacheEntry = Ip4Route (IpSb->DefaultRouteTable, Head->Dst, Head->Src, IpIf->SubnetMask, TRUE);
309 }
310 }
311
312 if (CacheEntry == NULL) {
313 return EFI_NOT_FOUND;
314 }
315
316 GateWay = CacheEntry->NextHop;
317 Ip4FreeRouteCacheEntry (CacheEntry);
318 }
319
320 //
321 // OK, selected the source and route, fragment the packet then send
322 // them. Tag each fragment other than the first one as spawn from it.
323 //
324 Mtu = IpSb->MaxPacketSize + sizeof (IP4_HEAD);
325
326 if (Packet->TotalSize + HeadLen > Mtu) {
327 //
328 // Fragmentation is disabled for RawData mode.
329 //
330 if (RawData) {
331 return EFI_BAD_BUFFER_SIZE;
332 }
333
334 //
335 // Packet is fragmented from the tail to the head, that is, the
336 // first frame sent is the last fragment of the packet. The first
337 // fragment is NOT sent in this loop. First compute how many
338 // fragments there are.
339 //
340 Mtu = (Mtu - HeadLen) & (~0x07);
341 Num = (Packet->TotalSize + Mtu - 1) / Mtu;
342
343 //
344 // Initialize the packet length and Offset. Other than the last
345 // fragment, the packet length equals to MTU. The offset is always
346 // aligned to MTU.
347 //
348 PacketLen = Packet->TotalSize - (Num - 1) * Mtu;
349 Offset = Mtu * (Num - 1);
350
351 for (Index = 0; Index < Num - 1; Index++, Offset -= Mtu) {
352 Fragment = NetbufGetFragment (Packet, Offset, PacketLen, IP4_MAX_HEADLEN);
353
354 if (Fragment == NULL) {
355 Status = EFI_OUT_OF_RESOURCES;
356 goto ON_ERROR;
357 }
358
359 //
360 // Update the header's fragment. The caller fills the IP4 header
361 // fields that are required by Ip4PrependHead except the fragment.
362 //
363 Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, (Index != 0), Offset);
364 Ip4PrependHead (Fragment, Head, Option, OptLen);
365
366 //
367 // Transmit the fragments, pass the Packet address as the context.
368 // So, we can find all the fragments spawned from the Packet by
369 // compare the NetBuf and Context to the Packet.
370 //
371 Status = Ip4SendFrame (
372 IpIf,
373 IpInstance,
374 Fragment,
375 GateWay,
376 Ip4SysPacketSent,
377 Packet,
378 IpSb
379 );
380
381 if (EFI_ERROR (Status)) {
382 goto ON_ERROR;
383 }
384
385 PacketLen = Mtu;
386 }
387
388 //
389 // Trim the already sent data, then adjust the head's fragment field.
390 //
391 NetbufTrim (Packet, Packet->TotalSize - Mtu, FALSE);
392 Head->Fragment = IP4_HEAD_FRAGMENT_FIELD (FALSE, TRUE, 0);
393 }
394
395 //
396 // Send the first fragment, it is either the original packet, or the
397 // first fragment of a fragmented packet. It seems that there is a subtle
398 // bug here: what if the caller free the packet in Callback and IpIf (or
399 // MNP child used by that interface) still holds the fragments and try
400 // to access the data? The caller can free the packet if it recycles the
401 // consumer's (such as UDP) data in the Callback. But this can't happen.
402 // The detailed sequence is:
403 // 1. for the packets generated by IP4 driver itself:
404 // The Callback is Ip4SysPacketSent, which is the same as the
405 // fragments' callback. Ip4SysPacketSent simply calls NetbufFree
406 // to release its reference to the packet. So, no problem for
407 // system packets.
408 //
409 // 2. for the upper layer's packets (use UDP as an example):
410 // UDP requests the IP layer to transmit some data which is
411 // wrapped in an asynchronous token, the token is wrapped
412 // in IP4_TXTOKEN_WRAP by IP4. IP4 also wrap the user's data
413 // in a net buffer, which is Packet we get here. IP4_TXTOKEN_WRAP
414 // is bound with the Packet. It will only be freed when all
415 // the references to Packet have been released. Upon then, the
416 // Packet's OnFree callback will release the IP4_TXTOKEN_WRAP,
417 // and signal the user's recycle event. So, also no problem for
418 // upper layer's packets.
419 //
420 Ip4PrependHead (Packet, Head, Option, OptLen);
421 Status = Ip4SendFrame (IpIf, IpInstance, Packet, GateWay, Callback, Context, IpSb);
422
423 if (EFI_ERROR (Status)) {
424 goto ON_ERROR;
425 }
426
427 return EFI_SUCCESS;
428
429 ON_ERROR:
430 Ip4CancelPacket (IpIf, Packet, Status);
431 return Status;
432 }
433
434 /**
435 The filter function to find a packet and all its fragments.
436 The packet's fragments have their Context set to the packet.
437
438 @param[in] Frame The frames hold by the low level interface
439 @param[in] Context Context to the function, which is the packet.
440
441 @retval TRUE This is the packet to cancel or its fragments.
442 @retval FALSE This is unrelated packet.
443
444 **/
445 BOOLEAN
446 Ip4CancelPacketFragments (
447 IN IP4_LINK_TX_TOKEN *Frame,
448 IN VOID *Context
449 )
450 {
451 if ((Frame->Packet == (NET_BUF *)Context) || (Frame->Context == Context)) {
452 return TRUE;
453 }
454
455 return FALSE;
456 }
457
458 /**
459 Cancel the Packet and all its fragments.
460
461 @param IpIf The interface from which the Packet is sent
462 @param Packet The Packet to cancel
463 @param IoStatus The status returns to the sender.
464
465 **/
466 VOID
467 Ip4CancelPacket (
468 IN IP4_INTERFACE *IpIf,
469 IN NET_BUF *Packet,
470 IN EFI_STATUS IoStatus
471 )
472 {
473 Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
474 }