Add Socket Libraries.
[mirror_edk2.git] / StdLib / EfiSocketLib / Udp4.c
CommitLineData
d7ce7006 1/** @file\r
2 Implement the UDP4 driver support for the socket layer.\r
3\r
4 Copyright (c) 2011, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Socket.h"\r
16\r
17\r
18/**\r
19 Bind a name to a socket.\r
20\r
21 The ::UdpBind4 routine connects a name to a UDP4 stack on the local machine.\r
22\r
23 The configure call to the UDP4 driver occurs on the first poll, recv, recvfrom,\r
24 send or sentto call. Until then, all changes are made in the local UDP context\r
25 structure.\r
26 \r
27 @param [in] pSocket Address of the socket structure.\r
28\r
29 @param [in] pSockAddr Address of a sockaddr structure that contains the\r
30 connection point on the local machine. An IPv4 address\r
31 of INADDR_ANY specifies that the connection is made to\r
32 all of the network stacks on the platform. Specifying a\r
33 specific IPv4 address restricts the connection to the\r
34 network stack supporting that address. Specifying zero\r
35 for the port causes the network layer to assign a port\r
36 number from the dynamic range. Specifying a specific\r
37 port number causes the network layer to use that port.\r
38\r
39 @param [in] SockAddrLen Specifies the length in bytes of the sockaddr structure.\r
40\r
41 @retval EFI_SUCCESS - Socket successfully created\r
42\r
43 **/\r
44EFI_STATUS\r
45EslUdpBind4 (\r
46 IN DT_SOCKET * pSocket,\r
47 IN const struct sockaddr * pSockAddr,\r
48 IN socklen_t SockAddrLength\r
49 )\r
50{\r
51 EFI_HANDLE ChildHandle;\r
52 DT_LAYER * pLayer;\r
53 DT_PORT * pPort;\r
54 DT_SERVICE * pService;\r
55 CONST struct sockaddr_in * pIp4Address;\r
56 EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;\r
57 EFI_STATUS Status;\r
58 EFI_STATUS TempStatus;\r
59 \r
60 DBG_ENTER ( );\r
61 \r
62 //\r
63 // Verify the socket layer synchronization\r
64 //\r
65 VERIFY_TPL ( TPL_SOCKETS );\r
66 \r
67 //\r
68 // Assume success\r
69 //\r
70 pSocket->errno = 0;\r
71 Status = EFI_SUCCESS;\r
72 \r
73 //\r
74 // Validate the address length\r
75 //\r
76 pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
77 if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
78 - sizeof ( pIp4Address->sin_zero ))) {\r
79\r
80 //\r
81 // Walk the list of services\r
82 //\r
83 pLayer = &mEslLayer;\r
84 pService = pLayer->pUdp4List;\r
85 while ( NULL != pService ) {\r
86\r
87 //\r
88 // Create the UDP port\r
89 //\r
90 pUdp4Service = pService->pInterface;\r
91 ChildHandle = NULL;\r
92 Status = pUdp4Service->CreateChild ( pUdp4Service,\r
93 &ChildHandle );\r
94 if ( !EFI_ERROR ( Status )) {\r
95 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
96 "0x%08x: Udp4 port handle created\r\n",\r
97 ChildHandle ));\r
98 \r
99 //\r
100 // Open the port\r
101 //\r
102 Status = EslUdpPortAllocate4 ( pSocket,\r
103 pService,\r
104 ChildHandle,\r
105 (UINT8 *) &pIp4Address->sin_addr.s_addr,\r
106 SwapBytes16 ( pIp4Address->sin_port ),\r
107 DEBUG_BIND,\r
108 &pPort );\r
109 }\r
110 else {\r
111 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
112 "ERROR - Failed to open Udp4 port handle, Status: %r\r\n",\r
113 Status ));\r
114 ChildHandle = NULL;\r
115 }\r
116 \r
117 //\r
118 // Close the port if necessary\r
119 //\r
120 if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {\r
121 TempStatus = pUdp4Service->DestroyChild ( pUdp4Service,\r
122 ChildHandle );\r
123 if ( !EFI_ERROR ( TempStatus )) {\r
124 DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
125 "0x%08x: Udp4 port handle destroyed\r\n",\r
126 ChildHandle ));\r
127 }\r
128 else {\r
129 DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
130 "ERROR - Failed to destroy the Udp4 port handle 0x%08x, Status: %r\r\n",\r
131 ChildHandle,\r
132 TempStatus ));\r
133 ASSERT ( EFI_SUCCESS == TempStatus );\r
134 }\r
135 }\r
136 \r
137 //\r
138 // Set the next service\r
139 //\r
140 pService = pService->pNext;\r
141 }\r
142 \r
143 //\r
144 // Verify that at least one network connection was found\r
145 //\r
146 if ( NULL == pSocket->pPortList ) {\r
147 DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
148 "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",\r
149 ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,\r
150 ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,\r
151 ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,\r
152 pIp4Address->sin_addr.s_addr & 0xff,\r
153 pIp4Address->sin_addr.s_addr ));\r
154 pSocket->errno = EADDRNOTAVAIL;\r
155 Status = EFI_INVALID_PARAMETER;\r
156 }\r
157 }\r
158 else {\r
159 DEBUG (( DEBUG_BIND,\r
160 "ERROR - Invalid Udp4 address length: %d\r\n",\r
161 SockAddrLength ));\r
162 Status = EFI_INVALID_PARAMETER;\r
163 pSocket->errno = EINVAL;\r
164 }\r
165 \r
166 //\r
167 // Return the operation status\r
168 //\r
169 DBG_EXIT_STATUS ( Status );\r
170 return Status;\r
171}\r
172\r
173\r
174/**\r
175 Initialize the UDP4 service.\r
176\r
177 This routine initializes the UDP4 service after its service binding\r
178 protocol was located on a controller.\r
179\r
180 @param [in] pService DT_SERVICE structure address\r
181\r
182 @retval EFI_SUCCESS The service was properly initialized\r
183 @retval other A failure occurred during the service initialization\r
184\r
185**/\r
186EFI_STATUS\r
187EFIAPI\r
188EslUdpInitialize4 (\r
189 IN DT_SERVICE * pService\r
190 )\r
191{\r
192 DT_LAYER * pLayer;\r
193 EFI_STATUS Status;\r
194\r
195 DBG_ENTER ( );\r
196\r
197 //\r
198 // Identify the service\r
199 //\r
200 pService->NetworkType = NETWORK_TYPE_UDP4;\r
201\r
202 //\r
203 // Connect this service to the service list\r
204 //\r
205 pLayer = &mEslLayer;\r
206 pService->pNext = pLayer->pUdp4List;\r
207 pLayer->pUdp4List = pService;\r
208\r
209 //\r
210 // Assume the list is empty\r
211 //\r
212 Status = EFI_SUCCESS;\r
213\r
214 //\r
215 // Return the initialization status\r
216 //\r
217 DBG_EXIT_STATUS ( Status );\r
218 return Status;\r
219}\r
220\r
221\r
222/**\r
223 Allocate and initialize a DT_PORT structure.\r
224\r
225 @param [in] pSocket Address of the socket structure.\r
226 @param [in] pService Address of the DT_SERVICE structure.\r
227 @param [in] ChildHandle Udp4 child handle\r
228 @param [in] pIpAddress Buffer containing IP4 network address of the local host\r
229 @param [in] PortNumber Udp4 port number\r
230 @param [in] DebugFlags Flags for debug messages\r
231 @param [out] ppPort Buffer to receive new DT_PORT structure address\r
232\r
233 @retval EFI_SUCCESS - Socket successfully created\r
234\r
235 **/\r
236EFI_STATUS\r
237EslUdpPortAllocate4 (\r
238 IN DT_SOCKET * pSocket,\r
239 IN DT_SERVICE * pService,\r
240 IN EFI_HANDLE ChildHandle,\r
241 IN CONST UINT8 * pIpAddress,\r
242 IN UINT16 PortNumber,\r
243 IN UINTN DebugFlags,\r
244 OUT DT_PORT ** ppPort\r
245 )\r
246{\r
247 UINTN LengthInBytes;\r
248 EFI_UDP4_CONFIG_DATA * pConfig;\r
249 DT_LAYER * pLayer;\r
250 DT_PORT * pPort;\r
251 DT_UDP4_CONTEXT * pUdp4;\r
252 EFI_STATUS Status;\r
253\r
254 DBG_ENTER ( );\r
255\r
256 //\r
257 // Use for/break instead of goto\r
258 for ( ; ; ) {\r
259 //\r
260 // Allocate a port structure\r
261 //\r
262 pLayer = &mEslLayer;\r
263 LengthInBytes = sizeof ( *pPort );\r
264 Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
265 LengthInBytes,\r
266 (VOID **)&pPort );\r
267 if ( EFI_ERROR ( Status )) {\r
268 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
269 "ERROR - Failed to allocate the port structure, Status: %r\r\n",\r
270 Status ));\r
271 pSocket->errno = ENOMEM;\r
272 pPort = NULL;\r
273 break;\r
274 }\r
275 DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
276 "0x%08x: Allocate pPort, %d bytes\r\n",\r
277 pPort,\r
278 LengthInBytes ));\r
279\r
280 //\r
281 // Initialize the port\r
282 //\r
283 ZeroMem ( pPort, LengthInBytes );\r
284 pPort->Signature = PORT_SIGNATURE;\r
285 pPort->pService = pService;\r
286 pPort->pSocket = pSocket;\r
287 pPort->pfnCloseStart = EslUdpPortCloseStart4;\r
288 pPort->DebugFlags = DebugFlags;\r
289\r
290 //\r
291 // Allocate the receive event\r
292 //\r
293 pUdp4 = &pPort->Context.Udp4;\r
294 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
295 TPL_SOCKETS,\r
296 (EFI_EVENT_NOTIFY)EslUdpRxComplete4,\r
297 pPort,\r
298 &pUdp4->RxToken.Event);\r
299 if ( EFI_ERROR ( Status )) {\r
300 DEBUG (( DEBUG_ERROR | DebugFlags,\r
301 "ERROR - Failed to create the receive event, Status: %r\r\n",\r
302 Status ));\r
303 pSocket->errno = ENOMEM;\r
304 break;\r
305 }\r
306 DEBUG (( DEBUG_RX | DEBUG_POOL,\r
307 "0x%08x: Created receive event\r\n",\r
308 pUdp4->RxToken.Event ));\r
309\r
310 //\r
311 // Allocate the transmit event\r
312 //\r
313 Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
314 TPL_SOCKETS,\r
315 (EFI_EVENT_NOTIFY)EslUdpTxComplete4,\r
316 pPort,\r
317 &pUdp4->TxToken.Event);\r
318 if ( EFI_ERROR ( Status )) {\r
319 DEBUG (( DEBUG_ERROR | DebugFlags,\r
320 "ERROR - Failed to create the transmit event, Status: %r\r\n",\r
321 Status ));\r
322 pSocket->errno = ENOMEM;\r
323 break;\r
324 }\r
325 DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
326 "0x%08x: Created transmit event\r\n",\r
327 pUdp4->TxToken.Event ));\r
328\r
329 //\r
330 // Open the port protocol\r
331 //\r
332 Status = gBS->OpenProtocol (\r
333 ChildHandle,\r
334 &gEfiUdp4ProtocolGuid,\r
335 (VOID **) &pUdp4->pProtocol,\r
336 pLayer->ImageHandle,\r
337 NULL,\r
338 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
339 if ( EFI_ERROR ( Status )) {\r
340 DEBUG (( DEBUG_ERROR | DebugFlags,\r
341 "ERROR - Failed to open gEfiUdp4ProtocolGuid on controller 0x%08x\r\n",\r
342 pUdp4->Handle ));\r
343 pSocket->errno = EEXIST;\r
344 break;\r
345 }\r
346 DEBUG (( DebugFlags,\r
347 "0x%08x: gEfiUdp4ProtocolGuid opened on controller 0x%08x\r\n",\r
348 pUdp4->pProtocol,\r
349 ChildHandle ));\r
350\r
351 //\r
352 // Set the port address\r
353 //\r
354 pUdp4->Handle = ChildHandle;\r
355 pConfig = &pPort->Context.Udp4.ConfigData;\r
356 pConfig->StationPort = PortNumber;\r
357 if (( 0 == pIpAddress[0])\r
358 && ( 0 == pIpAddress[1])\r
359 && ( 0 == pIpAddress[2])\r
360 && ( 0 == pIpAddress[3])) {\r
361 pConfig->UseDefaultAddress = TRUE;\r
362 }\r
363 else {\r
364 pConfig->StationAddress.Addr[0] = pIpAddress[0];\r
365 pConfig->StationAddress.Addr[1] = pIpAddress[1];\r
366 pConfig->StationAddress.Addr[2] = pIpAddress[2];\r
367 pConfig->StationAddress.Addr[3] = pIpAddress[3];\r
368 pConfig->SubnetMask.Addr[0] = 0xff;\r
369 pConfig->SubnetMask.Addr[1] = 0xff;\r
370 pConfig->SubnetMask.Addr[2] = 0xff;\r
371 pConfig->SubnetMask.Addr[3] = 0xff;\r
372 }\r
373 pConfig->TimeToLive = 255;\r
374 pConfig->AcceptAnyPort = FALSE;\r
375 pConfig->AcceptBroadcast = FALSE;\r
376 pConfig->AcceptPromiscuous = FALSE;\r
377 pConfig->AllowDuplicatePort = TRUE;\r
378 pConfig->DoNotFragment = TRUE;\r
379\r
380 //\r
381 // Verify the socket layer synchronization\r
382 //\r
383 VERIFY_TPL ( TPL_SOCKETS );\r
384\r
385 //\r
386 // Add this port to the socket\r
387 //\r
388 pPort->pLinkSocket = pSocket->pPortList;\r
389 pSocket->pPortList = pPort;\r
390 DEBUG (( DebugFlags,\r
391 "0x%08x: Socket adding port: 0x%08x\r\n",\r
392 pSocket,\r
393 pPort ));\r
394\r
395 //\r
396 // Add this port to the service\r
397 //\r
398 pPort->pLinkService = pService->pPortList;\r
399 pService->pPortList = pPort;\r
400\r
401 //\r
402 // Return the port\r
403 //\r
404 *ppPort = pPort;\r
405 break;\r
406 }\r
407\r
408 //\r
409 // Clean up after the error if necessary\r
410 //\r
411 if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {\r
412 //\r
413 // Close the port\r
414 //\r
415 EslUdpPortClose4 ( pPort );\r
416 }\r
417 //\r
418 // Return the operation status\r
419 //\r
420 DBG_EXIT_STATUS ( Status );\r
421 return Status;\r
422}\r
423\r
424\r
425/**\r
426 Close a UDP4 port.\r
427\r
428 This routine releases the resources allocated by\r
429 ::UdpPortAllocate4().\r
430 \r
431 @param [in] pPort Address of the port structure.\r
432\r
433 @retval EFI_SUCCESS The port is closed\r
434 @retval other Port close error\r
435\r
436**/\r
437EFI_STATUS\r
438EslUdpPortClose4 (\r
439 IN DT_PORT * pPort\r
440 )\r
441{\r
442 UINTN DebugFlags;\r
443 DT_LAYER * pLayer;\r
444 DT_PACKET * pPacket;\r
445 DT_PORT * pPreviousPort;\r
446 DT_SERVICE * pService;\r
447 DT_SOCKET * pSocket;\r
448 EFI_SERVICE_BINDING_PROTOCOL * pUdp4Service;\r
449 DT_UDP4_CONTEXT * pUdp4;\r
450 EFI_STATUS Status;\r
451 \r
452 DBG_ENTER ( );\r
453\r
454 //\r
455 // Verify the socket layer synchronization\r
456 //\r
457 VERIFY_TPL ( TPL_SOCKETS );\r
458\r
459 //\r
460 // Assume success\r
461 //\r
462 Status = EFI_SUCCESS;\r
463 pSocket = pPort->pSocket;\r
464 pSocket->errno = 0;\r
465\r
466 //\r
467 // Locate the port in the socket list\r
468 //\r
469 pLayer = &mEslLayer;\r
470 DebugFlags = pPort->DebugFlags;\r
471 pPreviousPort = pSocket->pPortList;\r
472 if ( pPreviousPort == pPort ) {\r
473 //\r
474 // Remove this port from the head of the socket list\r
475 //\r
476 pSocket->pPortList = pPort->pLinkSocket;\r
477 }\r
478 else {\r
479 //\r
480 // Locate the port in the middle of the socket list\r
481 //\r
482 while (( NULL != pPreviousPort )\r
483 && ( pPreviousPort->pLinkSocket != pPort )) {\r
484 pPreviousPort = pPreviousPort->pLinkSocket;\r
485 }\r
486 if ( NULL != pPreviousPort ) {\r
487 //\r
488 // Remove the port from the middle of the socket list\r
489 //\r
490 pPreviousPort->pLinkSocket = pPort->pLinkSocket;\r
491 }\r
492 }\r
493\r
494 //\r
495 // Locate the port in the service list\r
496 //\r
497 pService = pPort->pService;\r
498 pPreviousPort = pService->pPortList;\r
499 if ( pPreviousPort == pPort ) {\r
500 //\r
501 // Remove this port from the head of the service list\r
502 //\r
503 pService->pPortList = pPort->pLinkService;\r
504 }\r
505 else {\r
506 //\r
507 // Locate the port in the middle of the service list\r
508 //\r
509 while (( NULL != pPreviousPort )\r
510 && ( pPreviousPort->pLinkService != pPort )) {\r
511 pPreviousPort = pPreviousPort->pLinkService;\r
512 }\r
513 if ( NULL != pPreviousPort ) {\r
514 //\r
515 // Remove the port from the middle of the service list\r
516 //\r
517 pPreviousPort->pLinkService = pPort->pLinkService;\r
518 }\r
519 }\r
520\r
521 //\r
522 // Empty the receive queue\r
523 //\r
524 ASSERT ( NULL == pSocket->pRxPacketListHead );\r
525 ASSERT ( NULL == pSocket->pRxPacketListTail );\r
526 ASSERT ( 0 == pSocket->RxBytes );\r
527\r
528 //\r
529 // Empty the receive free queue\r
530 //\r
531 while ( NULL != pSocket->pRxFree ) {\r
532 pPacket = pSocket->pRxFree;\r
533 pSocket->pRxFree = pPacket->pNext;\r
534 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
535 }\r
536\r
537 //\r
538 // Done with the receive event\r
539 //\r
540 pUdp4 = &pPort->Context.Udp4;\r
541 if ( NULL != pUdp4->RxToken.Event ) {\r
542 Status = gBS->CloseEvent ( pUdp4->RxToken.Event );\r
543 if ( !EFI_ERROR ( Status )) {\r
544 DEBUG (( DebugFlags | DEBUG_POOL,\r
545 "0x%08x: Closed receive event\r\n",\r
546 pUdp4->RxToken.Event ));\r
547 }\r
548 else {\r
549 DEBUG (( DEBUG_ERROR | DebugFlags,\r
550 "ERROR - Failed to close the receive event, Status: %r\r\n",\r
551 Status ));\r
552 ASSERT ( EFI_SUCCESS == Status );\r
553 }\r
554 }\r
555\r
556 //\r
557 // Done with the transmit event\r
558 //\r
559 if ( NULL != pUdp4->TxToken.Event ) {\r
560 Status = gBS->CloseEvent ( pUdp4->TxToken.Event );\r
561 if ( !EFI_ERROR ( Status )) {\r
562 DEBUG (( DebugFlags | DEBUG_POOL,\r
563 "0x%08x: Closed normal transmit event\r\n",\r
564 pUdp4->TxToken.Event ));\r
565 }\r
566 else {\r
567 DEBUG (( DEBUG_ERROR | DebugFlags,\r
568 "ERROR - Failed to close the normal transmit event, Status: %r\r\n",\r
569 Status ));\r
570 ASSERT ( EFI_SUCCESS == Status );\r
571 }\r
572 }\r
573\r
574 //\r
575 // Done with the UDP protocol\r
576 //\r
577 pUdp4Service = pService->pInterface;\r
578 if ( NULL != pUdp4->pProtocol ) {\r
579 Status = gBS->CloseProtocol ( pUdp4->Handle,\r
580 &gEfiUdp4ProtocolGuid,\r
581 pLayer->ImageHandle,\r
582 NULL );\r
583 if ( !EFI_ERROR ( Status )) {\r
584 DEBUG (( DebugFlags,\r
585 "0x%08x: gEfiUdp4ProtocolGuid closed on controller 0x%08x\r\n",\r
586 pUdp4->pProtocol,\r
587 pUdp4->Handle ));\r
588 }\r
589 else {\r
590 DEBUG (( DEBUG_ERROR | DebugFlags,\r
591 "ERROR - Failed to close gEfiUdp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",\r
592 pUdp4->Handle,\r
593 Status ));\r
594 ASSERT ( EFI_SUCCESS == Status );\r
595 }\r
596 }\r
597\r
598 //\r
599 // Done with the UDP port\r
600 //\r
601 if ( NULL != pUdp4->Handle ) {\r
602 Status = pUdp4Service->DestroyChild ( pUdp4Service,\r
603 pUdp4->Handle );\r
604 if ( !EFI_ERROR ( Status )) {\r
605 DEBUG (( DebugFlags | DEBUG_POOL,\r
606 "0x%08x: Udp4 port handle destroyed\r\n",\r
607 pUdp4->Handle ));\r
608 }\r
609 else {\r
610 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
611 "ERROR - Failed to destroy the Udp4 port handle, Status: %r\r\n",\r
612 Status ));\r
613 ASSERT ( EFI_SUCCESS == Status );\r
614 }\r
615 }\r
616\r
617 //\r
618 // Release the port structure\r
619 //\r
620 Status = gBS->FreePool ( pPort );\r
621 if ( !EFI_ERROR ( Status )) {\r
622 DEBUG (( DebugFlags | DEBUG_POOL,\r
623 "0x%08x: Free pPort, %d bytes\r\n",\r
624 pPort,\r
625 sizeof ( *pPort )));\r
626 }\r
627 else {\r
628 DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
629 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",\r
630 pPort,\r
631 Status ));\r
632 ASSERT ( EFI_SUCCESS == Status );\r
633 }\r
634\r
635 //\r
636 // Mark the socket as closed if necessary\r
637 //\r
638 if ( NULL == pSocket->pPortList ) {\r
639 pSocket->State = SOCKET_STATE_CLOSED;\r
640 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
641 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",\r
642 pSocket ));\r
643 }\r
644\r
645 //\r
646 // Return the operation status\r
647 //\r
648 DBG_EXIT_STATUS ( Status );\r
649 return Status;\r
650}\r
651\r
652\r
653/**\r
654 Start the close operation on a UDP4 port, state 1.\r
655\r
656 Closing a port goes through the following states:\r
657 1. Port close starting - Mark the port as closing and wait for transmission to complete\r
658 2. Port TX close done - Transmissions complete, close the port and abort the receives\r
659 3. Port RX close done - Receive operations complete, close the port\r
660 4. Port closed - Release the port resources\r
661 \r
662 @param [in] pPort Address of the port structure.\r
663 @param [in] bCloseNow Set TRUE to abort active transfers\r
664 @param [in] DebugFlags Flags for debug messages\r
665\r
666 @retval EFI_SUCCESS The port is closed, not normally returned\r
667 @retval EFI_NOT_READY The port has started the closing process\r
668 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
669 most likely the routine was called already.\r
670\r
671**/\r
672EFI_STATUS\r
673EslUdpPortCloseStart4 (\r
674 IN DT_PORT * pPort,\r
675 IN BOOLEAN bCloseNow,\r
676 IN UINTN DebugFlags\r
677 )\r
678{\r
679 DT_SOCKET * pSocket;\r
680 EFI_STATUS Status;\r
681\r
682 DBG_ENTER ( );\r
683\r
684 //\r
685 // Verify the socket layer synchronization\r
686 //\r
687 VERIFY_TPL ( TPL_SOCKETS );\r
688\r
689 //\r
690 // Mark the port as closing\r
691 //\r
692 Status = EFI_ALREADY_STARTED;\r
693 pSocket = pPort->pSocket;\r
694 pSocket->errno = EALREADY;\r
695 if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
696\r
697 //\r
698 // Update the port state\r
699 //\r
700 pPort->State = PORT_STATE_CLOSE_STARTED;\r
701 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
702 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
703 pPort ));\r
704 pPort->bCloseNow = bCloseNow;\r
705 pPort->DebugFlags = DebugFlags;\r
706\r
707 //\r
708 // Determine if transmits are complete\r
709 //\r
710 Status = EslUdpPortCloseTxDone4 ( pPort );\r
711 }\r
712\r
713 //\r
714 // Return the operation status\r
715 //\r
716 DBG_EXIT_STATUS ( Status );\r
717 return Status;\r
718}\r
719\r
720\r
721/**\r
722 Port close state 3\r
723\r
724 Continue the close operation after the receive is complete.\r
725\r
726 @param [in] pPort Address of the port structure.\r
727\r
728 @retval EFI_SUCCESS The port is closed\r
729 @retval EFI_NOT_READY The port is still closing\r
730 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
731 most likely the routine was called already.\r
732\r
733**/\r
734EFI_STATUS\r
735EslUdpPortCloseRxDone4 (\r
736 IN DT_PORT * pPort\r
737 )\r
738{\r
739 PORT_STATE PortState;\r
740 DT_SOCKET * pSocket;\r
741 DT_UDP4_CONTEXT * pUdp4;\r
742 EFI_STATUS Status;\r
743\r
744 DBG_ENTER ( );\r
745\r
746 //\r
747 // Verify the socket layer synchronization\r
748 //\r
749 VERIFY_TPL ( TPL_SOCKETS );\r
750\r
751 //\r
752 // Verify that the port is closing\r
753 //\r
754 Status = EFI_ALREADY_STARTED;\r
755 pSocket = pPort->pSocket;\r
756 pSocket->errno = EALREADY;\r
757 PortState = pPort->State;\r
758 if (( PORT_STATE_CLOSE_TX_DONE == PortState )\r
759 || ( PORT_STATE_CLOSE_DONE == PortState )) {\r
760 //\r
761 // Determine if the receive operation is pending\r
762 //\r
763 Status = EFI_NOT_READY;\r
764 pSocket->errno = EAGAIN;\r
765 pUdp4 = &pPort->Context.Udp4;\r
766 if ( NULL == pUdp4->pReceivePending ) {\r
767 //\r
768 // The receive operation is complete\r
769 // Update the port state\r
770 //\r
771 pPort->State = PORT_STATE_CLOSE_RX_DONE;\r
772 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
773 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",\r
774 pPort ));\r
775\r
776 //\r
777 // The close operation has completed\r
778 // Release the port resources\r
779 //\r
780 Status = EslUdpPortClose4 ( pPort );\r
781 }\r
782 else {\r
783 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
784 "0x%08x: Port Close: Receive still pending!\r\n",\r
785 pPort ));\r
786 }\r
787 }\r
788\r
789 //\r
790 // Return the operation status\r
791 //\r
792 DBG_EXIT_STATUS ( Status );\r
793 return Status;\r
794}\r
795\r
796\r
797/**\r
798 Port close state 2\r
799\r
800 Continue the close operation after the transmission is complete.\r
801\r
802 @param [in] pPort Address of the port structure.\r
803\r
804 @retval EFI_SUCCESS The port is closed, not normally returned\r
805 @retval EFI_NOT_READY The port is still closing\r
806 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
807 most likely the routine was called already.\r
808\r
809**/\r
810EFI_STATUS\r
811EslUdpPortCloseTxDone4 (\r
812 IN DT_PORT * pPort\r
813 )\r
814{\r
815 DT_PACKET * pPacket;\r
816 DT_SOCKET * pSocket;\r
817 DT_UDP4_CONTEXT * pUdp4;\r
818 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
819 EFI_STATUS Status;\r
820\r
821 DBG_ENTER ( );\r
822\r
823 //\r
824 // Verify the socket layer synchronization\r
825 //\r
826 VERIFY_TPL ( TPL_SOCKETS );\r
827\r
828 //\r
829 // All transmissions are complete or must be stopped\r
830 // Mark the port as TX complete\r
831 //\r
832 Status = EFI_ALREADY_STARTED;\r
833 if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {\r
834 //\r
835 // Verify that the transmissions are complete\r
836 //\r
837 pSocket = pPort->pSocket;\r
838 if ( pPort->bCloseNow\r
839 || ( EFI_SUCCESS != pSocket->TxError )\r
840 || ( 0 == pSocket->TxBytes )) {\r
841 //\r
842 // Start the close operation on the port\r
843 //\r
844 pUdp4 = &pPort->Context.Udp4;\r
845 pUdp4Protocol = pUdp4->pProtocol;\r
846 if ( !pUdp4->bConfigured ) {\r
847 //\r
848 // Skip the close operation since the port is not\r
849 // configured\r
850 //\r
851 // Update the port state\r
852 //\r
853 pPort->State = PORT_STATE_CLOSE_DONE;\r
854 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
855 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",\r
856 pPort ));\r
857 Status = EFI_SUCCESS;\r
858 }\r
859 else {\r
860 //\r
861 // Update the port state\r
862 //\r
863 pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
864 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
865 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
866 pPort ));\r
867\r
868 //\r
869 // Empty the receive queue\r
870 //\r
871 while ( NULL != pSocket->pRxPacketListHead ) {\r
872 pPacket = pSocket->pRxPacketListHead;\r
873 pSocket->pRxPacketListHead = pPacket->pNext;\r
874 pSocket->RxBytes -= pPacket->Op.Udp4Rx.pRxData->DataLength;\r
875\r
876 //\r
877 // Return the buffer to the UDP4 driver\r
878 //\r
879 gBS->SignalEvent ( pPacket->Op.Udp4Rx.pRxData->RecycleSignal );\r
880\r
881 //\r
882 // Done with this packet\r
883 //\r
884 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
885 }\r
886 pSocket->pRxPacketListTail = NULL;\r
887 ASSERT ( 0 == pSocket->RxBytes );\r
888\r
889 //\r
890 // Reset the port, cancel the outstanding receive\r
891 //\r
892 Status = pUdp4Protocol->Configure ( pUdp4Protocol,\r
893 NULL );\r
894 if ( !EFI_ERROR ( Status )) {\r
895 DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
896 "0x%08x: Port reset\r\n",\r
897 pPort ));\r
898\r
899 //\r
900 // Free the receive packet\r
901 //\r
902 Status = gBS->CheckEvent ( pUdp4->RxToken.Event );\r
903 if ( EFI_SUCCESS != Status ) {\r
904 EslSocketPacketFree ( pUdp4->pReceivePending, DEBUG_CLOSE );\r
905 pUdp4->pReceivePending = NULL;\r
906 Status = EFI_SUCCESS;\r
907 }\r
908 }\r
909 else {\r
910 DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
911 "ERROR - Port 0x%08x reset failed, Status: %r\r\n",\r
912 pPort,\r
913 Status ));\r
914 ASSERT ( EFI_SUCCESS == Status );\r
915 }\r
916 }\r
917\r
918 //\r
919 // Determine if the receive operation is pending\r
920 //\r
921 if ( !EFI_ERROR ( Status )) {\r
922 Status = EslUdpPortCloseRxDone4 ( pPort );\r
923 }\r
924 }\r
925 else {\r
926 //\r
927 // Transmissions are still active, exit\r
928 //\r
929 DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
930 "0x%08x: Port Close: Transmits are still pending!\r\n",\r
931 pPort ));\r
932 Status = EFI_NOT_READY;\r
933 pSocket->errno = EAGAIN;\r
934 }\r
935 }\r
936\r
937 //\r
938 // Return the operation status\r
939 //\r
940 DBG_EXIT_STATUS ( Status );\r
941 return Status;\r
942}\r
943\r
944\r
945/**\r
946 Connect to a remote system via the network.\r
947\r
948 The ::UdpConnectStart4= routine sets the remote address for the connection.\r
949\r
950 @param [in] pSocket Address of the socket structure.\r
951\r
952 @param [in] pSockAddr Network address of the remote system.\r
953 \r
954 @param [in] SockAddrLength Length in bytes of the network address.\r
955 \r
956 @retval EFI_SUCCESS The connection was successfully established.\r
957 @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
958 @retval Others The connection attempt failed.\r
959\r
960 **/\r
961EFI_STATUS\r
962EslUdpConnect4 (\r
963 IN DT_SOCKET * pSocket,\r
964 IN const struct sockaddr * pSockAddr,\r
965 IN socklen_t SockAddrLength\r
966 )\r
967{\r
968 struct sockaddr_in LocalAddress;\r
969 DT_PORT * pPort;\r
970 struct sockaddr_in * pRemoteAddress;\r
971 DT_UDP4_CONTEXT * pUdp4;\r
972 EFI_STATUS Status;\r
973\r
974 DBG_ENTER ( );\r
975\r
976 //\r
977 // Assume failure\r
978 //\r
979 Status = EFI_NETWORK_UNREACHABLE;\r
980 pSocket->errno = ENETUNREACH;\r
981\r
982 //\r
983 // Get the address\r
984 //\r
985 pRemoteAddress = (struct sockaddr_in *)pSockAddr;\r
986\r
987 //\r
988 // Validate the address length\r
989 //\r
990 if ( SockAddrLength >= ( sizeof ( *pRemoteAddress )\r
991 - sizeof ( pRemoteAddress->sin_zero ))) {\r
992 //\r
993 // Determine if BIND was already called\r
994 //\r
995 if ( NULL == pSocket->pPortList ) {\r
996 //\r
997 // Allow any local port\r
998 //\r
999 ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
1000 LocalAddress.sin_len = sizeof ( LocalAddress );\r
1001 LocalAddress.sin_family = AF_INET;\r
1002 Status = EslSocketBind ( &pSocket->SocketProtocol,\r
1003 (struct sockaddr *)&LocalAddress,\r
1004 LocalAddress.sin_len,\r
1005 &pSocket->errno );\r
1006 }\r
1007\r
1008 //\r
1009 // Walk the list of ports\r
1010 //\r
1011 pPort = pSocket->pPortList;\r
1012 while ( NULL != pPort ) {\r
1013 //\r
1014 // Set the remote address\r
1015 //\r
1016 pUdp4 = &pPort->Context.Udp4;\r
1017 pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );\r
1018 pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
1019 pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
1020 pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
1021 pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );\r
1022\r
1023 //\r
1024 // At least one path exists\r
1025 //\r
1026 Status = EFI_SUCCESS;\r
1027 pSocket->errno = 0;\r
1028\r
1029 //\r
1030 // Set the next port\r
1031 //\r
1032 pPort = pPort->pLinkSocket;\r
1033 }\r
1034 }\r
1035 else {\r
1036 DEBUG (( DEBUG_CONNECT,\r
1037 "ERROR - Invalid UDP4 address length: %d\r\n",\r
1038 SockAddrLength ));\r
1039 Status = EFI_INVALID_PARAMETER;\r
1040 pSocket->errno = EINVAL;\r
1041 }\r
1042\r
1043 //\r
1044 // Return the connect status\r
1045 //\r
1046 DBG_EXIT_STATUS ( Status );\r
1047 return Status;\r
1048}\r
1049\r
1050\r
1051/**\r
1052 Get the local socket address\r
1053\r
1054 @param [in] pSocket Address of the socket structure.\r
1055\r
1056 @param [out] pAddress Network address to receive the local system address\r
1057\r
1058 @param [in,out] pAddressLength Length of the local network address structure\r
1059\r
1060 @retval EFI_SUCCESS - Address available\r
1061 @retval Other - Failed to get the address\r
1062\r
1063**/\r
1064EFI_STATUS\r
1065EslUdpGetLocalAddress4 (\r
1066 IN DT_SOCKET * pSocket,\r
1067 OUT struct sockaddr * pAddress,\r
1068 IN OUT socklen_t * pAddressLength\r
1069 )\r
1070{\r
1071 socklen_t LengthInBytes;\r
1072 DT_PORT * pPort;\r
1073 struct sockaddr_in * pLocalAddress;\r
1074 DT_UDP4_CONTEXT * pUdp4;\r
1075 EFI_STATUS Status;\r
1076\r
1077 DBG_ENTER ( );\r
1078\r
1079 //\r
1080 // Verify the socket layer synchronization\r
1081 //\r
1082 VERIFY_TPL ( TPL_SOCKETS );\r
1083\r
1084 //\r
1085 // Verify that there is just a single connection\r
1086 //\r
1087 pPort = pSocket->pPortList;\r
1088 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
1089 //\r
1090 // Verify the address length\r
1091 //\r
1092 LengthInBytes = sizeof ( struct sockaddr_in );\r
1093 if ( LengthInBytes <= * pAddressLength ) {\r
1094 //\r
1095 // Return the local address\r
1096 //\r
1097 pUdp4 = &pPort->Context.Udp4;\r
1098 pLocalAddress = (struct sockaddr_in *)pAddress;\r
1099 ZeroMem ( pLocalAddress, LengthInBytes );\r
1100 pLocalAddress->sin_family = AF_INET;\r
1101 pLocalAddress->sin_len = (uint8_t)LengthInBytes;\r
1102 pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );\r
1103 CopyMem ( &pLocalAddress->sin_addr,\r
1104 &pUdp4->ConfigData.StationAddress.Addr[0],\r
1105 sizeof ( pLocalAddress->sin_addr ));\r
1106 pSocket->errno = 0;\r
1107 Status = EFI_SUCCESS;\r
1108 }\r
1109 else {\r
1110 pSocket->errno = EINVAL;\r
1111 Status = EFI_INVALID_PARAMETER;\r
1112 }\r
1113 }\r
1114 else {\r
1115 pSocket->errno = ENOTCONN;\r
1116 Status = EFI_NOT_STARTED;\r
1117 }\r
1118 \r
1119 //\r
1120 // Return the operation status\r
1121 //\r
1122 DBG_EXIT_STATUS ( Status );\r
1123 return Status;\r
1124}\r
1125\r
1126\r
1127/**\r
1128 Get the remote socket address\r
1129\r
1130 @param [in] pSocket Address of the socket structure.\r
1131\r
1132 @param [out] pAddress Network address to receive the remote system address\r
1133\r
1134 @param [in,out] pAddressLength Length of the remote network address structure\r
1135\r
1136 @retval EFI_SUCCESS - Address available\r
1137 @retval Other - Failed to get the address\r
1138\r
1139**/\r
1140EFI_STATUS\r
1141EslUdpGetRemoteAddress4 (\r
1142 IN DT_SOCKET * pSocket,\r
1143 OUT struct sockaddr * pAddress,\r
1144 IN OUT socklen_t * pAddressLength\r
1145 )\r
1146{\r
1147 socklen_t LengthInBytes;\r
1148 DT_PORT * pPort;\r
1149 struct sockaddr_in * pRemoteAddress;\r
1150 DT_UDP4_CONTEXT * pUdp4;\r
1151 EFI_STATUS Status;\r
1152\r
1153 DBG_ENTER ( );\r
1154\r
1155 //\r
1156 // Verify the socket layer synchronization\r
1157 //\r
1158 VERIFY_TPL ( TPL_SOCKETS );\r
1159\r
1160 //\r
1161 // Verify that there is just a single connection\r
1162 //\r
1163 pPort = pSocket->pPortList;\r
1164 if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
1165 //\r
1166 // Verify the address length\r
1167 //\r
1168 LengthInBytes = sizeof ( struct sockaddr_in );\r
1169 if ( LengthInBytes <= * pAddressLength ) {\r
1170 //\r
1171 // Return the local address\r
1172 //\r
1173 pUdp4 = &pPort->Context.Udp4;\r
1174 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1175 ZeroMem ( pRemoteAddress, LengthInBytes );\r
1176 pRemoteAddress->sin_family = AF_INET;\r
1177 pRemoteAddress->sin_len = (uint8_t)LengthInBytes;\r
1178 pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );\r
1179 CopyMem ( &pRemoteAddress->sin_addr,\r
1180 &pUdp4->ConfigData.RemoteAddress.Addr[0],\r
1181 sizeof ( pRemoteAddress->sin_addr ));\r
1182 pSocket->errno = 0;\r
1183 Status = EFI_SUCCESS;\r
1184 }\r
1185 else {\r
1186 pSocket->errno = EINVAL;\r
1187 Status = EFI_INVALID_PARAMETER;\r
1188 }\r
1189 }\r
1190 else {\r
1191 pSocket->errno = ENOTCONN;\r
1192 Status = EFI_NOT_STARTED;\r
1193 }\r
1194 \r
1195 //\r
1196 // Return the operation status\r
1197 //\r
1198 DBG_EXIT_STATUS ( Status );\r
1199 return Status;\r
1200}\r
1201\r
1202\r
1203/**\r
1204 Receive data from a network connection.\r
1205\r
1206 To minimize the number of buffer copies, the ::UdpRxComplete4\r
1207 routine queues the UDP4 driver's buffer to a list of datagrams\r
1208 waiting to be received. The socket driver holds on to the\r
1209 buffers from the UDP4 driver until the application layer requests\r
1210 the data or the socket is closed.\r
1211\r
1212 The application calls this routine in the socket layer to\r
1213 receive datagrams from one or more remote systems. This routine\r
1214 removes the next available datagram from the list of datagrams\r
1215 and copies the data from the UDP4 driver's buffer into the\r
1216 application's buffer. The UDP4 driver's buffer is then returned.\r
1217\r
1218 @param [in] pSocket Address of a DT_SOCKET structure\r
1219\r
1220 @param [in] Flags Message control flags\r
1221\r
1222 @param [in] BufferLength Length of the the buffer\r
1223\r
1224 @param [in] pBuffer Address of a buffer to receive the data.\r
1225\r
1226 @param [in] pDataLength Number of received data bytes in the buffer.\r
1227\r
1228 @param [out] pAddress Network address to receive the remote system address\r
1229\r
1230 @param [in,out] pAddressLength Length of the remote network address structure\r
1231\r
1232 @retval EFI_SUCCESS - Socket data successfully received\r
1233\r
1234**/\r
1235EFI_STATUS\r
1236EslUdpReceive4 (\r
1237 IN DT_SOCKET * pSocket,\r
1238 IN INT32 Flags,\r
1239 IN size_t BufferLength,\r
1240 IN UINT8 * pBuffer,\r
1241 OUT size_t * pDataLength,\r
1242 OUT struct sockaddr * pAddress,\r
1243 IN OUT socklen_t * pAddressLength\r
1244 )\r
1245{\r
1246 socklen_t AddressLength;\r
1247 size_t BytesToCopy;\r
1248 size_t DataBytes;\r
1249 UINT32 Fragment;\r
1250 in_addr_t IpAddress;\r
1251 size_t LengthInBytes;\r
1252 UINT8 * pData;\r
1253 DT_PACKET * pPacket;\r
1254 DT_PORT * pPort;\r
1255 struct sockaddr_in * pRemoteAddress;\r
1256 EFI_UDP4_RECEIVE_DATA * pRxData;\r
1257 DT_UDP4_CONTEXT * pUdp4;\r
1258 struct sockaddr_in RemoteAddress;\r
1259 EFI_STATUS Status;\r
1260\r
1261 DBG_ENTER ( );\r
1262\r
1263 //\r
1264 // Assume failure\r
1265 //\r
1266 Status = EFI_UNSUPPORTED;\r
1267 pSocket->errno = ENOTCONN;\r
1268\r
1269 //\r
1270 // Verify that the socket is connected\r
1271 //\r
1272 if (( SOCKET_STATE_CONNECTED == pSocket->State )\r
1273 || ( PORT_STATE_RX_ERROR == pSocket->State )) {\r
1274 //\r
1275 // Locate the port\r
1276 //\r
1277 pPort = pSocket->pPortList;\r
1278 if ( NULL != pPort ) {\r
1279 //\r
1280 // Determine if there is any data on the queue\r
1281 //\r
1282 pUdp4 = &pPort->Context.Udp4;\r
1283 pPacket = pSocket->pRxPacketListHead;\r
1284 if ( NULL != pPacket ) {\r
1285 //\r
1286 // Validate the return address parameters\r
1287 //\r
1288 pRxData = pPacket->Op.Udp4Rx.pRxData;\r
1289 if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
1290 //\r
1291 // Return the remote system address if requested\r
1292 //\r
1293 if ( NULL != pAddress ) {\r
1294 //\r
1295 // Build the remote address\r
1296 //\r
1297 DEBUG (( DEBUG_RX,\r
1298 "Getting packet source address: %d.%d.%d.%d:%d\r\n",\r
1299 pRxData->UdpSession.SourceAddress.Addr[0],\r
1300 pRxData->UdpSession.SourceAddress.Addr[1],\r
1301 pRxData->UdpSession.SourceAddress.Addr[2],\r
1302 pRxData->UdpSession.SourceAddress.Addr[3],\r
1303 pRxData->UdpSession.SourcePort ));\r
1304 ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));\r
1305 RemoteAddress.sin_len = sizeof ( RemoteAddress );\r
1306 RemoteAddress.sin_family = AF_INET;\r
1307 IpAddress = pRxData->UdpSession.SourceAddress.Addr[3];\r
1308 IpAddress <<= 8;\r
1309 IpAddress |= pRxData->UdpSession.SourceAddress.Addr[2];\r
1310 IpAddress <<= 8;\r
1311 IpAddress |= pRxData->UdpSession.SourceAddress.Addr[1];\r
1312 IpAddress <<= 8;\r
1313 IpAddress |= pRxData->UdpSession.SourceAddress.Addr[0];\r
1314 RemoteAddress.sin_addr.s_addr = IpAddress;\r
1315 RemoteAddress.sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );\r
1316\r
1317 //\r
1318 // Copy the address\r
1319 //\r
1320 pRemoteAddress = (struct sockaddr_in *)pAddress;\r
1321 AddressLength = sizeof ( *pRemoteAddress );\r
1322 if ( AddressLength > *pAddressLength ) {\r
1323 AddressLength = *pAddressLength;\r
1324 }\r
1325 CopyMem ( pRemoteAddress,\r
1326 &RemoteAddress,\r
1327 AddressLength );\r
1328\r
1329 //\r
1330 // Update the address length\r
1331 //\r
1332 *pAddressLength = AddressLength;\r
1333 }\r
1334\r
1335 //\r
1336 // Reduce the buffer length if necessary\r
1337 //\r
1338 DataBytes = pRxData->DataLength;\r
1339 if ( DataBytes < BufferLength ) {\r
1340 BufferLength = DataBytes;\r
1341 }\r
1342\r
1343 //\r
1344 // Copy the received data\r
1345 //\r
1346 LengthInBytes = 0;\r
1347 Fragment = 0;\r
1348 do {\r
1349 //\r
1350 // Determine the amount of received data\r
1351 //\r
1352 pData = pRxData->FragmentTable[Fragment].FragmentBuffer;\r
1353 BytesToCopy = pRxData->FragmentTable[Fragment].FragmentLength;\r
1354 if (( BufferLength - LengthInBytes ) < BytesToCopy ) {\r
1355 BytesToCopy = BufferLength - LengthInBytes;\r
1356 }\r
1357 LengthInBytes += BytesToCopy;\r
1358\r
1359 //\r
1360 // Move the data into the buffer\r
1361 //\r
1362 DEBUG (( DEBUG_RX,\r
1363 "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
1364 pPort,\r
1365 pPacket,\r
1366 pBuffer,\r
1367 BytesToCopy ));\r
1368 CopyMem ( pBuffer, pData, BytesToCopy );\r
1369 } while ( BufferLength > LengthInBytes );\r
1370\r
1371 //\r
1372 // Determine if the data is being read\r
1373 //\r
1374 if ( 0 == ( Flags & MSG_PEEK )) {\r
1375 //\r
1376 // Display for the bytes consumed\r
1377 //\r
1378 DEBUG (( DEBUG_RX,\r
1379 "0x%08x: Port account for 0x%08x bytes\r\n",\r
1380 pPort,\r
1381 BufferLength ));\r
1382\r
1383 //\r
1384 // All done with this packet\r
1385 // Account for any discarded data\r
1386 //\r
1387 pSocket->RxBytes -= DataBytes;\r
1388 if ( 0 != ( DataBytes - BufferLength )) {\r
1389 DEBUG (( DEBUG_RX,\r
1390 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
1391 pPort,\r
1392 DataBytes - BufferLength ));\r
1393 }\r
1394\r
1395 //\r
1396 // Remove this packet from the queue\r
1397 //\r
1398 pSocket->pRxPacketListHead = pPacket->pNext;\r
1399 if ( NULL == pSocket->pRxPacketListHead ) {\r
1400 pSocket->pRxPacketListTail = NULL;\r
1401 }\r
1402\r
1403 //\r
1404 // Return this packet to the UDP4 driver\r
1405 //\r
1406 gBS->SignalEvent ( pRxData->RecycleSignal );\r
1407\r
1408 //\r
1409 // Move the packet to the free queue\r
1410 //\r
1411 pPacket->pNext = pSocket->pRxFree;\r
1412 pSocket->pRxFree = pPacket;\r
1413 DEBUG (( DEBUG_RX,\r
1414 "0x%08x: Port freeing packet 0x%08x\r\n",\r
1415 pPort,\r
1416 pPacket ));\r
1417\r
1418 //\r
1419 // Restart this receive operation if necessary\r
1420 //\r
1421 if (( NULL == pUdp4->pReceivePending )\r
1422 && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
1423 EslUdpRxStart4 ( pPort );\r
1424 }\r
1425 }\r
1426\r
1427 //\r
1428 // Return the data length\r
1429 //\r
1430 *pDataLength = LengthInBytes;\r
1431\r
1432 //\r
1433 // Successful operation\r
1434 //\r
1435 Status = EFI_SUCCESS;\r
1436 pSocket->errno = 0;\r
1437 }\r
1438 else {\r
1439 //\r
1440 // Bad return address pointer and length\r
1441 //\r
1442 Status = EFI_INVALID_PARAMETER;\r
1443 pSocket->errno = EINVAL;\r
1444 }\r
1445 }\r
1446 else {\r
1447 //\r
1448 // The queue is empty\r
1449 // Determine if it is time to return the receive error\r
1450 //\r
1451 if ( EFI_ERROR ( pSocket->RxError )) {\r
1452 Status = pSocket->RxError;\r
1453 switch ( Status ) {\r
1454 default:\r
1455 pSocket->errno = EIO;\r
1456 break;\r
1457\r
1458 case EFI_HOST_UNREACHABLE:\r
1459 pSocket->errno = EHOSTUNREACH;\r
1460 break;\r
1461\r
1462 case EFI_NETWORK_UNREACHABLE:\r
1463 pSocket->errno = ENETUNREACH;\r
1464 break;\r
1465\r
1466 case EFI_PORT_UNREACHABLE:\r
1467 pSocket->errno = EPROTONOSUPPORT;\r
1468 break;\r
1469\r
1470 case EFI_PROTOCOL_UNREACHABLE:\r
1471 pSocket->errno = ENOPROTOOPT;\r
1472 break;\r
1473 }\r
1474 pSocket->RxError = EFI_SUCCESS;\r
1475 }\r
1476 else {\r
1477 Status = EFI_NOT_READY;\r
1478 pSocket->errno = EAGAIN;\r
1479 }\r
1480 }\r
1481 }\r
1482 }\r
1483\r
1484 //\r
1485 // Return the operation status\r
1486 //\r
1487 DBG_EXIT_STATUS ( Status );\r
1488 return Status;\r
1489}\r
1490\r
1491\r
1492/**\r
1493 Cancel the receive operations\r
1494\r
1495 @param [in] pSocket Address of a DT_SOCKET structure\r
1496 \r
1497 @retval EFI_SUCCESS - The cancel was successful\r
1498\r
1499 **/\r
1500EFI_STATUS\r
1501EslUdpRxCancel4 (\r
1502 IN DT_SOCKET * pSocket\r
1503 )\r
1504{\r
1505 DT_PACKET * pPacket;\r
1506 DT_PORT * pPort;\r
1507 DT_UDP4_CONTEXT * pUdp4;\r
1508 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
1509 EFI_STATUS Status;\r
1510\r
1511 DBG_ENTER ( );\r
1512\r
1513 //\r
1514 // Assume failure\r
1515 //\r
1516 Status = EFI_NOT_FOUND;\r
1517\r
1518 //\r
1519 // Locate the port\r
1520 //\r
1521 pPort = pSocket->pPortList;\r
1522 if ( NULL != pPort ) {\r
1523 //\r
1524 // Determine if a receive is pending\r
1525 //\r
1526 pUdp4 = &pPort->Context.Udp4;\r
1527 pPacket = pUdp4->pReceivePending;\r
1528 if ( NULL != pPacket ) {\r
1529 //\r
1530 // Attempt to cancel the receive operation\r
1531 //\r
1532 pUdp4Protocol = pUdp4->pProtocol;\r
1533 Status = pUdp4Protocol->Cancel ( pUdp4Protocol,\r
1534 &pUdp4->RxToken );\r
1535 if ( EFI_NOT_FOUND == Status ) {\r
1536 //\r
1537 // The receive is complete\r
1538 //\r
1539 Status = EFI_SUCCESS;\r
1540 }\r
1541 }\r
1542 }\r
1543\r
1544 //\r
1545 // Return the operation status\r
1546 //\r
1547 DBG_EXIT_STATUS ( Status );\r
1548 return Status;\r
1549}\r
1550\r
1551\r
1552/**\r
1553 Process the receive completion\r
1554\r
1555 Keep the UDP4 driver's buffer and append it to the list of\r
1556 datagrams for the application to receive. The UDP4 driver's\r
1557 buffer will be returned by either ::UdpReceive4 or\r
1558 ::UdpPortCloseTxDone4.\r
1559\r
1560 @param Event The receive completion event\r
1561\r
1562 @param pPort The DT_PORT structure address\r
1563\r
1564**/\r
1565VOID\r
1566EslUdpRxComplete4 (\r
1567 IN EFI_EVENT Event,\r
1568 IN DT_PORT * pPort\r
1569 )\r
1570{\r
1571 size_t LengthInBytes;\r
1572 DT_PACKET * pPacket;\r
1573 DT_PACKET * pPrevious;\r
1574 EFI_UDP4_RECEIVE_DATA * pRxData;\r
1575 DT_SOCKET * pSocket;\r
1576 DT_UDP4_CONTEXT * pUdp4;\r
1577 EFI_STATUS Status;\r
1578 \r
1579 DBG_ENTER ( );\r
1580 \r
1581 //\r
1582 // Mark this receive complete\r
1583 //\r
1584 pUdp4 = &pPort->Context.Udp4;\r
1585 pPacket = pUdp4->pReceivePending;\r
1586 pUdp4->pReceivePending = NULL;\r
1587 \r
1588 //\r
1589 // Determine if this receive was successful\r
1590 //\r
1591 pSocket = pPort->pSocket;\r
1592 Status = pUdp4->RxToken.Status;\r
1593 if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {\r
1594 pRxData = pUdp4->RxToken.Packet.RxData;\r
1595 if ( PORT_STATE_CLOSE_STARTED >= pPort->State ) {\r
1596 //\r
1597 // Save the data in the packet\r
1598 //\r
1599 pPacket->Op.Udp4Rx.pRxData = pRxData;\r
1600\r
1601 //\r
1602 // Queue this packet\r
1603 //\r
1604 pPrevious = pSocket->pRxPacketListTail;\r
1605 if ( NULL == pPrevious ) {\r
1606 pSocket->pRxPacketListHead = pPacket;\r
1607 }\r
1608 else {\r
1609 pPrevious->pNext = pPacket;\r
1610 }\r
1611 pSocket->pRxPacketListTail = pPacket;\r
1612\r
1613 //\r
1614 // Account for the normal data\r
1615 //\r
1616 LengthInBytes = pRxData->DataLength;\r
1617 pSocket->RxBytes += LengthInBytes;\r
1618\r
1619 //\r
1620 // Log the received data\r
1621 //\r
1622 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1623 "Received packet from: %d.%d.%d.%d:%d\r\n",\r
1624 pRxData->UdpSession.SourceAddress.Addr[0],\r
1625 pRxData->UdpSession.SourceAddress.Addr[1],\r
1626 pRxData->UdpSession.SourceAddress.Addr[2],\r
1627 pRxData->UdpSession.SourceAddress.Addr[3],\r
1628 pRxData->UdpSession.SourcePort ));\r
1629 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1630 "Received packet sent to: %d.%d.%d.%d:%d\r\n",\r
1631 pRxData->UdpSession.DestinationAddress.Addr[0],\r
1632 pRxData->UdpSession.DestinationAddress.Addr[1],\r
1633 pRxData->UdpSession.DestinationAddress.Addr[2],\r
1634 pRxData->UdpSession.DestinationAddress.Addr[3],\r
1635 pRxData->UdpSession.DestinationPort ));\r
1636 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1637 "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of data\r\n",\r
1638 pPacket,\r
1639 pPort,\r
1640 LengthInBytes ));\r
1641\r
1642 //\r
1643 // Attempt to restart this receive operation\r
1644 //\r
1645 if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
1646 EslUdpRxStart4 ( pPort );\r
1647 }\r
1648 else {\r
1649 DEBUG (( DEBUG_RX,\r
1650 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
1651 pPort,\r
1652 pSocket->RxBytes ));\r
1653 }\r
1654 }\r
1655 else {\r
1656 //\r
1657 // The port is being closed\r
1658 // Return the buffer to the UDP4 driver\r
1659 //\r
1660 gBS->SignalEvent ( pRxData->RecycleSignal );\r
1661\r
1662 //\r
1663 // Free the packet\r
1664 //\r
1665 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
1666 }\r
1667 }\r
1668 else\r
1669 {\r
1670 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1671 "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",\r
1672 pPacket,\r
1673 pPort,\r
1674 Status ));\r
1675 \r
1676 //\r
1677 // Receive error, free the packet save the error\r
1678 //\r
1679 EslSocketPacketFree ( pPacket, DEBUG_RX );\r
1680 if ( !EFI_ERROR ( pSocket->RxError )) {\r
1681 pSocket->RxError = Status;\r
1682 }\r
1683 \r
1684 //\r
1685 // Update the port state\r
1686 //\r
1687 if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
1688 EslUdpPortCloseRxDone4 ( pPort );\r
1689 }\r
1690 else {\r
1691 if ( EFI_ERROR ( Status )) {\r
1692 pPort->State = PORT_STATE_RX_ERROR;\r
1693 }\r
1694 }\r
1695 }\r
1696 \r
1697 DBG_EXIT ( );\r
1698}\r
1699\r
1700\r
1701/**\r
1702 Start a receive operation\r
1703\r
1704 @param [in] pPort Address of the DT_PORT structure.\r
1705\r
1706 **/\r
1707VOID\r
1708EslUdpRxStart4 (\r
1709 IN DT_PORT * pPort\r
1710 )\r
1711{\r
1712 DT_PACKET * pPacket;\r
1713 DT_SOCKET * pSocket;\r
1714 DT_UDP4_CONTEXT * pUdp4;\r
1715 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
1716 EFI_STATUS Status;\r
1717\r
1718 DBG_ENTER ( );\r
1719\r
1720 //\r
1721 // Determine if a receive is already pending\r
1722 //\r
1723 Status = EFI_SUCCESS;\r
1724 pPacket = NULL;\r
1725 pSocket = pPort->pSocket;\r
1726 pUdp4 = &pPort->Context.Udp4;\r
1727 if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
1728 if (( NULL == pUdp4->pReceivePending )\r
1729 && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
1730 //\r
1731 // Determine if there are any free packets\r
1732 //\r
1733 pPacket = pSocket->pRxFree;\r
1734 if ( NULL != pPacket ) {\r
1735 //\r
1736 // Remove this packet from the free list\r
1737 //\r
1738 pSocket->pRxFree = pPacket->pNext;\r
1739 DEBUG (( DEBUG_RX,\r
1740 "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
1741 pPort,\r
1742 pPacket ));\r
1743 }\r
1744 else {\r
1745 //\r
1746 // Allocate a packet structure\r
1747 //\r
1748 Status = EslSocketPacketAllocate ( &pPacket,\r
1749 sizeof ( pPacket->Op.Udp4Rx ),\r
1750 DEBUG_RX );\r
1751 if ( EFI_ERROR ( Status )) {\r
1752 pPacket = NULL;\r
1753 DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
1754 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",\r
1755 pPort,\r
1756 Status ));\r
1757 }\r
1758 }\r
1759\r
1760 //\r
1761 // Determine if a packet is available\r
1762 //\r
1763 if ( NULL != pPacket ) {\r
1764 //\r
1765 // Initialize the buffer for receive\r
1766 //\r
1767 pPacket->pNext = NULL;\r
1768 pPacket->Op.Udp4Rx.pRxData = NULL;\r
1769 pUdp4->RxToken.Packet.RxData = NULL;\r
1770 pUdp4->pReceivePending = pPacket;\r
1771\r
1772 //\r
1773 // Start the receive on the packet\r
1774 //\r
1775 pUdp4Protocol = pUdp4->pProtocol;\r
1776 Status = pUdp4Protocol->Receive ( pUdp4Protocol,\r
1777 &pUdp4->RxToken );\r
1778 if ( !EFI_ERROR ( Status )) {\r
1779 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1780 "0x%08x: Packet receive pending on port 0x%08x\r\n",\r
1781 pPacket,\r
1782 pPort ));\r
1783 }\r
1784 else {\r
1785 DEBUG (( DEBUG_RX | DEBUG_INFO,\r
1786 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",\r
1787 pPort,\r
1788 Status ));\r
1789 if ( !EFI_ERROR ( pSocket->RxError )) {\r
1790 //\r
1791 // Save the error status\r
1792 //\r
1793 pSocket->RxError = Status;\r
1794 }\r
1795\r
1796 //\r
1797 // Free the packet\r
1798 //\r
1799 pUdp4->pReceivePending = NULL;\r
1800 pPacket->pNext = pSocket->pRxFree;\r
1801 pSocket->pRxFree = pPacket;\r
1802 }\r
1803 }\r
1804 }\r
1805 }\r
1806\r
1807 DBG_EXIT ( );\r
1808}\r
1809\r
1810\r
1811/**\r
1812 Shutdown the UDP4 service.\r
1813\r
1814 This routine undoes the work performed by ::UdpInitialize4.\r
1815\r
1816 @param [in] pService DT_SERVICE structure address\r
1817\r
1818**/\r
1819VOID\r
1820EFIAPI\r
1821EslUdpShutdown4 (\r
1822 IN DT_SERVICE * pService\r
1823 )\r
1824{\r
1825 DT_LAYER * pLayer;\r
1826 DT_PORT * pPort;\r
1827 DT_SERVICE * pPreviousService;\r
1828\r
1829 DBG_ENTER ( );\r
1830\r
1831 //\r
1832 // Verify the socket layer synchronization\r
1833 //\r
1834 VERIFY_TPL ( TPL_SOCKETS );\r
1835\r
1836 //\r
1837 // Walk the list of ports\r
1838 //\r
1839 do {\r
1840 pPort = pService->pPortList;\r
1841 if ( NULL != pPort ) {\r
1842 //\r
1843 // Remove the port from the port list\r
1844 //\r
1845 pService->pPortList = pPort->pLinkService;\r
1846\r
1847 //\r
1848 // Close the port\r
1849 // TODO: Fix this\r
1850 //\r
1851// pPort->pfnClosePort ( pPort, 0 );\r
1852 }\r
1853 } while ( NULL != pPort );\r
1854\r
1855 //\r
1856 // Remove the service from the service list\r
1857 //\r
1858 pLayer = &mEslLayer;\r
1859 pPreviousService = pLayer->pUdp4List;\r
1860 if ( pService == pPreviousService ) {\r
1861 //\r
1862 // Remove the service from the beginning of the list\r
1863 //\r
1864 pLayer->pUdp4List = pService->pNext;\r
1865 }\r
1866 else {\r
1867 //\r
1868 // Remove the service from the middle of the list\r
1869 //\r
1870 while ( NULL != pPreviousService ) {\r
1871 if ( pService == pPreviousService->pNext ) {\r
1872 pPreviousService->pNext = pService->pNext;\r
1873 break;\r
1874 }\r
1875 }\r
1876 }\r
1877\r
1878 DBG_EXIT ( );\r
1879}\r
1880\r
1881\r
1882/**\r
1883 Determine if the sockedt is configured.\r
1884\r
1885\r
1886 @param [in] pSocket Address of a DT_SOCKET structure\r
1887 \r
1888 @retval EFI_SUCCESS - The port is connected\r
1889 @retval EFI_NOT_STARTED - The port is not connected\r
1890\r
1891 **/\r
1892 EFI_STATUS\r
1893 EslUdpSocketIsConfigured4 (\r
1894 IN DT_SOCKET * pSocket\r
1895 )\r
1896{\r
1897 DT_PORT * pPort;\r
1898 DT_PORT * pNextPort;\r
1899 DT_UDP4_CONTEXT * pUdp4;\r
1900 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
1901 EFI_STATUS Status;\r
1902 struct sockaddr_in LocalAddress;\r
1903\r
1904 DBG_ENTER ( );\r
1905\r
1906 //\r
1907 // Assume success\r
1908 //\r
1909 Status = EFI_SUCCESS;\r
1910\r
1911 //\r
1912 // Configure the port if necessary\r
1913 //\r
1914 if ( !pSocket->bConfigured ) {\r
1915 //\r
1916 // Fill in the port list if necessary\r
1917 //\r
1918 if ( NULL == pSocket->pPortList ) {\r
1919 LocalAddress.sin_len = sizeof ( LocalAddress );\r
1920 LocalAddress.sin_family = AF_INET;\r
1921 LocalAddress.sin_addr.s_addr = 0;\r
1922 LocalAddress.sin_port = 0;\r
1923 Status = EslUdpBind4 ( pSocket,\r
1924 (struct sockaddr *)&LocalAddress,\r
1925 LocalAddress.sin_len );\r
1926 }\r
1927\r
1928 //\r
1929 // Walk the port list\r
1930 //\r
1931 pPort = pSocket->pPortList;\r
1932 while ( NULL != pPort ) {\r
1933 //\r
1934 // Attempt to configure the port\r
1935 //\r
1936 pNextPort = pPort->pLinkSocket;\r
1937 pUdp4 = &pPort->Context.Udp4;\r
1938 pUdp4Protocol = pUdp4->pProtocol;\r
1939 Status = pUdp4Protocol->Configure ( pUdp4Protocol,\r
1940 &pUdp4->ConfigData );\r
1941 if ( EFI_ERROR ( Status )) {\r
1942 DEBUG (( DEBUG_LISTEN,\r
1943 "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",\r
1944 Status ));\r
1945 switch ( Status ) {\r
1946 case EFI_ACCESS_DENIED:\r
1947 pSocket->errno = EACCES;\r
1948 break;\r
1949\r
1950 default:\r
1951 case EFI_DEVICE_ERROR:\r
1952 pSocket->errno = EIO;\r
1953 break;\r
1954\r
1955 case EFI_INVALID_PARAMETER:\r
1956 pSocket->errno = EADDRNOTAVAIL;\r
1957 break;\r
1958\r
1959 case EFI_NO_MAPPING:\r
1960 pSocket->errno = EAFNOSUPPORT;\r
1961 break;\r
1962\r
1963 case EFI_OUT_OF_RESOURCES:\r
1964 pSocket->errno = ENOBUFS;\r
1965 break;\r
1966\r
1967 case EFI_UNSUPPORTED:\r
1968 pSocket->errno = EOPNOTSUPP;\r
1969 break;\r
1970 }\r
1971 }\r
1972 else {\r
1973 DEBUG (( DEBUG_LISTEN,\r
1974 "0x%08x: Port configured\r\n",\r
1975 pPort ));\r
1976 pUdp4->bConfigured = TRUE;\r
1977\r
1978 //\r
1979 // Start the first read on the port\r
1980 //\r
1981 EslUdpRxStart4 ( pPort );\r
1982\r
1983 //\r
1984 // The socket is connected\r
1985 //\r
1986 pSocket->State = SOCKET_STATE_CONNECTED;\r
1987 }\r
1988\r
1989 //\r
1990 // Set the next port\r
1991 //\r
1992 pPort = pNextPort;\r
1993 }\r
1994\r
1995 //\r
1996 // Determine the configuration status\r
1997 //\r
1998 if ( NULL != pSocket->pPortList ) {\r
1999 pSocket->bConfigured = TRUE;\r
2000 }\r
2001 }\r
2002\r
2003 //\r
2004 // Determine the socket configuration status\r
2005 //\r
2006 if ( !EFI_ERROR ( Status )) {\r
2007 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
2008 }\r
2009 \r
2010 //\r
2011 // Return the port connected state.\r
2012 //\r
2013 DBG_EXIT_STATUS ( Status );\r
2014 return Status;\r
2015}\r
2016\r
2017\r
2018/**\r
2019 Buffer data for transmission over a network connection.\r
2020\r
2021 This routine is called by the socket layer API to buffer\r
2022 data for transmission. The data is copied into a local buffer\r
2023 freeing the application buffer for reuse upon return. When\r
2024 necessary, this routine will start the transmit engine that\r
2025 performs the data transmission on the network connection. The\r
2026 transmit engine transmits the data a packet at a time over the\r
2027 network connection.\r
2028\r
2029 Transmission errors are returned during the next transmission or\r
2030 during the close operation. Only buffering errors are returned\r
2031 during the current transmission attempt.\r
2032\r
2033 @param [in] pSocket Address of a DT_SOCKET structure\r
2034\r
2035 @param [in] Flags Message control flags\r
2036\r
2037 @param [in] BufferLength Length of the the buffer\r
2038\r
2039 @param [in] pBuffer Address of a buffer to receive the data.\r
2040\r
2041 @param [in] pDataLength Number of received data bytes in the buffer.\r
2042\r
2043 @param [in] pAddress Network address of the remote system address\r
2044\r
2045 @param [in] AddressLength Length of the remote network address structure\r
2046\r
2047 @retval EFI_SUCCESS - Socket data successfully buffered\r
2048\r
2049**/\r
2050EFI_STATUS\r
2051EslUdpTxBuffer4 (\r
2052 IN DT_SOCKET * pSocket,\r
2053 IN int Flags,\r
2054 IN size_t BufferLength,\r
2055 IN CONST UINT8 * pBuffer,\r
2056 OUT size_t * pDataLength,\r
2057 IN const struct sockaddr * pAddress,\r
2058 IN socklen_t AddressLength\r
2059 )\r
2060{\r
2061 DT_PACKET * pPacket;\r
2062 DT_PACKET * pPreviousPacket;\r
2063 DT_PACKET ** ppPacket;\r
2064 DT_PORT * pPort;\r
2065 const struct sockaddr_in * pRemoteAddress;\r
2066 DT_UDP4_CONTEXT * pUdp4;\r
2067 EFI_UDP4_COMPLETION_TOKEN * pToken;\r
2068 size_t * pTxBytes;\r
2069 DT_UDP4_TX_DATA * pTxData;\r
2070 EFI_STATUS Status;\r
2071 EFI_TPL TplPrevious;\r
2072\r
2073 DBG_ENTER ( );\r
2074\r
2075 //\r
2076 // Assume failure\r
2077 //\r
2078 Status = EFI_UNSUPPORTED;\r
2079 pSocket->errno = ENOTCONN;\r
2080 * pDataLength = 0;\r
2081\r
2082 //\r
2083 // Verify that the socket is connected\r
2084 //\r
2085 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
2086 //\r
2087 // Locate the port\r
2088 //\r
2089 pPort = pSocket->pPortList;\r
2090 if ( NULL != pPort ) {\r
2091 //\r
2092 // Determine the queue head\r
2093 //\r
2094 pUdp4 = &pPort->Context.Udp4;\r
2095 ppPacket = &pUdp4->pTxPacket;\r
2096 pToken = &pUdp4->TxToken;\r
2097 pTxBytes = &pSocket->TxBytes;\r
2098\r
2099 //\r
2100 // Verify that there is enough room to buffer another\r
2101 // transmit operation\r
2102 //\r
2103 if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
2104 //\r
2105 // Attempt to allocate the packet\r
2106 //\r
2107 Status = EslSocketPacketAllocate ( &pPacket,\r
2108 sizeof ( pPacket->Op.Udp4Tx )\r
2109 - sizeof ( pPacket->Op.Udp4Tx.Buffer )\r
2110 + BufferLength,\r
2111 DEBUG_TX );\r
2112 if ( !EFI_ERROR ( Status )) {\r
2113 //\r
2114 // Initialize the transmit operation\r
2115 //\r
2116 pTxData = &pPacket->Op.Udp4Tx;\r
2117 pTxData->TxData.GatewayAddress = NULL;\r
2118 pTxData->TxData.UdpSessionData = NULL;\r
2119 pTxData->TxData.DataLength = (UINT32) BufferLength;\r
2120 pTxData->TxData.FragmentCount = 1;\r
2121 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
2122 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];\r
2123\r
2124 //\r
2125 // Set the remote system address if necessary\r
2126 //\r
2127 if ( NULL != pAddress ) {\r
2128 pRemoteAddress = (const struct sockaddr_in *)pAddress;\r
2129 pTxData->Session.SourceAddress.Addr[0] = 0;\r
2130 pTxData->Session.SourceAddress.Addr[1] = 0;\r
2131 pTxData->Session.SourceAddress.Addr[2] = 0;\r
2132 pTxData->Session.SourceAddress.Addr[3] = 0;\r
2133 pTxData->Session.SourcePort = 0;\r
2134 pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;\r
2135 pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
2136 pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
2137 pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
2138 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );\r
2139\r
2140 //\r
2141 // Use the remote system address when sending this packet\r
2142 //\r
2143 pTxData->TxData.UdpSessionData = &pTxData->Session;\r
2144 }\r
2145\r
2146 //\r
2147 // Copy the data into the buffer\r
2148 //\r
2149 CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],\r
2150 pBuffer,\r
2151 BufferLength );\r
2152\r
2153 //\r
2154 // Synchronize with the socket layer\r
2155 //\r
2156 RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
2157\r
2158 //\r
2159 // Stop transmission after an error\r
2160 //\r
2161 if ( !EFI_ERROR ( pSocket->TxError )) {\r
2162 //\r
2163 // Display the request\r
2164 //\r
2165 DEBUG (( DEBUG_TX,\r
2166 "Send %d %s bytes from 0x%08x\r\n",\r
2167 BufferLength,\r
2168 pBuffer ));\r
2169\r
2170 //\r
2171 // Queue the data for transmission\r
2172 //\r
2173 pPacket->pNext = NULL;\r
2174 pPreviousPacket = pSocket->pTxPacketListTail;\r
2175 if ( NULL == pPreviousPacket ) {\r
2176 pSocket->pTxPacketListHead = pPacket;\r
2177 }\r
2178 else {\r
2179 pPreviousPacket->pNext = pPacket;\r
2180 }\r
2181 pSocket->pTxPacketListTail = pPacket;\r
2182 DEBUG (( DEBUG_TX,\r
2183 "0x%08x: Packet on transmit list\r\n",\r
2184 pPacket ));\r
2185\r
2186 //\r
2187 // Account for the buffered data\r
2188 //\r
2189 *pTxBytes += BufferLength;\r
2190 *pDataLength = BufferLength;\r
2191\r
2192 //\r
2193 // Start the transmit engine if it is idle\r
2194 //\r
2195 if ( NULL == pUdp4->pTxPacket ) {\r
2196 EslUdpTxStart4 ( pSocket->pPortList );\r
2197 }\r
2198 }\r
2199 else {\r
2200 //\r
2201 // Previous transmit error\r
2202 // Stop transmission\r
2203 //\r
2204 Status = pSocket->TxError;\r
2205 pSocket->errno = EIO;\r
2206\r
2207 //\r
2208 // Free the packet\r
2209 //\r
2210 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2211 }\r
2212\r
2213 //\r
2214 // Release the socket layer synchronization\r
2215 //\r
2216 RESTORE_TPL ( TplPrevious );\r
2217 }\r
2218 else {\r
2219 //\r
2220 // Packet allocation failed\r
2221 //\r
2222 pSocket->errno = ENOMEM;\r
2223 }\r
2224 }\r
2225 else {\r
2226 //\r
2227 // Not enough buffer space available\r
2228 //\r
2229 pSocket->errno = EAGAIN;\r
2230 Status = EFI_NOT_READY;\r
2231 }\r
2232 }\r
2233 }\r
2234\r
2235 //\r
2236 // Return the operation status\r
2237 //\r
2238 DBG_EXIT_STATUS ( Status );\r
2239 return Status;\r
2240}\r
2241\r
2242\r
2243/**\r
2244 Process the transmit completion\r
2245\r
2246 @param Event The normal transmit completion event\r
2247\r
2248 @param pPort The DT_PORT structure address\r
2249\r
2250**/\r
2251VOID\r
2252EslUdpTxComplete4 (\r
2253 IN EFI_EVENT Event,\r
2254 IN DT_PORT * pPort\r
2255 )\r
2256{\r
2257 UINT32 LengthInBytes;\r
2258 DT_PACKET * pCurrentPacket;\r
2259 DT_PACKET * pNextPacket;\r
2260 DT_PACKET * pPacket;\r
2261 DT_SOCKET * pSocket;\r
2262 DT_UDP4_CONTEXT * pUdp4;\r
2263 EFI_STATUS Status;\r
2264 \r
2265 DBG_ENTER ( );\r
2266 \r
2267 //\r
2268 // Locate the active transmit packet\r
2269 //\r
2270 pSocket = pPort->pSocket;\r
2271 pUdp4 = &pPort->Context.Udp4;\r
2272 pPacket = pUdp4->pTxPacket;\r
2273 \r
2274 //\r
2275 // Mark this packet as complete\r
2276 //\r
2277 pUdp4->pTxPacket = NULL;\r
2278 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;\r
2279 pSocket->TxBytes -= LengthInBytes;\r
2280 \r
2281 //\r
2282 // Save any transmit error\r
2283 //\r
2284 Status = pUdp4->TxToken.Status;\r
2285 if ( EFI_ERROR ( Status )) {\r
2286 if ( !EFI_ERROR ( pSocket->TxError )) {\r
2287 pSocket->TxError = Status;\r
2288 }\r
2289 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
2290 "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",\r
2291 pPacket,\r
2292 Status ));\r
2293 \r
2294 //\r
2295 // Empty the normal transmit list\r
2296 //\r
2297 pCurrentPacket = pPacket;\r
2298 pNextPacket = pSocket->pTxPacketListHead;\r
2299 while ( NULL != pNextPacket ) {\r
2300 pPacket = pNextPacket;\r
2301 pNextPacket = pPacket->pNext;\r
2302 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2303 }\r
2304 pSocket->pTxPacketListHead = NULL;\r
2305 pSocket->pTxPacketListTail = NULL;\r
2306 pPacket = pCurrentPacket;\r
2307 }\r
2308 else\r
2309 {\r
2310 DEBUG (( DEBUG_TX | DEBUG_INFO,\r
2311 "0x%08x: Packet transmitted %d bytes successfully\r\n",\r
2312 pPacket,\r
2313 LengthInBytes ));\r
2314 \r
2315 //\r
2316 // Verify the transmit engine is still running\r
2317 //\r
2318 if ( !pPort->bCloseNow ) {\r
2319 //\r
2320 // Start the next packet transmission\r
2321 //\r
2322 EslUdpTxStart4 ( pPort );\r
2323 }\r
2324 }\r
2325 \r
2326 //\r
2327 // Release this packet\r
2328 //\r
2329 EslSocketPacketFree ( pPacket, DEBUG_TX );\r
2330 \r
2331 //\r
2332 // Finish the close operation if necessary\r
2333 //\r
2334 if (( PORT_STATE_CLOSE_STARTED <= pPort->State )\r
2335 && ( NULL == pSocket->pTxPacketListHead )\r
2336 && ( NULL == pUdp4->pTxPacket )) {\r
2337 //\r
2338 // Indicate that the transmit is complete\r
2339 //\r
2340 EslUdpPortCloseTxDone4 ( pPort );\r
2341 }\r
2342 DBG_EXIT ( );\r
2343}\r
2344\r
2345\r
2346/**\r
2347 Transmit data using a network connection.\r
2348\r
2349 @param [in] pPort Address of a DT_PORT structure\r
2350\r
2351 **/\r
2352VOID\r
2353EslUdpTxStart4 (\r
2354 IN DT_PORT * pPort\r
2355 )\r
2356{\r
2357 DT_PACKET * pNextPacket;\r
2358 DT_PACKET * pPacket;\r
2359 DT_SOCKET * pSocket;\r
2360 DT_UDP4_CONTEXT * pUdp4;\r
2361 EFI_UDP4_PROTOCOL * pUdp4Protocol;\r
2362 EFI_STATUS Status;\r
2363\r
2364 DBG_ENTER ( );\r
2365\r
2366 //\r
2367 // Assume success\r
2368 //\r
2369 Status = EFI_SUCCESS;\r
2370\r
2371 //\r
2372 // Get the packet from the queue head\r
2373 //\r
2374 pSocket = pPort->pSocket;\r
2375 pPacket = pSocket->pTxPacketListHead;\r
2376 if ( NULL != pPacket ) {\r
2377 //\r
2378 // Remove the packet from the queue\r
2379 //\r
2380 pNextPacket = pPacket->pNext;\r
2381 pSocket->pTxPacketListHead = pNextPacket;\r
2382 if ( NULL == pNextPacket ) {\r
2383 pSocket->pTxPacketListTail = NULL;\r
2384 }\r
2385\r
2386 //\r
2387 // Set the packet as active\r
2388 //\r
2389 pUdp4 = &pPort->Context.Udp4;\r
2390 pUdp4->pTxPacket = pPacket;\r
2391\r
2392 //\r
2393 // Start the transmit operation\r
2394 //\r
2395 pUdp4Protocol = pUdp4->pProtocol;\r
2396 pUdp4->TxToken.Packet.TxData = &pPacket->Op.Udp4Tx.TxData;\r
2397 Status = pUdp4Protocol->Transmit ( pUdp4Protocol, &pUdp4->TxToken );\r
2398 if ( EFI_ERROR ( Status )) {\r
2399 pSocket = pPort->pSocket;\r
2400 if ( EFI_SUCCESS == pSocket->TxError ) {\r
2401 pSocket->TxError = Status;\r
2402 }\r
2403 }\r
2404 }\r
2405\r
2406 DBG_EXIT ( );\r
2407}\r
2408\r