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