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