]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_udp.c
1. Add EFI LOADED IMAGE DEVICE PATH Protocol in LoadImage() service, per UEFI 2.1b.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_bc_udp.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2004 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13 pxe_bc_udp.c\r
14\r
15Abstract:\r
16\r
17\r
18**/\r
19\r
20#include "Bc.h"\r
21\r
22//\r
23// //////////////////////////////////////////////////////////////////////\r
24//\r
25// Udp Write Routine - called by base code - e.g. TFTP - already locked\r
26//\r
27\r
28/**\r
29\r
30 @return EFI_SUCCESS :=\r
31 @return EFI_INVALID_PARAMETER :=\r
32 @return other :=\r
33\r
34**/\r
35EFI_STATUS\r
36UdpWrite (\r
37 IN PXE_BASECODE_DEVICE *Private,\r
38 IN UINT16 OpFlags,\r
39 IN EFI_IP_ADDRESS *DestIpPtr,\r
40 IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
41 IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
42 IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
43 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
44 IN UINTN *HeaderSizePtr, OPTIONAL\r
45 IN VOID *HeaderPtr, OPTIONAL\r
46 IN UINTN *BufferSizeptr,\r
47 IN VOID *BufferPtr\r
48 )\r
49{\r
50 UINTN TotalLength;\r
51 UINTN HeaderSize;\r
52 EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort;\r
53\r
54 //\r
55 //\r
56 //\r
57 HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
58 DefaultSrcPort = 0;\r
59\r
60 //\r
61 // check parameters\r
62 //\r
63 if (BufferSizeptr == NULL ||\r
64 BufferPtr == NULL ||\r
65 DestIpPtr == NULL ||\r
66 DestPortPtr == NULL ||\r
67 (HeaderSizePtr != NULL && *HeaderSizePtr == 0) ||\r
68 (HeaderSize != 0 && HeaderPtr == NULL) ||\r
69 (GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) ||\r
70 (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))\r
71 ) {\r
72 DEBUG (\r
73 (DEBUG_WARN,\r
74 "\nUdpWrite() Exit #1 %xh (%r)",\r
75 EFI_INVALID_PARAMETER,\r
76 EFI_INVALID_PARAMETER)\r
77 );\r
78\r
79 return EFI_INVALID_PARAMETER;\r
80 }\r
81\r
82 TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER);\r
83\r
84 if (TotalLength > 0x0000ffff) {\r
85 DEBUG (\r
86 (DEBUG_WARN,\r
87 "\nUdpWrite() Exit #2 %xh (%r)",\r
88 EFI_BAD_BUFFER_SIZE,\r
89 EFI_BAD_BUFFER_SIZE)\r
90 );\r
91\r
92 return EFI_BAD_BUFFER_SIZE;\r
93 }\r
94\r
95 if (SrcIpPtr == NULL) {\r
96 SrcIpPtr = &Private->EfiBc.Mode->StationIp;\r
97 }\r
98\r
99 if (SrcPortPtr == NULL) {\r
100 SrcPortPtr = &DefaultSrcPort;\r
101 OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;\r
102 }\r
103\r
104 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {\r
105 *SrcPortPtr = Private->RandomPort;\r
106\r
107 if (++Private->RandomPort == 0) {\r
108 Private->RandomPort = PXE_RND_PORT_LOW;\r
109 }\r
110 }\r
111\r
112#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
113 //\r
114 // build pseudo header and udp header in transmit buffer\r
115 //\r
116#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER)))\r
117\r
118 Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
119 Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
120 Udpv4Base->Udpv4PseudoHeader.Zero = 0;\r
121 Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP;\r
122 Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength);\r
123 Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr);\r
124 Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr);\r
125 Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength;\r
126 Udpv4Base->Udpv4Header.Checksum = 0;\r
127\r
128 if (HeaderSize != 0) {\r
129 CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize);\r
130 }\r
131\r
132 HeaderSize += sizeof (UDPV4_HEADER);\r
133\r
134 Udpv4Base->Udpv4Header.Checksum = IpChecksum2 (\r
135 (UINT16 *) Udpv4Base,\r
136 HeaderSize + sizeof (UDPV4_PSEUDO_HEADER),\r
137 (UINT16 *) BufferPtr,\r
138 (UINT16) *BufferSizeptr\r
139 );\r
140\r
141 if (Udpv4Base->Udpv4Header.Checksum == 0) {\r
142 Udpv4Base->Udpv4Header.Checksum = 0xffff;\r
143 //\r
144 // transmit zero checksum as ones complement\r
145 //\r
146 }\r
147\r
148 return Ip4Send (\r
149 Private,\r
150 OpFlags,\r
151 PROT_UDP,\r
152 Udpv4Base->Udpv4PseudoHeader.SrcAddr.L,\r
153 Udpv4Base->Udpv4PseudoHeader.DestAddr.L,\r
154 (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,\r
155 HeaderSize,\r
156 BufferPtr,\r
157 *BufferSizeptr\r
158 );\r
159}\r
160//\r
161// //////////////////////////////////////////////////////////\r
162//\r
163// BC Udp Write Routine\r
164//\r
165\r
166/**\r
167\r
168 @return EFI_SUCCESS :=\r
169 @return other :=\r
170\r
171**/\r
172EFI_STATUS\r
173EFIAPI\r
174BcUdpWrite (\r
175 IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
176 IN UINT16 OpFlags,\r
177 IN EFI_IP_ADDRESS *DestIpPtr,\r
178 IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
179 IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
180 IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
181 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
182 IN UINTN *HeaderSizePtr, OPTIONAL\r
183 IN VOID *HeaderPtr, OPTIONAL\r
184 IN UINTN *BufferSizeptr,\r
185 IN VOID *BufferPtr\r
186 )\r
187{\r
188 EFI_STATUS StatCode;\r
189 PXE_BASECODE_DEVICE *Private;\r
190\r
191 //\r
192 // Lock the instance data and make sure started\r
193 //\r
194 StatCode = EFI_SUCCESS;\r
195\r
196 if (This == NULL) {\r
197 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
198 return EFI_INVALID_PARAMETER;\r
199 }\r
200\r
201 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
202\r
203 if (Private == NULL) {\r
204 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
205 return EFI_INVALID_PARAMETER;\r
206 }\r
207\r
208 EfiAcquireLock (&Private->Lock);\r
209\r
210 if (This->Mode == NULL || !This->Mode->Started) {\r
211 DEBUG ((DEBUG_ERROR, "BC was not started."));\r
212 EfiReleaseLock (&Private->Lock);\r
213 return EFI_NOT_STARTED;\r
214 }\r
215\r
216 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE;\r
217\r
218 //\r
219 // Issue BC command\r
220 //\r
221 StatCode = UdpWrite (\r
222 Private,\r
223 OpFlags,\r
224 DestIpPtr,\r
225 DestPortPtr,\r
226 GatewayIpPtr,\r
227 SrcIpPtr,\r
228 SrcPortPtr,\r
229 HeaderSizePtr,\r
230 HeaderPtr,\r
231 BufferSizeptr,\r
232 BufferPtr\r
233 );\r
234\r
235 //\r
236 // Unlock the instance data\r
237 //\r
238 EfiReleaseLock (&Private->Lock);\r
239 return StatCode;\r
240}\r
241//\r
242// /////////////////////////////////////////////////////////////////////\r
243//\r
244// Udp Read Routine - called by base code - e.g. TFTP - already locked\r
245//\r
246\r
247/**\r
248\r
249 @return EFI_SUCCESS :=\r
250 @return EFI_INVALID_PARAMETER :=\r
251 @return other :=\r
252\r
253**/\r
254EFI_STATUS\r
255UdpRead (\r
256 IN PXE_BASECODE_DEVICE *Private,\r
257 IN UINT16 OpFlags,\r
258 IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL\r
259 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, OPTIONAL\r
260 IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
261 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
262 IN UINTN *HeaderSizePtr, OPTIONAL\r
263 IN VOID *HeaderPtr, OPTIONAL\r
264 IN OUT UINTN *BufferSizeptr,\r
265 IN VOID *BufferPtr,\r
266 EFI_EVENT TimeoutEvent\r
267 )\r
268{\r
269 EFI_STATUS StatCode;\r
270 EFI_IP_ADDRESS TmpSrcIp;\r
271 EFI_IP_ADDRESS TmpDestIp;\r
272 UINTN BufferSize;\r
273 UINTN HeaderSize;\r
274\r
275 //\r
276 // combination structure of pseudo header/udp header\r
277 //\r
278#pragma pack (1)\r
279 struct {\r
280 UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;\r
281 UDPV4_HEADER Udpv4Header;\r
282 UINT8 ProtHdr[64];\r
283 } Hdrs;\r
284#pragma pack ()\r
285\r
286 HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
287 //\r
288 // read [with filtering]\r
289 // check parameters\r
290 //\r
291 if (BufferSizeptr == NULL ||\r
292 BufferPtr == NULL ||\r
293 (HeaderSize != 0 && HeaderPtr == NULL) ||\r
294 (OpFlags &~UDP_FILTER_MASK)\r
295 //\r
296 // if filtering on a particular IP/Port, need it\r
297 //\r
298 ||\r
299 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) ||\r
300 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) ||\r
301 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL)\r
302 ) {\r
303 DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #1 Invalid Parameter"));\r
304 return EFI_INVALID_PARAMETER;\r
305 }\r
306\r
307 //\r
308 // in case we loop\r
309 //\r
310 BufferSize = *BufferSizeptr;\r
311 //\r
312 // we need source and dest IPs for pseudo header\r
313 //\r
314 if (SrcIpPtr == NULL) {\r
315 SrcIpPtr = &TmpSrcIp;\r
316 }\r
317\r
318 if (DestIpPtr == NULL) {\r
319 DestIpPtr = &TmpDestIp;\r
67a58d0f 320 CopyMem (&TmpDestIp, &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));\r
772db4bb 321 }\r
322\r
772db4bb 323 for (;;) {\r
324 *BufferSizeptr = BufferSize;\r
325\r
326 StatCode = IpReceive (\r
327 Private,\r
328 OpFlags,\r
329 SrcIpPtr,\r
330 DestIpPtr,\r
331 PROT_UDP,\r
332 &Hdrs.Udpv4Header,\r
333 HeaderSize + sizeof Hdrs.Udpv4Header,\r
334 BufferPtr,\r
335 BufferSizeptr,\r
336 TimeoutEvent\r
337 );\r
338\r
339 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
340 UINT16 SPort;\r
341 UINT16 DPort;\r
342\r
343 SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);\r
344 DPort = NTOHS (Hdrs.Udpv4Header.DestPort);\r
345\r
346 //\r
347 // do filtering\r
348 //\r
349 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {\r
350 continue;\r
351 }\r
352\r
353 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {\r
354 continue;\r
355 }\r
356 //\r
357 // check checksum\r
358 //\r
359 if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {\r
360 Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
361 Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
362 Hdrs.Udpv4PseudoHeader.Zero = 0;\r
363 Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;\r
364 Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;\r
365\r
366 if (Hdrs.Udpv4Header.Checksum == 0xffff) {\r
367 Hdrs.Udpv4Header.Checksum = 0;\r
368 }\r
369\r
370 if (IpChecksum2 (\r
371 (UINT16 *) &Hdrs.Udpv4PseudoHeader,\r
372 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),\r
373 (UINT16 *) BufferPtr,\r
374 *BufferSizeptr\r
375 )) {\r
376 DEBUG (\r
377 (DEBUG_INFO,\r
378 "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",\r
67a58d0f 379 &Hdrs.Udpv4PseudoHeader)\r
772db4bb 380 );\r
381 DEBUG (\r
382 (DEBUG_INFO,\r
383 "\nUdpRead() Header size == %d",\r
384 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))\r
385 );\r
386 DEBUG (\r
387 (DEBUG_INFO,\r
388 "\nUdpRead() BufferPtr == %Xh",\r
389 BufferPtr)\r
390 );\r
391 DEBUG (\r
392 (DEBUG_INFO,\r
393 "\nUdpRead() Buffer size == %d",\r
394 *BufferSizeptr)\r
395 );\r
396 DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #2 Device Error"));\r
397 return EFI_DEVICE_ERROR;\r
398 }\r
399 }\r
400 //\r
401 // all passed\r
402 //\r
403 if (SrcPortPtr != NULL) {\r
404 *SrcPortPtr = SPort;\r
405 }\r
406\r
407 if (DestPortPtr != NULL) {\r
408 *DestPortPtr = DPort;\r
409 }\r
410\r
411 if (HeaderSize != 0) {\r
412 CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);\r
413 }\r
414 }\r
415\r
416 if ((StatCode != EFI_SUCCESS) && (StatCode != EFI_TIMEOUT)) {\r
417 DEBUG (\r
418 (DEBUG_INFO,\r
419 "\nUdpRead() Exit #3 %Xh %r",\r
420 StatCode,\r
421 StatCode)\r
422 );\r
423 }\r
424\r
425 return StatCode;\r
426 }\r
427}\r
428//\r
429// //////////////////////////////////////////////////////////\r
430//\r
431// BC Udp Read Routine\r
432//\r
433\r
434/**\r
435\r
436 @return EFI_SUCCESS :=\r
437 @return other :=\r
438\r
439**/\r
440EFI_STATUS\r
441EFIAPI\r
442BcUdpRead (\r
443 IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
444 IN UINT16 OpFlags,\r
445 IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL\r
446 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL\r
447 IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL\r
448 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL\r
449 IN UINTN *HeaderSize, OPTIONAL\r
450 IN VOID *HeaderPtr, OPTIONAL\r
451 IN OUT UINTN *BufferSize,\r
452 IN VOID *BufferPtr\r
453 )\r
454{\r
455 EFI_STATUS StatCode;\r
456 PXE_BASECODE_DEVICE *Private;\r
457\r
458 //\r
459 // Lock the instance data and make sure started\r
460 //\r
461 StatCode = EFI_SUCCESS;\r
462\r
463 if (This == NULL) {\r
464 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));\r
465 return EFI_INVALID_PARAMETER;\r
466 }\r
467\r
468 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
469\r
470 if (Private == NULL) {\r
471 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
472 return EFI_INVALID_PARAMETER;\r
473 }\r
474\r
475 EfiAcquireLock (&Private->Lock);\r
476\r
477 if (This->Mode == NULL || !This->Mode->Started) {\r
478 DEBUG ((DEBUG_ERROR, "BC was not started."));\r
479 EfiReleaseLock (&Private->Lock);\r
480 return EFI_NOT_STARTED;\r
481 }\r
482\r
483 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;\r
484\r
485 //\r
486 // Issue BC command\r
487 //\r
488 StatCode = UdpRead (\r
489 Private,\r
490 OpFlags,\r
491 DestIp,\r
492 DestPort,\r
493 SrcIp,\r
494 SrcPort,\r
495 HeaderSize,\r
496 HeaderPtr,\r
497 BufferSize,\r
498 BufferPtr,\r
499 0\r
500 );\r
501\r
502 //\r
503 // Unlock the instance data and return\r
504 //\r
505 EfiReleaseLock (&Private->Lock);\r
506 return StatCode;\r
507}\r
508\r
509/* eof - pxe_bc_udp.c */\r