]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/EfiSocketLib/Udp4.c
Update the sockets library code
[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] = 0xff;
135 pConfig->SubnetMask.Addr[2] = 0xff;
136 pConfig->SubnetMask.Addr[3] = 0xff;
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->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Receive;
257 pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.UDPv4->Transmit;
258
259 //
260 // Set the configuration flags
261 //
262 pConfig = &pPort->Context.Udp4.ConfigData;
263 pConfig->TimeToLive = 255;
264 pConfig->AcceptAnyPort = FALSE;
265 pConfig->AcceptBroadcast = FALSE;
266 pConfig->AcceptPromiscuous = FALSE;
267 pConfig->AllowDuplicatePort = TRUE;
268 pConfig->DoNotFragment = TRUE;
269 Status = EFI_SUCCESS;
270
271 //
272 // Return the operation status
273 //
274 DBG_EXIT_STATUS ( Status );
275 return Status;
276 }
277
278
279 /**
280 Receive data from a network connection.
281
282 This routine attempts to return buffered data to the caller. The
283 data is removed from the urgent queue if the message flag MSG_OOB
284 is specified, otherwise data is removed from the normal queue.
285 See the \ref ReceiveEngine section.
286
287 This routine is called by ::EslSocketReceive to handle the network
288 specific receive operation to support SOCK_DGRAM sockets.
289
290 @param [in] pPort Address of an ::ESL_PORT structure.
291
292 @param [in] pPacket Address of an ::ESL_PACKET structure.
293
294 @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed
295
296 @param [in] BufferLength Length of the the buffer
297
298 @param [in] pBuffer Address of a buffer to receive the data.
299
300 @param [in] pDataLength Number of received data bytes in the buffer.
301
302 @param [out] pAddress Network address to receive the remote system address
303
304 @param [out] pSkipBytes Address to receive the number of bytes skipped
305
306 @return Returns the address of the next free byte in the buffer.
307
308 **/
309 UINT8 *
310 EslUdp4Receive (
311 IN ESL_PORT * pPort,
312 IN ESL_PACKET * pPacket,
313 IN BOOLEAN * pbConsumePacket,
314 IN size_t BufferLength,
315 IN UINT8 * pBuffer,
316 OUT size_t * pDataLength,
317 OUT struct sockaddr * pAddress,
318 OUT size_t * pSkipBytes
319 )
320 {
321 size_t DataBytes;
322 struct sockaddr_in * pRemoteAddress;
323 EFI_UDP4_RECEIVE_DATA * pRxData;
324
325 DBG_ENTER ( );
326
327 pRxData = pPacket->Op.Udp4Rx.pRxData;
328 //
329 // Return the remote system address if requested
330 //
331 if ( NULL != pAddress ) {
332 //
333 // Build the remote address
334 //
335 DEBUG (( DEBUG_RX,
336 "Getting packet remote address: %d.%d.%d.%d:%d\r\n",
337 pRxData->UdpSession.SourceAddress.Addr[0],
338 pRxData->UdpSession.SourceAddress.Addr[1],
339 pRxData->UdpSession.SourceAddress.Addr[2],
340 pRxData->UdpSession.SourceAddress.Addr[3],
341 pRxData->UdpSession.SourcePort ));
342 pRemoteAddress = (struct sockaddr_in *)pAddress;
343 CopyMem ( &pRemoteAddress->sin_addr,
344 &pRxData->UdpSession.SourceAddress.Addr[0],
345 sizeof ( pRemoteAddress->sin_addr ));
346 pRemoteAddress->sin_port = SwapBytes16 ( pRxData->UdpSession.SourcePort );
347 }
348
349 //
350 // Copy the received data
351 //
352 pBuffer = EslSocketCopyFragmentedBuffer ( pRxData->FragmentCount,
353 (EFI_IP4_FRAGMENT_DATA *)&pRxData->FragmentTable[0],
354 BufferLength,
355 pBuffer,
356 &DataBytes );
357
358 //
359 // Determine if the data is being read
360 //
361 if ( *pbConsumePacket ) {
362 //
363 // Display for the bytes consumed
364 //
365 DEBUG (( DEBUG_RX,
366 "0x%08x: Port account for 0x%08x bytes\r\n",
367 pPort,
368 DataBytes ));
369
370 //
371 // Account for any discarded data
372 //
373 *pSkipBytes = pRxData->DataLength - DataBytes;
374 }
375
376 //
377 // Return the data length and the buffer address
378 //
379 *pDataLength = DataBytes;
380 DBG_EXIT_HEX ( pBuffer );
381 return pBuffer;
382 }
383
384
385 /**
386 Get the remote socket address
387
388 This routine returns the address of the remote connection point
389 associated with the SOCK_DGRAM socket.
390
391 This routine is called by ::EslSocketGetPeerAddress to detemine
392 the UDPv4 address and port number associated with the network adapter.
393
394 @param [in] pPort Address of an ::ESL_PORT structure.
395
396 @param [out] pAddress Network address to receive the remote system address
397
398 **/
399 VOID
400 EslUdp4RemoteAddressGet (
401 IN ESL_PORT * pPort,
402 OUT struct sockaddr * pAddress
403 )
404 {
405 struct sockaddr_in * pRemoteAddress;
406 ESL_UDP4_CONTEXT * pUdp4;
407
408 DBG_ENTER ( );
409
410 //
411 // Return the remote address
412 //
413 pUdp4 = &pPort->Context.Udp4;
414 pRemoteAddress = (struct sockaddr_in *)pAddress;
415 pRemoteAddress->sin_family = AF_INET;
416 pRemoteAddress->sin_port = SwapBytes16 ( pUdp4->ConfigData.RemotePort );
417 CopyMem ( &pRemoteAddress->sin_addr,
418 &pUdp4->ConfigData.RemoteAddress.Addr[0],
419 sizeof ( pRemoteAddress->sin_addr ));
420
421 DBG_EXIT ( );
422 }
423
424
425 /**
426 Set the remote address
427
428 This routine sets the remote address in the port.
429
430 This routine is called by ::EslSocketConnect to specify the
431 remote network address.
432
433 @param [in] pPort Address of an ::ESL_PORT structure.
434
435 @param [in] pSockAddr Network address of the remote system.
436
437 @param [in] SockAddrLength Length in bytes of the network address.
438
439 @retval EFI_SUCCESS The operation was successful
440
441 **/
442 EFI_STATUS
443 EslUdp4RemoteAddressSet (
444 IN ESL_PORT * pPort,
445 IN CONST struct sockaddr * pSockAddr,
446 IN socklen_t SockAddrLength
447 )
448 {
449 CONST struct sockaddr_in * pRemoteAddress;
450 ESL_UDP4_CONTEXT * pUdp4;
451 EFI_STATUS Status;
452
453 DBG_ENTER ( );
454
455 //
456 // Set the remote address
457 //
458 pUdp4 = &pPort->Context.Udp4;
459 pRemoteAddress = (struct sockaddr_in *)pSockAddr;
460 pUdp4->ConfigData.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );
461 pUdp4->ConfigData.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
462 pUdp4->ConfigData.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
463 pUdp4->ConfigData.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
464 pUdp4->ConfigData.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );
465 Status = EFI_SUCCESS;
466
467 //
468 // Return the operation status
469 //
470 DBG_EXIT_STATUS ( Status );
471 return Status;
472 }
473
474
475 /**
476 Process the receive completion
477
478 This routine keeps the UDPv4 driver's buffer and queues it in
479 in FIFO order to the data queue. The UDP4 driver's buffer will
480 be returned by either ::EslUdp4Receive or ::EslSocketPortCloseTxDone.
481 See the \ref ReceiveEngine section.
482
483 This routine is called by the UDPv4 driver when data is
484 received.
485
486 @param [in] Event The receive completion event
487
488 @param [in] pIo Address of an ::ESL_IO_MGMT structure
489
490 **/
491 VOID
492 EslUdp4RxComplete (
493 IN EFI_EVENT Event,
494 IN ESL_IO_MGMT * pIo
495 )
496 {
497 size_t LengthInBytes;
498 ESL_PACKET * pPacket;
499 EFI_UDP4_RECEIVE_DATA * pRxData;
500 EFI_STATUS Status;
501
502 DBG_ENTER ( );
503
504 //
505 // Get the operation status.
506 //
507 Status = pIo->Token.Udp4Rx.Status;
508
509 //
510 // Get the packet length
511 //
512 pRxData = pIo->Token.Udp4Rx.Packet.RxData;
513 LengthInBytes = pRxData->DataLength;
514
515 //
516 // +--------------------+ +-----------------------+
517 // | ESL_IO_MGMT | | Data Buffer |
518 // | | | (Driver owned) |
519 // | +---------------+ +-----------------------+
520 // | | Token | ^
521 // | | Rx Event | |
522 // | | | +-----------------------+
523 // | | RxData --> | EFI_UDP4_RECEIVE_DATA |
524 // +----+---------------+ | (Driver owned) |
525 // +-----------------------+
526 // +--------------------+ ^
527 // | ESL_PACKET | .
528 // | | .
529 // | +---------------+ .
530 // | | pRxData --> NULL .......
531 // +----+---------------+
532 //
533 //
534 // Save the data in the packet
535 //
536 pPacket = pIo->pPacket;
537 pPacket->Op.Udp4Rx.pRxData = pRxData;
538
539 //
540 // Complete this request
541 //
542 EslSocketRxComplete ( pIo, Status, LengthInBytes, FALSE );
543 DBG_EXIT ( );
544 }
545
546
547 /**
548 Determine if the socket is configured.
549
550 This routine uses the flag ESL_SOCKET::bConfigured to determine
551 if the network layer's configuration routine has been called.
552 This routine calls the bind and configuration routines if they
553 were not already called. After the port is configured, the
554 \ref ReceiveEngine is started.
555
556 This routine is called by EslSocketIsConfigured to verify
557 that the socket is configured.
558
559 @param [in] pSocket Address of an ::ESL_SOCKET structure
560
561 @retval EFI_SUCCESS - The port is connected
562 @retval EFI_NOT_STARTED - The port is not connected
563
564 **/
565 EFI_STATUS
566 EslUdp4SocketIsConfigured (
567 IN ESL_SOCKET * pSocket
568 )
569 {
570 EFI_UDP4_CONFIG_DATA * pConfigData;
571 ESL_PORT * pPort;
572 ESL_PORT * pNextPort;
573 ESL_UDP4_CONTEXT * pUdp4;
574 EFI_UDP4_PROTOCOL * pUdp4Protocol;
575 EFI_STATUS Status;
576 struct sockaddr_in LocalAddress;
577
578 DBG_ENTER ( );
579
580 //
581 // Assume success
582 //
583 Status = EFI_SUCCESS;
584
585 //
586 // Configure the port if necessary
587 //
588 if ( !pSocket->bConfigured ) {
589 //
590 // Fill in the port list if necessary
591 //
592 if ( NULL == pSocket->pPortList ) {
593 LocalAddress.sin_len = sizeof ( LocalAddress );
594 LocalAddress.sin_family = AF_INET;
595 LocalAddress.sin_addr.s_addr = 0;
596 LocalAddress.sin_port = 0;
597 Status = EslSocketBind ( &pSocket->SocketProtocol,
598 (struct sockaddr *)&LocalAddress,
599 LocalAddress.sin_len,
600 &pSocket->errno );
601 }
602
603 //
604 // Walk the port list
605 //
606 pPort = pSocket->pPortList;
607 while ( NULL != pPort ) {
608 //
609 // Attempt to configure the port
610 //
611 pNextPort = pPort->pLinkSocket;
612 pUdp4 = &pPort->Context.Udp4;
613 pUdp4Protocol = pPort->pProtocol.UDPv4;
614 pConfigData = &pUdp4->ConfigData;
615 DEBUG (( DEBUG_TX,
616 "0x%08x: pPort Configuring for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
617 pPort,
618 pConfigData->StationAddress.Addr[0],
619 pConfigData->StationAddress.Addr[1],
620 pConfigData->StationAddress.Addr[2],
621 pConfigData->StationAddress.Addr[3],
622 pConfigData->StationPort,
623 pConfigData->RemoteAddress.Addr[0],
624 pConfigData->RemoteAddress.Addr[1],
625 pConfigData->RemoteAddress.Addr[2],
626 pConfigData->RemoteAddress.Addr[3],
627 pConfigData->RemotePort ));
628 Status = pUdp4Protocol->Configure ( pUdp4Protocol,
629 pConfigData );
630 if ( !EFI_ERROR ( Status )) {
631 //
632 // Update the configuration data
633 //
634 Status = pUdp4Protocol->GetModeData ( pUdp4Protocol,
635 pConfigData,
636 NULL,
637 NULL,
638 NULL );
639 }
640 if ( EFI_ERROR ( Status )) {
641 DEBUG (( DEBUG_LISTEN,
642 "ERROR - Failed to configure the Udp4 port, Status: %r\r\n",
643 Status ));
644 switch ( Status ) {
645 case EFI_ACCESS_DENIED:
646 pSocket->errno = EACCES;
647 break;
648
649 default:
650 case EFI_DEVICE_ERROR:
651 pSocket->errno = EIO;
652 break;
653
654 case EFI_INVALID_PARAMETER:
655 pSocket->errno = EADDRNOTAVAIL;
656 break;
657
658 case EFI_NO_MAPPING:
659 pSocket->errno = EAFNOSUPPORT;
660 break;
661
662 case EFI_OUT_OF_RESOURCES:
663 pSocket->errno = ENOBUFS;
664 break;
665
666 case EFI_UNSUPPORTED:
667 pSocket->errno = EOPNOTSUPP;
668 break;
669 }
670 }
671 else {
672 DEBUG (( DEBUG_TX,
673 "0x%08x: pPort Configured for %d.%d.%d.%d:%d --> %d.%d.%d.%d:%d\r\n",
674 pPort,
675 pConfigData->StationAddress.Addr[0],
676 pConfigData->StationAddress.Addr[1],
677 pConfigData->StationAddress.Addr[2],
678 pConfigData->StationAddress.Addr[3],
679 pConfigData->StationPort,
680 pConfigData->RemoteAddress.Addr[0],
681 pConfigData->RemoteAddress.Addr[1],
682 pConfigData->RemoteAddress.Addr[2],
683 pConfigData->RemoteAddress.Addr[3],
684 pConfigData->RemotePort ));
685 pPort->bConfigured = TRUE;
686
687 //
688 // Start the first read on the port
689 //
690 EslSocketRxStart ( pPort );
691
692 //
693 // The socket is connected
694 //
695 pSocket->State = SOCKET_STATE_CONNECTED;
696 }
697
698 //
699 // Set the next port
700 //
701 pPort = pNextPort;
702 }
703
704 //
705 // Determine the configuration status
706 //
707 if ( NULL != pSocket->pPortList ) {
708 pSocket->bConfigured = TRUE;
709 }
710 }
711
712 //
713 // Determine the socket configuration status
714 //
715 if ( !EFI_ERROR ( Status )) {
716 Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;
717 }
718
719 //
720 // Return the port connected state.
721 //
722 DBG_EXIT_STATUS ( Status );
723 return Status;
724 }
725
726
727 /**
728 Buffer data for transmission over a network connection.
729
730 This routine buffers data for the transmit engine in the normal
731 data queue. When the \ref TransmitEngine has resources, this
732 routine will start the transmission of the next buffer on the
733 network connection.
734
735 This routine is called by ::EslSocketTransmit to buffer
736 data for transmission. The data is copied into a local buffer
737 freeing the application buffer for reuse upon return. When
738 necessary, this routine starts the transmit engine that
739 performs the data transmission on the network connection. The
740 transmit engine transmits the data a packet at a time over the
741 network connection.
742
743 Transmission errors are returned during the next transmission or
744 during the close operation. Only buffering errors are returned
745 during the current transmission attempt.
746
747 @param [in] pSocket Address of an ::ESL_SOCKET structure
748
749 @param [in] Flags Message control flags
750
751 @param [in] BufferLength Length of the the buffer
752
753 @param [in] pBuffer Address of a buffer to receive the data.
754
755 @param [in] pDataLength Number of received data bytes in the buffer.
756
757 @param [in] pAddress Network address of the remote system address
758
759 @param [in] AddressLength Length of the remote network address structure
760
761 @retval EFI_SUCCESS - Socket data successfully buffered
762
763 **/
764 EFI_STATUS
765 EslUdp4TxBuffer (
766 IN ESL_SOCKET * pSocket,
767 IN int Flags,
768 IN size_t BufferLength,
769 IN CONST UINT8 * pBuffer,
770 OUT size_t * pDataLength,
771 IN const struct sockaddr * pAddress,
772 IN socklen_t AddressLength
773 )
774 {
775 ESL_PACKET * pPacket;
776 ESL_PACKET * pPreviousPacket;
777 ESL_PORT * pPort;
778 const struct sockaddr_in * pRemoteAddress;
779 ESL_UDP4_CONTEXT * pUdp4;
780 size_t * pTxBytes;
781 ESL_UDP4_TX_DATA * pTxData;
782 EFI_STATUS Status;
783 EFI_TPL TplPrevious;
784
785 DBG_ENTER ( );
786
787 //
788 // Assume failure
789 //
790 Status = EFI_UNSUPPORTED;
791 pSocket->errno = ENOTCONN;
792 *pDataLength = 0;
793
794 //
795 // Verify that the socket is connected
796 //
797 if ( SOCKET_STATE_CONNECTED == pSocket->State ) {
798 //
799 // Locate the port
800 //
801 pPort = pSocket->pPortList;
802 if ( NULL != pPort ) {
803 //
804 // Determine the queue head
805 //
806 pUdp4 = &pPort->Context.Udp4;
807 pTxBytes = &pSocket->TxBytes;
808
809 //
810 // Verify that there is enough room to buffer another
811 // transmit operation
812 //
813 if ( pSocket->MaxTxBuf > *pTxBytes ) {
814 //
815 // Attempt to allocate the packet
816 //
817 Status = EslSocketPacketAllocate ( &pPacket,
818 sizeof ( pPacket->Op.Udp4Tx )
819 - sizeof ( pPacket->Op.Udp4Tx.Buffer )
820 + BufferLength,
821 0,
822 DEBUG_TX );
823 if ( !EFI_ERROR ( Status )) {
824 //
825 // Initialize the transmit operation
826 //
827 pTxData = &pPacket->Op.Udp4Tx;
828 pTxData->TxData.GatewayAddress = NULL;
829 pTxData->TxData.UdpSessionData = NULL;
830 pTxData->TxData.DataLength = (UINT32) BufferLength;
831 pTxData->TxData.FragmentCount = 1;
832 pTxData->TxData.FragmentTable[0].FragmentLength = (UINT32) BufferLength;
833 pTxData->TxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Udp4Tx.Buffer[0];
834 pTxData->RetransmitCount = 0;
835
836 //
837 // Set the remote system address if necessary
838 //
839 pTxData->TxData.UdpSessionData = NULL;
840 if ( NULL != pAddress ) {
841 pRemoteAddress = (const struct sockaddr_in *)pAddress;
842 pTxData->Session.SourceAddress.Addr[0] = pUdp4->ConfigData.StationAddress.Addr[0];
843 pTxData->Session.SourceAddress.Addr[1] = pUdp4->ConfigData.StationAddress.Addr[1];
844 pTxData->Session.SourceAddress.Addr[2] = pUdp4->ConfigData.StationAddress.Addr[2];
845 pTxData->Session.SourceAddress.Addr[3] = pUdp4->ConfigData.StationAddress.Addr[3];
846 pTxData->Session.SourcePort = 0;
847 pTxData->Session.DestinationAddress.Addr[0] = (UINT8)pRemoteAddress->sin_addr.s_addr;
848 pTxData->Session.DestinationAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );
849 pTxData->Session.DestinationAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );
850 pTxData->Session.DestinationAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );
851 pTxData->Session.DestinationPort = SwapBytes16 ( pRemoteAddress->sin_port );
852
853 //
854 // Use the remote system address when sending this packet
855 //
856 pTxData->TxData.UdpSessionData = &pTxData->Session;
857 }
858
859 //
860 // Copy the data into the buffer
861 //
862 CopyMem ( &pPacket->Op.Udp4Tx.Buffer[0],
863 pBuffer,
864 BufferLength );
865
866 //
867 // Synchronize with the socket layer
868 //
869 RAISE_TPL ( TplPrevious, TPL_SOCKETS );
870
871 //
872 // Stop transmission after an error
873 //
874 if ( !EFI_ERROR ( pSocket->TxError )) {
875 //
876 // Display the request
877 //
878 DEBUG (( DEBUG_TX,
879 "Send %d %s bytes from 0x%08x\r\n",
880 BufferLength,
881 pBuffer ));
882
883 //
884 // Queue the data for transmission
885 //
886 pPacket->pNext = NULL;
887 pPreviousPacket = pSocket->pTxPacketListTail;
888 if ( NULL == pPreviousPacket ) {
889 pSocket->pTxPacketListHead = pPacket;
890 }
891 else {
892 pPreviousPacket->pNext = pPacket;
893 }
894 pSocket->pTxPacketListTail = pPacket;
895 DEBUG (( DEBUG_TX,
896 "0x%08x: Packet on transmit list\r\n",
897 pPacket ));
898
899 //
900 // Account for the buffered data
901 //
902 *pTxBytes += BufferLength;
903 *pDataLength = BufferLength;
904
905 //
906 // Start the transmit engine if it is idle
907 //
908 if ( NULL != pPort->pTxFree ) {
909 EslSocketTxStart ( pPort,
910 &pSocket->pTxPacketListHead,
911 &pSocket->pTxPacketListTail,
912 &pPort->pTxActive,
913 &pPort->pTxFree );
914 }
915 }
916 else {
917 //
918 // Previous transmit error
919 // Stop transmission
920 //
921 Status = pSocket->TxError;
922 pSocket->errno = EIO;
923
924 //
925 // Free the packet
926 //
927 EslSocketPacketFree ( pPacket, DEBUG_TX );
928 }
929
930 //
931 // Release the socket layer synchronization
932 //
933 RESTORE_TPL ( TplPrevious );
934 }
935 else {
936 //
937 // Packet allocation failed
938 //
939 pSocket->errno = ENOMEM;
940 }
941 }
942 else {
943 //
944 // Not enough buffer space available
945 //
946 pSocket->errno = EAGAIN;
947 Status = EFI_NOT_READY;
948 }
949 }
950 }
951
952 //
953 // Return the operation status
954 //
955 DBG_EXIT_STATUS ( Status );
956 return Status;
957 }
958
959
960 /**
961 Process the transmit completion
962
963 This routine use ::EslSocketTxComplete to perform the transmit
964 completion processing for data packets.
965
966 This routine is called by the UDPv4 network layer when a data
967 transmit request completes.
968
969 @param [in] Event The normal transmit completion event
970
971 @param [in] pIo Address of an ::ESL_IO_MGMT structure
972
973 **/
974 VOID
975 EslUdp4TxComplete (
976 IN EFI_EVENT Event,
977 IN ESL_IO_MGMT * pIo
978 )
979 {
980 UINT32 LengthInBytes;
981 ESL_PORT * pPort;
982 ESL_PACKET * pPacket;
983 ESL_SOCKET * pSocket;
984 EFI_STATUS Status;
985
986 DBG_ENTER ( );
987
988 //
989 // Locate the active transmit packet
990 //
991 pPacket = pIo->pPacket;
992 pPort = pIo->pPort;
993 pSocket = pPort->pSocket;
994
995 //
996 // Get the transmit length and status
997 //
998 LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
999 pSocket->TxBytes -= LengthInBytes;
1000 Status = pIo->Token.Udp4Tx.Status;
1001
1002 //
1003 // Complete the transmit operation
1004 //
1005 EslSocketTxComplete ( pIo,
1006 LengthInBytes,
1007 Status,
1008 "UDP ",
1009 &pSocket->pTxPacketListHead,
1010 &pSocket->pTxPacketListTail,
1011 &pPort->pTxActive,
1012 &pPort->pTxFree );
1013 DBG_EXIT ( );
1014 }
1015
1016
1017 /**
1018 Interface between the socket layer and the network specific
1019 code that supports SOCK_DGRAM sockets over UDPv4.
1020 **/
1021 CONST ESL_PROTOCOL_API cEslUdp4Api = {
1022 "UDPv4",
1023 IPPROTO_UDP,
1024 OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
1025 OFFSET_OF ( ESL_LAYER, pUdp4List ),
1026 OFFSET_OF ( struct sockaddr_in, sin_zero ),
1027 sizeof ( struct sockaddr_in ),
1028 AF_INET,
1029 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1030 sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1031 OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
1032 FALSE,
1033 EADDRINUSE,
1034 NULL, // Accept
1035 NULL, // ConnectPoll
1036 NULL, // ConnectStart
1037 EslUdp4SocketIsConfigured,
1038 EslUdp4LocalAddressGet,
1039 EslUdp4LocalAddressSet,
1040 NULL, // Listen
1041 NULL, // OptionGet
1042 NULL, // OptionSet
1043 EslUdp4PacketFree,
1044 EslUdp4PortAllocate,
1045 NULL, // PortClose,
1046 NULL, // PortCloseOp
1047 TRUE,
1048 EslUdp4Receive,
1049 EslUdp4RemoteAddressGet,
1050 EslUdp4RemoteAddressSet,
1051 EslUdp4RxComplete,
1052 NULL, // RxStart
1053 EslUdp4TxBuffer,
1054 EslUdp4TxComplete,
1055 NULL // TxOobComplete
1056 };