]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Udp4.c
Return the proper status after one of the ports is configured for UDP or IP communica...
[mirror_edk2.git] / StdLib / EfiSocketLib / Udp4.c
1 /** @file
2 Implement the UDP4 driver support for the socket layer.
3
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Socket.h"
16
17
18 /**
19 Get the local socket address
20
21 This routine returns the IPv4 address and UDP port number associated
22 with the local socket.
23
24 This routine is called by ::EslSocketGetLocalAddress to determine the
25 network address for the SOCK_DGRAM socket.
26
27 @param [in] pPort Address of an ::ESL_PORT structure.
28
29 @param [out] pSockAddr Network address to receive the local system address
30
31 **/
32 VOID
33 EslUdp4LocalAddressGet (
34 IN ESL_PORT * pPort,
35 OUT struct sockaddr * pSockAddr
36 )
37 {
38 struct sockaddr_in * pLocalAddress;
39 ESL_UDP4_CONTEXT * pUdp4;
40
41 DBG_ENTER ( );
42
43 //
44 // Return the local address
45 //
46 pUdp4 = &pPort->Context.Udp4;
47 pLocalAddress = (struct sockaddr_in *)pSockAddr;
48 pLocalAddress->sin_family = AF_INET;
49 pLocalAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.StationPort );
50 CopyMem ( &pLocalAddress->sin_addr,
51 &pUdp4->ConfigData.StationAddress.Addr[0],
52 sizeof ( pLocalAddress->sin_addr ));
53
54 DBG_EXIT ( );
55 }
56
57
58 /**
59 Set the local port address.
60
61 This routine sets the local port address.
62
63 This support routine is called by ::EslSocketPortAllocate.
64
65 @param [in] pPort Address of an ESL_PORT structure
66 @param [in] pSockAddr Address of a sockaddr structure that contains the
67 connection point on the local machine. An IPv4 address
68 of INADDR_ANY specifies that the connection is made to
69 all of the network stacks on the platform. Specifying a
70 specific IPv4 address restricts the connection to the
71 network stack supporting that address. Specifying zero
72 for the port causes the network layer to assign a port
73 number from the dynamic range. Specifying a specific
74 port number causes the network layer to use that port.
75
76 @param [in] bBindTest TRUE = run bind testing
77
78 @retval EFI_SUCCESS The operation was successful
79
80 **/
81 EFI_STATUS
82 EslUdp4LocalAddressSet (
83 IN ESL_PORT * pPort,
84 IN CONST struct sockaddr * pSockAddr,
85 IN BOOLEAN bBindTest
86 )
87 {
88 EFI_UDP4_CONFIG_DATA * pConfig;
89 CONST struct sockaddr_in * pIpAddress;
90 CONST UINT8 * pIpv4Address;
91 EFI_STATUS Status;
92
93 DBG_ENTER ( );
94
95 //
96 // Validate the address
97 //
98 pIpAddress = (struct sockaddr_in *)pSockAddr;
99 if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {
100 //
101 // The local address must not be the broadcast address
102 //
103 Status = EFI_INVALID_PARAMETER;
104 pPort->pSocket->errno = EADDRNOTAVAIL;
105 }
106 else {
107 //
108 // Set the local address
109 //
110 pIpAddress = (struct sockaddr_in *)pSockAddr;
111 pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;
112 pConfig = &pPort->Context.Udp4.ConfigData;
113 pConfig->StationAddress.Addr[0] = pIpv4Address[0];
114 pConfig->StationAddress.Addr[1] = pIpv4Address[1];
115 pConfig->StationAddress.Addr[2] = pIpv4Address[2];
116 pConfig->StationAddress.Addr[3] = pIpv4Address[3];
117
118 //
119 // Determine if the default address is used
120 //
121 pConfig->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );
122
123 //
124 // Set the subnet mask
125 //
126 if ( pConfig->UseDefaultAddress ) {
127 pConfig->SubnetMask.Addr[0] = 0;
128 pConfig->SubnetMask.Addr[1] = 0;
129 pConfig->SubnetMask.Addr[2] = 0;
130 pConfig->SubnetMask.Addr[3] = 0;
131 }
132 else {
133 pConfig->SubnetMask.Addr[0] = 0xff;
134 pConfig->SubnetMask.Addr[1] = ( 128 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
135 pConfig->SubnetMask.Addr[2] = ( 192 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
136 pConfig->SubnetMask.Addr[3] = ( 224 <= pConfig->StationAddress.Addr[0]) ? 0xff : 0;
137 }
138
139 //
140 // Validate the IP address
141 //
142 pConfig->StationPort = 0;
143 Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )
144 : EFI_SUCCESS;
145 if ( !EFI_ERROR ( Status )) {
146 //
147 // Set the port number
148 //
149 pConfig->StationPort = SwapBytes16 ( pIpAddress->sin_port );
150
151 //
152 // Display the local address
153 //
154 DEBUG (( DEBUG_BIND,
155 "0x%08x: Port, Local UDP4 Address: %d.%d.%d.%d:%d\r\n",
156 pPort,
157 pConfig->StationAddress.Addr[0],
158 pConfig->StationAddress.Addr[1],
159 pConfig->StationAddress.Addr[2],
160 pConfig->StationAddress.Addr[3],
161 pConfig->StationPort ));
162 }
163 }
164
165 //
166 // Return the operation status
167 //
168 DBG_EXIT_STATUS ( Status );
169 return Status;
170 }
171
172
173 /**
174 Free a receive packet
175
176 This routine performs the network specific operations necessary
177 to free a receive packet.
178
179 This routine is called by ::EslSocketPortCloseTxDone to free a
180 receive packet.
181
182 @param [in] pPacket Address of an ::ESL_PACKET structure.
183 @param [in, out] pRxBytes Address of the count of RX bytes
184
185 **/
186 VOID
187 EslUdp4PacketFree (
188 IN ESL_PACKET * pPacket,
189 IN OUT size_t * pRxBytes
190 )
191 {
192 EFI_UDP4_RECEIVE_DATA * pRxData;
193
194 DBG_ENTER ( );
195
196 //
197 // Account for the receive bytes
198 //
199 pRxData = pPacket->Op.Udp4Rx.pRxData;
200 *pRxBytes -= pRxData->DataLength;
201
202 //
203 // Disconnect the buffer from the packet
204 //
205 pPacket->Op.Udp4Rx.pRxData = NULL;
206
207 //
208 // Return the buffer to the UDP4 driver
209 //
210 gBS->SignalEvent ( pRxData->RecycleSignal );
211 DBG_EXIT ( );
212 }
213
214
215 /**
216 Initialize the network specific portions of an ::ESL_PORT structure.
217
218 This routine initializes the network specific portions of an
219 ::ESL_PORT structure for use by the socket.
220
221 This support routine is called by ::EslSocketPortAllocate
222 to connect the socket with the underlying network adapter
223 running the UDPv4 protocol.
224
225 @param [in] pPort Address of an ESL_PORT structure
226 @param [in] DebugFlags Flags for debug messages
227
228 @retval EFI_SUCCESS - Socket successfully created
229
230 **/
231 EFI_STATUS
232 EslUdp4PortAllocate (
233 IN ESL_PORT * pPort,
234 IN UINTN DebugFlags
235 )
236 {
237 EFI_UDP4_CONFIG_DATA * pConfig;
238 ESL_SOCKET * pSocket;
239 EFI_STATUS Status;
240
241 DBG_ENTER ( );
242
243 //
244 // Initialize the port
245 //
246 pSocket = pPort->pSocket;
247 pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Udp4Tx.TxData );
248 pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Tx.Event );
249 pSocket->TxTokenOffset = OFFSET_OF ( EFI_UDP4_COMPLETION_TOKEN, Packet.TxData );
250
251 //
252 // Save the cancel, receive and transmit addresses
253 //
254 pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.UDPv4->Configure;
255 pPort->pfnRxCancel = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Cancel;
256 pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.UDPv4->Poll;
257 pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
258 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
259
260 //
261 // Set the configuration flags
262 //
263 pConfig = &pPort->Context.Udp4.ConfigData;
264 pConfig->TimeToLive = 255;
265 pConfig->AcceptAnyPort = FALSE;
266 pConfig->AcceptBroadcast = FALSE;
267 pConfig->AcceptPromiscuous = FALSE;
268 pConfig->AllowDuplicatePort = TRUE;
269 pConfig->DoNotFragment = TRUE;
270 Status = EFI_SUCCESS;
271
272 //
273 // Return the operation status
274 //
275 DBG_EXIT_STATUS ( Status );
276 return Status;
277 }
278
279
280 /**
281 Receive data from a network connection.
282
283 This routine attempts to return buffered data to the caller. The
284 data is removed from the urgent queue if the message flag MSG_OOB
285 is specified, otherwise data is removed from the normal queue.
286 See the \ref ReceiveEngine section.
287
288 This routine is called by ::EslSocketReceive to handle the network
289 specific receive operation to support SOCK_DGRAM sockets.
290
291 @param [in] pPort Address of an ::ESL_PORT structure.
292
293 @param [in] pPacket Address of an ::ESL_PACKET structure.
294
295 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
296
297 @param [in] BufferLength Length of the the buffer
298
299 @param [in] pBuffer Address of a buffer to receive the data.
300
301 @param [in] pDataLength Number of received data bytes in the buffer.
302
303 @param [out] pAddress Network address to receive the remote system address
304
305 @param [out] pSkipBytes Address to receive the number of bytes skipped
306
307 @return Returns the address of the next free byte in the buffer.
308
309 **/
310 UINT8 *
311 EslUdp4Receive (
312 IN ESL_PORT * pPort,
313 IN ESL_PACKET * pPacket,
314 IN BOOLEAN * pbConsumePacket,
315 IN size_t BufferLength,
316 IN UINT8 * pBuffer,
317 OUT size_t * pDataLength,
318 OUT struct sockaddr * pAddress,
319 OUT size_t * pSkipBytes
320 )
321 {
322 size_t DataBytes;
323 struct sockaddr_in * pRemoteAddress;
324 EFI_UDP4_RECEIVE_DATA * pRxData;
325
326 DBG_ENTER ( );
327
328 pRxData = pPacket->Op.Udp4Rx.pRxData;
329 //
330 // Return the remote system address if requested
331 //
332 if ( NULL != pAddress ) {
333 //
334 // Build the remote address
335 //
336 DEBUG (( DEBUG_RX,
337 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
338 pRxData->UdpSession.SourceAddress.Addr[0],
339 pRxData->UdpSession.SourceAddress.Addr[1],
340 pRxData->UdpSession.SourceAddress.Addr[2],
341 pRxData->UdpSession.SourceAddress.Addr[3],
342 pRxData->UdpSession.SourcePort ));
343 pRemoteAddress = (struct sockaddr_in *)pAddress;
344 CopyMem ( &pRemoteAddress->sin_addr,
345 &pRxData->UdpSession.SourceAddress.Addr[0],
346 sizeof ( pRemoteAddress->sin_addr ));
347 pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
348 }
349
350 //
351 // Copy the received data
352 //
353 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
354 (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
355 BufferLength,
356 pBuffer,
357 &DataBytes );
358
359 //
360 // Determine if the data is being read
361 //
362 if ( *pbConsumePacket ) {
363 //
364 // Display for the bytes consumed
365 //
366 DEBUG (( DEBUG_RX,
367 "0x%08x: Port account for 0x%08x bytes\r\n",
368 pPort,
369 DataBytes ));
370
371 //
372 // Account for any discarded data
373 //
374 *pSkipBytes = pRxData->DataLength - DataBytes;
375 }
376
377 //
378 // Return the data length and the buffer address
379 //
380 *pDataLength = DataBytes;
381 DBG_EXIT_HEX ( pBuffer );
382 return pBuffer;
383 }
384
385
386 /**
387 Get the remote socket address
388
389 This routine returns the address of the remote connection point
390 associated with the SOCK_DGRAM socket.
391
392 This routine is called by ::EslSocketGetPeerAddress to detemine
393 the UDPv4 address and port number associated with the network adapter.
394
395 @param [in] pPort Address of an ::ESL_PORT structure.
396
397 @param [out] pAddress Network address to receive the remote system address
398
399 **/
400 VOID
401 EslUdp4RemoteAddressGet (
402 IN ESL_PORT * pPort,
403 OUT struct sockaddr * pAddress
404 )
405 {
406 struct sockaddr_in * pRemoteAddress;
407 ESL_UDP4_CONTEXT * pUdp4;
408
409 DBG_ENTER ( );
410
411 //
412 // Return the remote address
413 //
414 pUdp4 = &pPort->Context.Udp4;
415 pRemoteAddress = (struct sockaddr_in *)pAddress;
416 pRemoteAddress->sin_family = AF_INET;
417 pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
418 CopyMem ( &pRemoteAddress->sin_addr,
419 &pUdp4->ConfigData.RemoteAddress.Addr[0],
420 sizeof ( pRemoteAddress->sin_addr ));
421
422 DBG_EXIT ( );
423 }
424
425
426 /**
427 Set the remote address
428
429 This routine sets the remote address in the port.
430
431 This routine is called by ::EslSocketConnect to specify the
432 remote network address.
433
434 @param [in] pPort Address of an ::ESL_PORT structure.
435
436 @param [in] pSockAddr Network address of the remote system.
437
438 @param [in] SockAddrLength Length in bytes of the network address.
439
440 @retval EFI_SUCCESS The operation was successful
441
442 **/
443 EFI_STATUS
444 EslUdp4RemoteAddressSet (
445 IN ESL_PORT * pPort,
446 IN CONST struct sockaddr * pSockAddr,
447 IN socklen_t SockAddrLength
448 )
449 {
450 CONST struct sockaddr_in * pRemoteAddress;
451 ESL_UDP4_CONTEXT * pUdp4;
452 EFI_STATUS Status;
453
454 DBG_ENTER ( );
455
456 //
457 // Set the remote address
458 //
459 pUdp4 = &pPort->Context.Udp4;
460 pRemoteAddress = (struct sockaddr_in *)pSockAddr;
461 pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
462 pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
463 pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
464 pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
465 pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
466 pPort->pSocket->bAddressSet = TRUE;
467 Status = EFI_SUCCESS;
468
469 //
470 // Return the operation status
471 //
472 DBG_EXIT_STATUS ( Status );
473 return Status;
474 }
475
476
477 /**
478 Process the receive completion
479
480 This routine keeps the UDPv4 driver's buffer and queues it in
481 in FIFO order to the data queue. The UDP4 driver's buffer will
482 be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.
483 See the \ref ReceiveEngine section.
484
485 This routine is called by the UDPv4 driver when data is
486 received.
487
488 @param [in] Event The receive completion event
489
490 @param [in] pIo Address of an ::ESL_IO_MGMT structure
491
492 **/
493 VOID
494 EslUdp4RxComplete (
495 IN EFI_EVENT Event,
496 IN ESL_IO_MGMT * pIo
497 )
498 {
499 size_t LengthInBytes;
500 ESL_PACKET * pPacket;
501 EFI_UDP4_RECEIVE_DATA * pRxData;
502 EFI_STATUS Status;
503
504 DBG_ENTER ( );
505
506 //
507 // Get the operation status.
508 //
509 Status = pIo->Token.Udp4Rx.Status;
510
511 //
512 // Get the packet length
513 //
514 pRxData = pIo->Token.Udp4Rx.Packet.RxData;
515 LengthInBytes = pRxData->DataLength;
516
517 //
518 // +--------------------+ +-----------------------+
519 // | ESL_IO_MGMT | | Data Buffer |
520 // | | | (Driver owned) |
521 // | +---------------+ +-----------------------+
522 // | | Token | ^
523 // | | Rx Event | |
524 // | | | +-----------------------+
525 // | | RxData --> | EFI_UDP4_RECEIVE_DATA |
526 // +----+---------------+ | (Driver owned) |
527 // +-----------------------+
528 // +--------------------+ ^
529 // | ESL_PACKET | .
530 // | | .
531 // | +---------------+ .
532 // | | pRxData --> NULL .......
533 // +----+---------------+
534 //
535 //
536 // Save the data in the packet
537 //
538 pPacket = pIo->pPacket;
539 pPacket->Op.Udp4Rx.pRxData = pRxData;
540
541 //
542 // Complete this request
543 //
544 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
545 DBG_EXIT ( );
546 }
547
548
549 /**
550 Determine if the socket is configured.
551
552 This routine uses the flag ESL_SOCKET::bConfigured to determine
553 if the network layer's configuration routine has been called.
554 This routine calls the bind and configuration routines if they
555 were not already called. After the port is configured, the
556 \ref ReceiveEngine is started.
557
558 This routine is called by EslSocketIsConfigured to verify
559 that the socket is configured.
560
561 @param [in] pSocket Address of an ::ESL_SOCKET structure
562
563 @retval EFI_SUCCESS - The port is connected
564 @retval EFI_NOT_STARTED - The port is not connected
565
566 **/
567 EFI_STATUS
568 EslUdp4SocketIsConfigured (
569 IN ESL_SOCKET * pSocket
570 )
571 {
572 EFI_UDP4_CONFIG_DATA * pConfigData;
573 ESL_PORT * pPort;
574 ESL_PORT * pNextPort;
575 ESL_UDP4_CONTEXT * pUdp4;
576 EFI_UDP4_PROTOCOL * pUdp4Protocol;
577 EFI_STATUS Status;
578 struct sockaddr_in LocalAddress;
579
580 DBG_ENTER ( );
581
582 //
583 // Assume success
584 //
585 Status = EFI_SUCCESS;
586
587 //
588 // Configure the port if necessary
589 //
590 if ( !pSocket->bConfigured ) {
591 //
592 // Fill in the port list if necessary
593 //
594 pSocket->errno = ENETDOWN;
595 if ( NULL == pSocket->pPortList ) {
596 LocalAddress.sin_len = sizeof ( LocalAddress );
597 LocalAddress.sin_family = AF_INET;
598 LocalAddress.sin_addr.s_addr = 0;
599 LocalAddress.sin_port = 0;
600 Status = EslSocketBind ( &pSocket->SocketProtocol,
601 (struct sockaddr *)&LocalAddress,
602 LocalAddress.sin_len,
603 &pSocket->errno );
604 }
605
606 //
607 // Walk the port list
608 //
609 pPort = pSocket->pPortList;
610 while ( NULL != pPort ) {
611 //
612 // Attempt to configure the port
613 //
614 pNextPort = pPort->pLinkSocket;
615 pUdp4 = &pPort->Context.Udp4;
616 pUdp4Protocol = pPort->pProtocol.UDPv4;
617 pConfigData = &pUdp4->ConfigData;
618 DEBUG (( DEBUG_TX,
619 "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
620 pPort,
621 pConfigData->StationAddress.Addr[0],
622 pConfigData->StationAddress.Addr[1],
623 pConfigData->StationAddress.Addr[2],
624 pConfigData->StationAddress.Addr[3],
625 pConfigData->StationPort,
626 pConfigData->RemoteAddress.Addr[0],
627 pConfigData->RemoteAddress.Addr[1],
628 pConfigData->RemoteAddress.Addr[2],
629 pConfigData->RemoteAddress.Addr[3],
630 pConfigData->RemotePort ));
631 Status = pUdp4Protocol->Configure ( pUdp4Protocol,
632 pConfigData );
633 if ( !EFI_ERROR ( Status )) {
634 //
635 // Update the configuration data
636 //
637 Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,
638 pConfigData,
639 NULL,
640 NULL,
641 NULL );
642 }
643 if ( EFI_ERROR ( Status )) {
644 if ( !pSocket->bConfigured ) {
645 DEBUG (( DEBUG_LISTEN,
646 "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",
647 Status ));
648 switch ( Status ) {
649 case EFI_ACCESS_DENIED:
650 pSocket->errno = EACCES;
651 break;
652
653 default:
654 case EFI_DEVICE_ERROR:
655 pSocket->errno = EIO;
656 break;
657
658 case EFI_INVALID_PARAMETER:
659 pSocket->errno = EADDRNOTAVAIL;
660 break;
661
662 case EFI_NO_MAPPING:
663 pSocket->errno = EAFNOSUPPORT;
664 break;
665
666 case EFI_OUT_OF_RESOURCES:
667 pSocket->errno = ENOBUFS;
668 break;
669
670 case EFI_UNSUPPORTED:
671 pSocket->errno = EOPNOTSUPP;
672 break;
673 }
674 }
675 }
676 else {
677 DEBUG (( DEBUG_TX,
678 "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
679 pPort,
680 pConfigData->StationAddress.Addr[0],
681 pConfigData->StationAddress.Addr[1],
682 pConfigData->StationAddress.Addr[2],
683 pConfigData->StationAddress.Addr[3],
684 pConfigData->StationPort,
685 pConfigData->RemoteAddress.Addr[0],
686 pConfigData->RemoteAddress.Addr[1],
687 pConfigData->RemoteAddress.Addr[2],
688 pConfigData->RemoteAddress.Addr[3],
689 pConfigData->RemotePort ));
690 pPort->bConfigured = TRUE;
691 pSocket->bConfigured = TRUE;
692
693 //
694 // Start the first read on the port
695 //
696 EslSocketRxStart ( pPort );
697
698 //
699 // The socket is connected
700 //
701 pSocket->State = SOCKET_STATE_CONNECTED;
702 pSocket->errno = 0;
703 }
704
705 //
706 // Set the next port
707 //
708 pPort = pNextPort;
709 }
710 }
711
712 //
713 // Determine the socket configuration status
714 //
715 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
716
717 //
718 // Return the port connected state.
719 //
720 DBG_EXIT_STATUS ( Status );
721 return Status;
722 }
723
724
725 /**
726 Buffer data for transmission over a network connection.
727
728 This routine buffers data for the transmit engine in the normal
729 data queue. When the \ref TransmitEngine has resources, this
730 routine will start the transmission of the next buffer on the
731 network connection.
732
733 This routine is called by ::EslSocketTransmit to buffer
734 data for transmission. The data is copied into a local buffer
735 freeing the application buffer for reuse upon return. When
736 necessary, this routine starts the transmit engine that
737 performs the data transmission on the network connection. The
738 transmit engine transmits the data a packet at a time over the
739 network connection.
740
741 Transmission errors are returned during the next transmission or
742 during the close operation. Only buffering errors are returned
743 during the current transmission attempt.
744
745 @param [in] pSocket Address of an ::ESL_SOCKET structure
746
747 @param [in] Flags Message control flags
748
749 @param [in] BufferLength Length of the the buffer
750
751 @param [in] pBuffer Address of a buffer to receive the data.
752
753 @param [in] pDataLength Number of received data bytes in the buffer.
754
755 @param [in] pAddress Network address of the remote system address
756
757 @param [in] AddressLength Length of the remote network address structure
758
759 @retval EFI_SUCCESS - Socket data successfully buffered
760
761 **/
762 EFI_STATUS
763 EslUdp4TxBuffer (
764 IN ESL_SOCKET * pSocket,
765 IN int Flags,
766 IN size_t BufferLength,
767 IN CONST UINT8 * pBuffer,
768 OUT size_t * pDataLength,
769 IN const struct sockaddr * pAddress,
770 IN socklen_t AddressLength
771 )
772 {
773 ESL_PACKET * pPacket;
774 ESL_PACKET * pPreviousPacket;
775 ESL_PORT * pPort;
776 const struct sockaddr_in * pRemoteAddress;
777 ESL_UDP4_CONTEXT * pUdp4;
778 size_t * pTxBytes;
779 ESL_UDP4_TX_DATA * pTxData;
780 EFI_STATUS Status;
781 EFI_TPL TplPrevious;
782
783 DBG_ENTER ( );
784
785 //
786 // Assume failure
787 //
788 Status = EFI_UNSUPPORTED;
789 pSocket->errno = ENOTCONN;
790 *pDataLength = 0;
791
792 //
793 // Verify that the socket is connected
794 //
795 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
796 //
797 // Locate the port
798 //
799 pPort = pSocket->pPortList;
800 if ( NULL != pPort ) {
801 //
802 // Determine the queue head
803 //
804 pUdp4 = &pPort->Context.Udp4;
805 pTxBytes = &pSocket->TxBytes;
806
807 //
808 // Verify that there is enough room to buffer another
809 // transmit operation
810 //
811 if ( pSocket->MaxTxBuf > *pTxBytes ) {
812 //
813 // Attempt to allocate the packet
814 //
815 Status = EslSocketPacketAllocate ( &pPacket,
816 sizeof ( pPacket->Op.Udp4Tx )
817 - sizeof ( pPacket->Op.Udp4Tx.Buffer )
818 + BufferLength,
819 0,
820 DEBUG_TX );
821 if ( !EFI_ERROR ( Status )) {
822 //
823 // Initialize the transmit operation
824 //
825 pTxData = &pPacket->Op.Udp4Tx;
826 pTxData->TxData.GatewayAddress = NULL;
827 pTxData->TxData.UdpSessionData = NULL;
828 pTxData->TxData.DataLength = (UINT32) BufferLength;
829 pTxData->TxData.FragmentCount = 1;
830 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
831 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];
832 pTxData->RetransmitCount = 0;
833
834 //
835 // Set the remote system address if necessary
836 //
837 pTxData->TxData.UdpSessionData = NULL;
838 if ( NULL != pAddress ) {
839 pRemoteAddress = (const struct sockaddr_in *)pAddress;
840 pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];
841 pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];
842 pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];
843 pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];
844 pTxData->Session.SourcePort = 0;
845 pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
846 pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
847 pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
848 pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
849 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );
850
851 //
852 // Use the remote system address when sending this packet
853 //
854 pTxData->TxData.UdpSessionData = &pTxData->Session;
855 }
856
857 //
858 // Copy the data into the buffer
859 //
860 CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],
861 pBuffer,
862 BufferLength );
863
864 //
865 // Synchronize with the socket layer
866 //
867 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
868
869 //
870 // Stop transmission after an error
871 //
872 if ( !EFI_ERROR ( pSocket->TxError )) {
873 //
874 // Display the request
875 //
876 DEBUG (( DEBUG_TX,
877 "Send %d %s bytes from 0x%08x\r\n",
878 BufferLength,
879 pBuffer ));
880
881 //
882 // Queue the data for transmission
883 //
884 pPacket->pNext = NULL;
885 pPreviousPacket = pSocket->pTxPacketListTail;
886 if ( NULL == pPreviousPacket ) {
887 pSocket->pTxPacketListHead = pPacket;
888 }
889 else {
890 pPreviousPacket->pNext = pPacket;
891 }
892 pSocket->pTxPacketListTail = pPacket;
893 DEBUG (( DEBUG_TX,
894 "0x%08x: Packet on transmit list\r\n",
895 pPacket ));
896
897 //
898 // Account for the buffered data
899 //
900 *pTxBytes += BufferLength;
901 *pDataLength = BufferLength;
902
903 //
904 // Start the transmit engine if it is idle
905 //
906 if ( NULL != pPort->pTxFree ) {
907 EslSocketTxStart ( pPort,
908 &pSocket->pTxPacketListHead,
909 &pSocket->pTxPacketListTail,
910 &pPort->pTxActive,
911 &pPort->pTxFree );
912 }
913 }
914 else {
915 //
916 // Previous transmit error
917 // Stop transmission
918 //
919 Status = pSocket->TxError;
920 pSocket->errno = EIO;
921
922 //
923 // Free the packet
924 //
925 EslSocketPacketFree ( pPacket, DEBUG_TX );
926 }
927
928 //
929 // Release the socket layer synchronization
930 //
931 RESTORE_TPL ( TplPrevious );
932 }
933 else {
934 //
935 // Packet allocation failed
936 //
937 pSocket->errno = ENOMEM;
938 }
939 }
940 else {
941 //
942 // Not enough buffer space available
943 //
944 pSocket->errno = EAGAIN;
945 Status = EFI_NOT_READY;
946 }
947 }
948 }
949
950 //
951 // Return the operation status
952 //
953 DBG_EXIT_STATUS ( Status );
954 return Status;
955 }
956
957
958 /**
959 Process the transmit completion
960
961 This routine use ::EslSocketTxComplete to perform the transmit
962 completion processing for data packets.
963
964 This routine is called by the UDPv4 network layer when a data
965 transmit request completes.
966
967 @param [in] Event The normal transmit completion event
968
969 @param [in] pIo Address of an ::ESL_IO_MGMT structure
970
971 **/
972 VOID
973 EslUdp4TxComplete (
974 IN EFI_EVENT Event,
975 IN ESL_IO_MGMT * pIo
976 )
977 {
978 UINT32 LengthInBytes;
979 ESL_PORT * pPort;
980 ESL_PACKET * pPacket;
981 ESL_SOCKET * pSocket;
982 EFI_STATUS Status;
983
984 DBG_ENTER ( );
985
986 //
987 // Locate the active transmit packet
988 //
989 pPacket = pIo->pPacket;
990 pPort = pIo->pPort;
991 pSocket = pPort->pSocket;
992
993 //
994 // Get the transmit length and status
995 //
996 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
997 pSocket->TxBytes -= LengthInBytes;
998 Status = pIo->Token.Udp4Tx.Status;
999
1000 //
1001 // Complete the transmit operation
1002 //
1003 EslSocketTxComplete ( pIo,
1004 LengthInBytes,
1005 Status,
1006 "UDP ",
1007 &pSocket->pTxPacketListHead,
1008 &pSocket->pTxPacketListTail,
1009 &pPort->pTxActive,
1010 &pPort->pTxFree );
1011 DBG_EXIT ( );
1012 }
1013
1014
1015 /**
1016 Interface between the socket layer and the network specific
1017 code that supports SOCK_DGRAM sockets over UDPv4.
1018 **/
1019 CONST ESL_PROTOCOL_API cEslUdp4Api = {
1020 "UDPv4",
1021 IPPROTO_UDP,
1022 OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
1023 OFFSET_OF ( ESL_LAYER, pUdp4List ),
1024 OFFSET_OF ( struct sockaddr_in, sin_zero ),
1025 sizeof ( struct sockaddr_in ),
1026 AF_INET,
1027 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1028 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1029 OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
1030 FALSE,
1031 EADDRINUSE,
1032 NULL, // Accept
1033 NULL, // ConnectPoll
1034 NULL, // ConnectStart
1035 EslUdp4SocketIsConfigured,
1036 EslUdp4LocalAddressGet,
1037 EslUdp4LocalAddressSet,
1038 NULL, // Listen
1039 NULL, // OptionGet
1040 NULL, // OptionSet
1041 EslUdp4PacketFree,
1042 EslUdp4PortAllocate,
1043 NULL, // PortClose,
1044 NULL, // PortCloseOp
1045 TRUE,
1046 EslUdp4Receive,
1047 EslUdp4RemoteAddressGet,
1048 EslUdp4RemoteAddressSet,
1049 EslUdp4RxComplete,
1050 NULL, // RxStart
1051 EslUdp4TxBuffer,
1052 EslUdp4TxComplete,
1053 NULL // TxOobComplete
1054 };