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