TianoCore EDK2 master
Loading...
Searching...
No Matches
Ip4Output.c
Go to the documentation of this file.
1
9#include "Ip4Impl.h"
10
11UINT16 mIp4Id;
12
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
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
157VOID
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
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,
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,
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
429ON_ERROR:
430 Ip4CancelPacket (IpIf, Packet, Status);
431 return Status;
432}
433
445BOOLEAN
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
466VOID
468 IN IP4_INTERFACE *IpIf,
469 IN NET_BUF *Packet,
470 IN EFI_STATUS IoStatus
471 )
472{
473 Ip4CancelFrames (IpIf, IoStatus, Ip4CancelPacketFragments, Packet);
474}
IP4_INTERFACE * Ip4FindInterface(IN IP4_SERVICE *IpSb, IN IP4_ADDR Ip)
Definition: Ip4Common.c:124
INTN Ip4GetNetCast(IN IP4_ADDR IpAddr, IN IP4_INTERFACE *IpIf)
Definition: Ip4Common.c:26
IP4_INTERFACE * Ip4FindNet(IN IP4_SERVICE *IpSb, IN IP4_ADDR Ip)
Definition: Ip4Common.c:153
#define IP4_HEAD_FRAGMENT_FIELD(Df, Mf, Offset)
Definition: Ip4Common.h:51
EFI_STATUS Ip4SendFrame(IN IP4_INTERFACE *Interface, IN IP4_PROTOCOL *IpInstance OPTIONAL, IN NET_BUF *Packet, IN IP4_ADDR NextHop, IN IP4_FRAME_CALLBACK CallBack, IN VOID *Context, IN IP4_SERVICE *IpSb)
Definition: Ip4If.c:1052
VOID Ip4CancelFrames(IN IP4_INTERFACE *Interface, IN EFI_STATUS IoStatus, IN IP4_FRAME_TO_CANCEL FrameToCancel OPTIONAL, IN VOID *Context)
Definition: Ip4If.c:425
VOID(* IP4_FRAME_CALLBACK)(IN IP4_PROTOCOL *IpInstance OPTIONAL, IN NET_BUF *Packet, IN EFI_STATUS IoStatus, IN UINT32 LinkFlag, IN VOID *Context)
Definition: Ip4If.h:42
EFI_STATUS Ip4IpSecProcessPacket(IN IP4_SERVICE *IpSb, IN OUT IP4_HEAD **Head, IN OUT NET_BUF **Netbuf, IN OUT UINT8 **Options, IN OUT UINT32 *OptionsLen, IN EFI_IPSEC_TRAFFIC_DIR Direction, IN VOID *Context)
Definition: Ip4Input.c:482
EFI_STATUS Ip4CopyOption(IN UINT8 *Option, IN UINT32 OptionLen, IN BOOLEAN FirstFragment, IN OUT UINT8 *Buf OPTIONAL, IN OUT UINT32 *BufLen)
Definition: Ip4Option.c:111
VOID Ip4SysPacketSent(IP4_PROTOCOL *Ip4Instance, NET_BUF *Packet, EFI_STATUS IoStatus, UINT32 LinkFlag, VOID *Context)
Definition: Ip4Output.c:158
EFI_STATUS Ip4PrependHead(IN OUT NET_BUF *Packet, IN IP4_HEAD *Head, IN UINT8 *Option, IN UINT32 OptLen)
Definition: Ip4Output.c:32
EFI_STATUS Ip4Output(IN IP4_SERVICE *IpSb, IN IP4_PROTOCOL *IpInstance OPTIONAL, IN NET_BUF *Packet, IN IP4_HEAD *Head, IN UINT8 *Option, IN UINT32 OptLen, IN IP4_ADDR GateWay, IN IP4_FRAME_CALLBACK Callback, IN VOID *Context)
Definition: Ip4Output.c:205
BOOLEAN Ip4CancelPacketFragments(IN IP4_LINK_TX_TOKEN *Frame, IN VOID *Context)
Definition: Ip4Output.c:446
IP4_INTERFACE * Ip4SelectInterface(IN IP4_SERVICE *IpSb, IN IP4_ADDR Dst, IN IP4_ADDR Src)
Definition: Ip4Output.c:97
VOID Ip4CancelPacket(IN IP4_INTERFACE *IpIf, IN NET_BUF *Packet, IN EFI_STATUS IoStatus)
Definition: Ip4Output.c:467
VOID Ip4FreeRouteCacheEntry(IN IP4_ROUTE_CACHE_ENTRY *RtCacheEntry)
Definition: Ip4Route.c:113
IP4_ROUTE_CACHE_ENTRY * Ip4Route(IN IP4_ROUTE_TABLE *RtTable, IN IP4_ADDR Dest, IN IP4_ADDR Src, IN IP4_ADDR SubnetMask, IN BOOLEAN AlwaysTryDestAddr)
Definition: Ip4Route.c:484
@ EfiIPsecOutBound
Definition: IpSecConfig.h:141
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
VOID EFIAPI NetbufFree(IN NET_BUF *Nbuf)
Definition: NetBuffer.c:195
UINT32 EFIAPI NetbufTrim(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1134
UINT16 EFIAPI NetblockChecksum(IN UINT8 *Bulk, IN UINT32 Len)
Definition: NetBuffer.c:1615
NET_BUF *EFIAPI NetbufGetFragment(IN NET_BUF *Nbuf, IN UINT32 Offset, IN UINT32 Len, IN UINT32 HeadSpace)
Definition: NetBuffer.c:510
UINT8 *EFIAPI NetbufAllocSpace(IN OUT NET_BUF *Nbuf, IN UINT32 Len, IN BOOLEAN FromHead)
Definition: NetBuffer.c:1015
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112