]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_bc_udp.c
sync comments, fix function header, rename variable name to follow coding style.
[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 CopyMem (&TmpDestIp, &Private->EfiBc.Mode->StationIp, sizeof (EFI_IP_ADDRESS));
321 }
322
323 for (;;) {
324 *BufferSizeptr = BufferSize;
325
326 StatCode = IpReceive (
327 Private,
328 OpFlags,
329 SrcIpPtr,
330 DestIpPtr,
331 PROT_UDP,
332 &Hdrs.Udpv4Header,
333 HeaderSize + sizeof Hdrs.Udpv4Header,
334 BufferPtr,
335 BufferSizeptr,
336 TimeoutEvent
337 );
338
339 if (StatCode == EFI_SUCCESS || StatCode == EFI_BUFFER_TOO_SMALL) {
340 UINT16 SPort;
341 UINT16 DPort;
342
343 SPort = NTOHS (Hdrs.Udpv4Header.SrcPort);
344 DPort = NTOHS (Hdrs.Udpv4Header.DestPort);
345
346 //
347 // do filtering
348 //
349 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && *SrcPortPtr != SPort) {
350 continue;
351 }
352
353 if (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && *DestPortPtr != DPort) {
354 continue;
355 }
356 //
357 // check checksum
358 //
359 if (StatCode == EFI_SUCCESS && Hdrs.Udpv4Header.Checksum) {
360 Hdrs.Udpv4PseudoHeader.SrcAddr.L = SrcIpPtr->Addr[0];
361 Hdrs.Udpv4PseudoHeader.DestAddr.L = DestIpPtr->Addr[0];
362 Hdrs.Udpv4PseudoHeader.Zero = 0;
363 Hdrs.Udpv4PseudoHeader.Protocol = PROT_UDP;
364 Hdrs.Udpv4PseudoHeader.TotalLength = Hdrs.Udpv4Header.TotalLength;
365
366 if (Hdrs.Udpv4Header.Checksum == 0xffff) {
367 Hdrs.Udpv4Header.Checksum = 0;
368 }
369
370 if (IpChecksum2 (
371 (UINT16 *) &Hdrs.Udpv4PseudoHeader,
372 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader) + sizeof (Hdrs.Udpv4Header),
373 (UINT16 *) BufferPtr,
374 *BufferSizeptr
375 )) {
376 DEBUG (
377 (DEBUG_INFO,
378 "\nUdpRead() Hdrs.Udpv4PseudoHeader == %Xh",
379 &Hdrs.Udpv4PseudoHeader)
380 );
381 DEBUG (
382 (DEBUG_INFO,
383 "\nUdpRead() Header size == %d",
384 HeaderSize + sizeof (Hdrs.Udpv4PseudoHeader))
385 );
386 DEBUG (
387 (DEBUG_INFO,
388 "\nUdpRead() BufferPtr == %Xh",
389 BufferPtr)
390 );
391 DEBUG (
392 (DEBUG_INFO,
393 "\nUdpRead() Buffer size == %d",
394 *BufferSizeptr)
395 );
396 DEBUG ((DEBUG_INFO, "\nUdpRead() Exit #2 Device Error"));
397 return EFI_DEVICE_ERROR;
398 }
399 }
400 //
401 // all passed
402 //
403 if (SrcPortPtr != NULL) {
404 *SrcPortPtr = SPort;
405 }
406
407 if (DestPortPtr != NULL) {
408 *DestPortPtr = DPort;
409 }
410
411 if (HeaderSize != 0) {
412 CopyMem (HeaderPtr, Hdrs.ProtHdr, HeaderSize);
413 }
414 }
415
416 if ((StatCode != EFI_SUCCESS) && (StatCode != EFI_TIMEOUT)) {
417 DEBUG (
418 (DEBUG_INFO,
419 "\nUdpRead() Exit #3 %Xh %r",
420 StatCode,
421 StatCode)
422 );
423 }
424
425 return StatCode;
426 }
427 }
428 //
429 // //////////////////////////////////////////////////////////
430 //
431 // BC Udp Read Routine
432 //
433
434 /**
435
436 @return EFI_SUCCESS :=
437 @return other :=
438
439 **/
440 EFI_STATUS
441 EFIAPI
442 BcUdpRead (
443 IN EFI_PXE_BASE_CODE_PROTOCOL *This,
444 IN UINT16 OpFlags,
445 IN OUT EFI_IP_ADDRESS *DestIp, OPTIONAL
446 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *DestPort, OPTIONAL
447 IN OUT EFI_IP_ADDRESS *SrcIp, OPTIONAL
448 IN OUT EFI_PXE_BASE_CODE_UDP_PORT *SrcPort, OPTIONAL
449 IN UINTN *HeaderSize, OPTIONAL
450 IN VOID *HeaderPtr, OPTIONAL
451 IN OUT UINTN *BufferSize,
452 IN VOID *BufferPtr
453 )
454 {
455 EFI_STATUS StatCode;
456 PXE_BASECODE_DEVICE *Private;
457
458 //
459 // Lock the instance data and make sure started
460 //
461 StatCode = EFI_SUCCESS;
462
463 if (This == NULL) {
464 DEBUG ((DEBUG_ERROR, "BC *This pointer == NULL"));
465 return EFI_INVALID_PARAMETER;
466 }
467
468 Private = CR (This, PXE_BASECODE_DEVICE, EfiBc, PXE_BASECODE_DEVICE_SIGNATURE);
469
470 if (Private == NULL) {
471 DEBUG ((DEBUG_ERROR, "PXE_BASECODE_DEVICE poiner == NULL"));
472 return EFI_INVALID_PARAMETER;
473 }
474
475 EfiAcquireLock (&Private->Lock);
476
477 if (This->Mode == NULL || !This->Mode->Started) {
478 DEBUG ((DEBUG_ERROR, "BC was not started."));
479 EfiReleaseLock (&Private->Lock);
480 return EFI_NOT_STARTED;
481 }
482
483 Private->Function = EFI_PXE_BASE_CODE_FUNCTION_UDP_READ;
484
485 //
486 // Issue BC command
487 //
488 StatCode = UdpRead (
489 Private,
490 OpFlags,
491 DestIp,
492 DestPort,
493 SrcIp,
494 SrcPort,
495 HeaderSize,
496 HeaderPtr,
497 BufferSize,
498 BufferPtr,
499 0
500 );
501
502 //
503 // Unlock the instance data and return
504 //
505 EfiReleaseLock (&Private->Lock);
506 return StatCode;
507 }
508
509 /* eof - pxe_bc_udp.c */