]>
Commit | Line | Data |
---|---|---|
772db4bb | 1 | /** @file\r |
3e8c18da | 2 | Transmit the IP4 packet.\r |
d1102dba LG |
3 | \r |
4 | Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r | |
9d510e61 | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
772db4bb | 6 | \r |
772db4bb | 7 | **/\r |
8 | \r | |
9 | #include "Ip4Impl.h"\r | |
10 | \r | |
11 | UINT16 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 | |
31 | EFI_STATUS\r | |
32 | Ip4PrependHead (\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 | |
96 | IP4_INTERFACE *\r | |
97 | Ip4SelectInterface (\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 |
157 | VOID\r | |
158 | Ip4SysPacketSent (\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 | |
204 | EFI_STATUS\r | |
205 | Ip4Output (\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 | |
429 | ON_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 | 445 | BOOLEAN\r |
446 | Ip4CancelPacketFragments (\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 |
466 | VOID\r | |
467 | Ip4CancelPacket (\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 |