]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_bc_udp.c
Initial import.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_bc_udp.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, 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
27EFI_STATUS\r
28UdpWrite (\r
29 IN PXE_BASECODE_DEVICE *Private,\r
30 IN UINT16 OpFlags,\r
31 IN EFI_IP_ADDRESS *DestIpPtr,\r
32 IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
33 IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
34 IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
35 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
36 IN UINTN *HeaderSizePtr, OPTIONAL\r
37 IN VOID *HeaderPtr, OPTIONAL\r
38 IN UINTN *BufferSizeptr,\r
39 IN VOID *BufferPtr\r
40 )\r
41/*++\r
42Routine description:\r
43 UDP write packet.\r
44\r
45Parameters:\r
46 Private := Pointer to PxeBc interface\r
47 OpFlags := \r
48 DestIpPtr := \r
49 DestPortPtr := \r
50 GatewayIpPtr := \r
51 SrcIpPtr := \r
52 SrcPortPtr := \r
53 HeaderSizePtr := \r
54 HeaderPtr := \r
55 BufferSizeptr := \r
56 BufferPtr := \r
57\r
58Returns:\r
59 EFI_SUCCESS := \r
60 EFI_INVALID_PARAMETER := \r
61 other := \r
62--*/\r
63{\r
64 UINTN TotalLength;\r
65 UINTN HeaderSize;\r
66 EFI_PXE_BASE_CODE_UDP_PORT DefaultSrcPort;\r
67\r
68 //\r
69 //\r
70 //\r
71 HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
72 DefaultSrcPort = 0;\r
73\r
74 //\r
75 // check parameters\r
76 //\r
77 if (BufferSizeptr == NULL ||\r
78 BufferPtr == NULL ||\r
79 DestIpPtr == NULL ||\r
80 DestPortPtr == NULL ||\r
81 (HeaderSizePtr != NULL && *HeaderSizePtr == 0) ||\r
82 (HeaderSize != 0 && HeaderPtr == NULL) ||\r
83 (GatewayIpPtr != NULL && !IS_INADDR_UNICAST(GatewayIpPtr)) ||\r
84 (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))\r
85 ) {\r
86 DEBUG (\r
87 (EFI_D_WARN,\r
88 "\nUdpWrite() Exit #1 %xh (%r)",\r
89 EFI_INVALID_PARAMETER,\r
90 EFI_INVALID_PARAMETER)\r
91 );\r
92\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
95\r
96 TotalLength = *BufferSizeptr + HeaderSize + sizeof (UDPV4_HEADER);\r
97\r
98 if (TotalLength > 0x0000ffff) {\r
99 DEBUG (\r
100 (EFI_D_WARN,\r
101 "\nUdpWrite() Exit #2 %xh (%r)",\r
102 EFI_BAD_BUFFER_SIZE,\r
103 EFI_BAD_BUFFER_SIZE)\r
104 );\r
105\r
106 return EFI_BAD_BUFFER_SIZE;\r
107 }\r
108\r
109 if (SrcIpPtr == NULL) {\r
110 SrcIpPtr = &Private->EfiBc.Mode->StationIp;\r
111 }\r
112\r
113 if (SrcPortPtr == NULL) {\r
114 SrcPortPtr = &DefaultSrcPort;\r
115 OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;\r
116 }\r
117\r
118 if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {\r
119 *SrcPortPtr = Private->RandomPort;\r
120\r
121 if (++Private->RandomPort == 0) {\r
122 Private->RandomPort = PXE_RND_PORT_LOW;\r
123 }\r
124 }\r
125\r
126#define IpTxBuffer ((IPV4_BUFFER *) Private->TransmitBufferPtr)\r
127 //\r
128 // build pseudo header and udp header in transmit buffer\r
129 //\r
130#define Udpv4Base ((UDPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (UDPV4_PSEUDO_HEADER)))\r
131\r
132 Udpv4Base->Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
133 Udpv4Base->Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
134 Udpv4Base->Udpv4PseudoHeader.Zero = 0;\r
135 Udpv4Base->Udpv4PseudoHeader.Protocol = PROT_UDP;\r
136 Udpv4Base->Udpv4PseudoHeader.TotalLength = HTONS (TotalLength);\r
137 Udpv4Base->Udpv4Header.SrcPort = HTONS (*SrcPortPtr);\r
138 Udpv4Base->Udpv4Header.DestPort = HTONS (*DestPortPtr);\r
139 Udpv4Base->Udpv4Header.TotalLength = Udpv4Base->Udpv4PseudoHeader.TotalLength;\r
140 Udpv4Base->Udpv4Header.Checksum = 0;\r
141\r
142 if (HeaderSize != 0) {\r
143 CopyMem (IpTxBuffer->u.Udp.Data, HeaderPtr, HeaderSize);\r
144 }\r
145\r
146 HeaderSize += sizeof (UDPV4_HEADER);\r
147\r
148 Udpv4Base->Udpv4Header.Checksum = IpChecksum2 (\r
149 (UINT16 *) Udpv4Base,\r
150 HeaderSize + sizeof (UDPV4_PSEUDO_HEADER),\r
151 (UINT16 *) BufferPtr,\r
152 (UINT16) *BufferSizeptr\r
153 );\r
154\r
155 if (Udpv4Base->Udpv4Header.Checksum == 0) {\r
156 Udpv4Base->Udpv4Header.Checksum = 0xffff;\r
157 //\r
158 // transmit zero checksum as ones complement\r
159 //\r
160 }\r
161\r
162 return Ip4Send (\r
163 Private,\r
164 OpFlags,\r
165 PROT_UDP,\r
166 Udpv4Base->Udpv4PseudoHeader.SrcAddr.L,\r
167 Udpv4Base->Udpv4PseudoHeader.DestAddr.L,\r
168 (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,\r
169 HeaderSize,\r
170 BufferPtr,\r
171 *BufferSizeptr\r
172 );\r
173}\r
174//\r
175// //////////////////////////////////////////////////////////\r
176//\r
177// BC Udp Write Routine\r
178//\r
179EFI_STATUS\r
180EFIAPI\r
181BcUdpWrite (\r
182 IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
183 IN UINT16 OpFlags,\r
184 IN EFI_IP_ADDRESS *DestIpPtr,\r
185 IN EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr,\r
186 IN EFI_IP_ADDRESS *GatewayIpPtr, OPTIONAL\r
187 IN EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
188 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
189 IN UINTN *HeaderSizePtr, OPTIONAL\r
190 IN VOID *HeaderPtr, OPTIONAL\r
191 IN UINTN *BufferSizeptr,\r
192 IN VOID *BufferPtr\r
193 )\r
194/*++\r
195Routine description:\r
196 UDP write API entry point.\r
197\r
198Parameters:\r
199 This := Pointer to PxeBc interface.\r
200 OpFlags := \r
201 DestIpPtr := \r
202 DestPortPtr := \r
203 GatewayIpPtr := \r
204 SrcIpPtr := \r
205 SrcPortPtr := \r
206 HeaderSizePtr := \r
207 HeaderPtr := \r
208 BufferSizeptr := \r
209 BufferPtr := \r
210\r
211Returns:\r
212 EFI_SUCCESS := \r
213 other := \r
214--*/\r
215{\r
216 EFI_STATUS StatCode;\r
217 PXE_BASECODE_DEVICE *Private;\r
218\r
219 //\r
220 // Lock the instance data and make sure started\r
221 //\r
222 StatCode = EFI_SUCCESS;\r
223\r
224 if (This == NULL) {\r
225 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));\r
226 return EFI_INVALID_PARAMETER;\r
227 }\r
228\r
229 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
230\r
231 if (Private == NULL) {\r
232 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
233 return EFI_INVALID_PARAMETER;\r
234 }\r
235\r
236 EfiAcquireLock (&Private->Lock);\r
237\r
238 if (This->Mode == NULL || !This->Mode->Started) {\r
239 DEBUG ((EFI_D_ERROR, "BC was not started."));\r
240 EfiReleaseLock (&Private->Lock);\r
241 return EFI_NOT_STARTED;\r
242 }\r
243\r
244 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_WRITE;\r
245\r
246 //\r
247 // Issue BC command\r
248 //\r
249 StatCode = UdpWrite (\r
250 Private,\r
251 OpFlags,\r
252 DestIpPtr,\r
253 DestPortPtr,\r
254 GatewayIpPtr,\r
255 SrcIpPtr,\r
256 SrcPortPtr,\r
257 HeaderSizePtr,\r
258 HeaderPtr,\r
259 BufferSizeptr,\r
260 BufferPtr\r
261 );\r
262\r
263 //\r
264 // Unlock the instance data\r
265 //\r
266 EfiReleaseLock (&Private->Lock);\r
267 return StatCode;\r
268}\r
269//\r
270// /////////////////////////////////////////////////////////////////////\r
271//\r
272// Udp Read Routine - called by base code - e.g. TFTP - already locked\r
273//\r
274EFI_STATUS\r
275UdpRead (\r
276 IN PXE_BASECODE_DEVICE *Private,\r
277 IN UINT16 OpFlags,\r
278 IN OUT EFI_IP_ADDRESS *DestIpPtr, OPTIONAL\r
279 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPortPtr, OPTIONAL\r
280 IN OUT EFI_IP_ADDRESS *SrcIpPtr, OPTIONAL\r
281 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPortPtr, OPTIONAL\r
282 IN UINTN *HeaderSizePtr, OPTIONAL\r
283 IN VOID *HeaderPtr, OPTIONAL\r
284 IN OUT UINTN *BufferSizeptr,\r
285 IN VOID *BufferPtr,\r
286 EFI_EVENT TimeoutEvent\r
287 )\r
288/*++\r
289Routine description:\r
290 UDP read packet.\r
291\r
292Parameters:\r
293 Private := Pointer to PxeBc interface\r
294 OpFlags := \r
295 DestIpPtr := \r
296 DestPortPtr := \r
297 SrcIpPtr := \r
298 SrcPortPtr := \r
299 HeaderSizePtr := \r
300 HeaderPtr := \r
301 BufferSizeptr := \r
302 BufferPtr := \r
303 TimeoutEvent :=\r
304\r
305Returns:\r
306 EFI_SUCCESS := \r
307 EFI_INVALID_PARAMETER := \r
308 other := \r
309--*/\r
310{\r
311 EFI_STATUS StatCode;\r
312 EFI_IP_ADDRESS TmpSrcIp;\r
313 EFI_IP_ADDRESS TmpDestIp;\r
314 UINTN BufferSize;\r
315 UINTN HeaderSize;\r
316\r
317 //\r
318 // combination structure of pseudo header/udp header\r
319 //\r
320#pragma pack (1)\r
321 struct {\r
322 UDPV4_PSEUDO_HEADER Udpv4PseudoHeader;\r
323 UDPV4_HEADER Udpv4Header;\r
324 UINT8 ProtHdr[64];\r
325 } Hdrs;\r
326#pragma pack ()\r
327\r
328 HeaderSize = (HeaderSizePtr != NULL) ? *HeaderSizePtr : 0;\r
329 //\r
330 // read [with filtering]\r
331 // check parameters\r
332 //\r
333 if (BufferSizeptr == NULL ||\r
334 BufferPtr == NULL ||\r
335 (HeaderSize != 0 && HeaderPtr == NULL) ||\r
336 (OpFlags &~UDP_FILTER_MASK)\r
337 //\r
338 // if filtering on a particular IP/Port, need it\r
339 //\r
340 ||\r
341 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) && SrcIpPtr == NULL) ||\r
342 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && SrcPortPtr == NULL) ||\r
343 (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && DestPortPtr == NULL)\r
344 ) {\r
345 DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #1 Invalid Parameter"));\r
346 return EFI_INVALID_PARAMETER;\r
347 }\r
348\r
349 //\r
350 // in case we loop\r
351 //\r
352 BufferSize = *BufferSizeptr;\r
353 //\r
354 // we need source and dest IPs for pseudo header\r
355 //\r
356 if (SrcIpPtr == NULL) {\r
357 SrcIpPtr = &TmpSrcIp;\r
358 }\r
359\r
360 if (DestIpPtr == NULL) {\r
361 DestIpPtr = &TmpDestIp;\r
362 CopyMem (&TmpDestIp, &Private->EfiBc.Mode->StationIp, sizeof (TmpDestIp));\r
363 }\r
364\r
365#if SUPPORT_IPV6\r
366 if (Private->EfiBc.Mode->UsingIpv6) {\r
367 //\r
368 // %%TBD\r
369 //\r
370 }\r
371#endif\r
372\r
373 for (;;) {\r
374 *BufferSizeptr = BufferSize;\r
375\r
376 StatCode = IpReceive (\r
377 Private,\r
378 OpFlags,\r
379 SrcIpPtr,\r
380 DestIpPtr,\r
381 PROT_UDP,\r
382 &Hdrs.Udpv4Header,\r
383 HeaderSize + sizeof Hdrs.Udpv4Header,\r
384 BufferPtr,\r
385 BufferSizeptr,\r
386 TimeoutEvent\r
387 );\r
388\r
389 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {\r
390 UINT16 SPort;\r
391 UINT16 DPort;\r
392\r
393 SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);\r
394 DPort = NTOHS (Hdrs.Udpv4Header.DestPort);\r
395\r
396 //\r
397 // do filtering\r
398 //\r
399 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {\r
400 continue;\r
401 }\r
402\r
403 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {\r
404 continue;\r
405 }\r
406 //\r
407 // check checksum\r
408 //\r
409 if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {\r
410 Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];\r
411 Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];\r
412 Hdrs.Udpv4PseudoHeader.Zero = 0;\r
413 Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;\r
414 Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;\r
415\r
416 if (Hdrs.Udpv4Header.Checksum == 0xffff) {\r
417 Hdrs.Udpv4Header.Checksum = 0;\r
418 }\r
419\r
420 if (IpChecksum2 (\r
421 (UINT16 *) &Hdrs.Udpv4PseudoHeader,\r
422 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),\r
423 (UINT16 *) BufferPtr,\r
424 *BufferSizeptr\r
425 )) {\r
426 DEBUG (\r
427 (EFI_D_INFO,\r
428 "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",\r
429 &Hdrs.Udpv4PseudoHeader)\r
430 );\r
431 DEBUG (\r
432 (EFI_D_INFO,\r
433 "\nUdpRead() Header size == %d",\r
434 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))\r
435 );\r
436 DEBUG (\r
437 (EFI_D_INFO,\r
438 "\nUdpRead() BufferPtr == %Xh",\r
439 BufferPtr)\r
440 );\r
441 DEBUG (\r
442 (EFI_D_INFO,\r
443 "\nUdpRead() Buffer size == %d",\r
444 *BufferSizeptr)\r
445 );\r
446 DEBUG ((EFI_D_INFO, "\nUdpRead() Exit #2 Device Error"));\r
447 return EFI_DEVICE_ERROR;\r
448 }\r
449 }\r
450 //\r
451 // all passed\r
452 //\r
453 if (SrcPortPtr != NULL) {\r
454 *SrcPortPtr = SPort;\r
455 }\r
456\r
457 if (DestPortPtr != NULL) {\r
458 *DestPortPtr = DPort;\r
459 }\r
460\r
461 if (HeaderSize != 0) {\r
462 CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);\r
463 }\r
464 }\r
465\r
466 switch (StatCode) {\r
467 case EFI_SUCCESS:\r
468 case EFI_TIMEOUT:\r
469 break;\r
470\r
471 default:\r
472 DEBUG (\r
473 (EFI_D_INFO,\r
474 "\nUdpRead() Exit #3 %Xh %r",\r
475 StatCode,\r
476 StatCode)\r
477 );\r
478 }\r
479\r
480 return StatCode;\r
481 }\r
482}\r
483//\r
484// //////////////////////////////////////////////////////////\r
485//\r
486// BC Udp Read Routine\r
487//\r
488EFI_STATUS\r
489EFIAPI\r
490BcUdpRead (\r
491 IN EFI_PXE_BASE_CODE_PROTOCOL *This,\r
492 IN UINT16 OpFlags,\r
493 IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL\r
494 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL\r
495 IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL\r
496 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL\r
497 IN UINTN *HeaderSize, OPTIONAL\r
498 IN VOID *HeaderPtr, OPTIONAL\r
499 IN OUT UINTN *BufferSize,\r
500 IN VOID *BufferPtr\r
501 )\r
502/*++\r
503Routine description:\r
504 UDP read API entry point.\r
505\r
506Parameters:\r
507 This := Pointer to PxeBc interface.\r
508 OpFlags := \r
509 DestIpPtr := \r
510 DestPortPtr := \r
511 SrcIpPtr := \r
512 SrcPortPtr := \r
513 HeaderSizePtr := \r
514 HeaderPtr := \r
515 BufferSizeptr := \r
516 BufferPtr := \r
517\r
518Returns:\r
519 EFI_SUCCESS := \r
520 other := \r
521--*/\r
522{\r
523 EFI_STATUS StatCode;\r
524 PXE_BASECODE_DEVICE *Private;\r
525\r
526 //\r
527 // Lock the instance data and make sure started\r
528 //\r
529 StatCode = EFI_SUCCESS;\r
530\r
531 if (This == NULL) {\r
532 DEBUG ((EFI_D_ERROR, "BC *This pointer == NULL"));\r
533 return EFI_INVALID_PARAMETER;\r
534 }\r
535\r
536 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);\r
537\r
538 if (Private == NULL) {\r
539 DEBUG ((EFI_D_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));\r
540 return EFI_INVALID_PARAMETER;\r
541 }\r
542\r
543 EfiAcquireLock (&Private->Lock);\r
544\r
545 if (This->Mode == NULL || !This->Mode->Started) {\r
546 DEBUG ((EFI_D_ERROR, "BC was not started."));\r
547 EfiReleaseLock (&Private->Lock);\r
548 return EFI_NOT_STARTED;\r
549 }\r
550\r
551 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;\r
552\r
553 //\r
554 // Issue BC command\r
555 //\r
556 StatCode = UdpRead (\r
557 Private,\r
558 OpFlags,\r
559 DestIp,\r
560 DestPort,\r
561 SrcIp,\r
562 SrcPort,\r
563 HeaderSize,\r
564 HeaderPtr,\r
565 BufferSize,\r
566 BufferPtr,\r
567 0\r
568 );\r
569\r
570 //\r
571 // Unlock the instance data and return\r
572 //\r
573 EfiReleaseLock (&Private->Lock);\r
574 return StatCode;\r
575}\r
576\r
577/* eof - pxe_bc_udp.c */\r