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