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