• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Implement the UDP4 driver support for the socket layer.
3 
4   Copyright (c) 2011 - 2015, 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
EslUdp4LocalAddressGet(IN ESL_PORT * pPort,OUT struct sockaddr * pSockAddr)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
EslUdp4LocalAddressSet(IN ESL_PORT * pPort,IN CONST struct sockaddr * pSockAddr,IN BOOLEAN bBindTest)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
EslUdp4PacketFree(IN ESL_PACKET * pPacket,IN OUT size_t * pRxBytes)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
EslUdp4PortAllocate(IN ESL_PORT * pPort,IN UINTN DebugFlags)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 = FALSE;
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 *
EslUdp4Receive(IN ESL_PORT * pPort,IN ESL_PACKET * pPacket,IN BOOLEAN * pbConsumePacket,IN size_t BufferLength,IN UINT8 * pBuffer,OUT size_t * pDataLength,OUT struct sockaddr * pAddress,OUT size_t * pSkipBytes)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
EslUdp4RemoteAddressGet(IN ESL_PORT * pPort,OUT struct sockaddr * pAddress)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
EslUdp4RemoteAddressSet(IN ESL_PORT * pPort,IN CONST struct sockaddr * pSockAddr,IN socklen_t SockAddrLength)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
EslUdp4RxComplete(IN EFI_EVENT Event,IN ESL_IO_MGMT * pIo)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
EslUdp4SocketIsConfigured(IN ESL_SOCKET * pSocket)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
EslUdp4TxBuffer(IN ESL_SOCKET * pSocket,IN int Flags,IN size_t BufferLength,IN CONST UINT8 * pBuffer,OUT size_t * pDataLength,IN const struct sockaddr * pAddress,IN socklen_t AddressLength)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     //  Verify that there is enough room to buffer another
798     //  transmit operation
799     //
800     pTxBytes = &pSocket->TxBytes;
801     if ( pSocket->MaxTxBuf > *pTxBytes ) {
802       //
803       //  Locate the port
804       //
805       pPort = pSocket->pPortList;
806       while ( NULL != pPort ) {
807         //
808         //  Determine the queue head
809         //
810         pUdp4 = &pPort->Context.Udp4;
811 
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           //  Display the request
871           //
872           DEBUG (( DEBUG_TX,
873                     "Send %d bytes from 0x%08x to %d.%d.%d.%d:%d\r\n",
874                     BufferLength,
875                     pBuffer,
876                     pTxData->Session.DestinationAddress.Addr[0],
877                     pTxData->Session.DestinationAddress.Addr[1],
878                     pTxData->Session.DestinationAddress.Addr[2],
879                     pTxData->Session.DestinationAddress.Addr[3],
880                     pTxData->Session.DestinationPort ));
881 
882           //
883           //  Queue the data for transmission
884           //
885           pPacket->pNext = NULL;
886           pPreviousPacket = pSocket->pTxPacketListTail;
887           if ( NULL == pPreviousPacket ) {
888             pSocket->pTxPacketListHead = pPacket;
889           }
890           else {
891             pPreviousPacket->pNext = pPacket;
892           }
893           pSocket->pTxPacketListTail = pPacket;
894           DEBUG (( DEBUG_TX,
895                     "0x%08x: Packet on transmit list\r\n",
896                     pPacket ));
897 
898           //
899           //  Account for the buffered data
900           //
901           *pTxBytes += BufferLength;
902           *pDataLength = BufferLength;
903 
904           //
905           //  Start the transmit engine if it is idle
906           //
907           if ( NULL != pPort->pTxFree ) {
908             pPacket = pSocket->pTxPacketListHead;
909             EslSocketTxStart ( pPort,
910                                &pSocket->pTxPacketListHead,
911                                &pSocket->pTxPacketListTail,
912                                &pPort->pTxActive,
913                                &pPort->pTxFree );
914 
915             //
916             //  Ignore any transmit error
917             //
918             if ( EFI_ERROR ( pSocket->TxError )) {
919               DEBUG (( DEBUG_TX,
920                        "0x%08x: Transmit error, Packet: 0x%08x, Status: %r\r\n",
921                        pPort,
922                        pPacket,
923                        pSocket->TxError ));
924             }
925             pSocket->TxError = EFI_SUCCESS;
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           break;
939         }
940 
941         //
942         //  Set the next port
943         //
944         pPort = pPort->pLinkSocket;
945       }
946     }
947     else {
948       //
949       //  Not enough buffer space available
950       //
951       pSocket->errno = EAGAIN;
952       Status = EFI_NOT_READY;
953     }
954   }
955 
956   //
957   //  Return the operation status
958   //
959   DBG_EXIT_STATUS ( Status );
960   return Status;
961 }
962 
963 
964 /**
965   Process the transmit completion
966 
967   This routine use ::EslSocketTxComplete to perform the transmit
968   completion processing for data packets.
969 
970   This routine is called by the UDPv4 network layer when a data
971   transmit request completes.
972 
973   @param [in] Event     The normal transmit completion event
974 
975   @param [in] pIo       Address of an ::ESL_IO_MGMT structure
976 
977 **/
978 VOID
EslUdp4TxComplete(IN EFI_EVENT Event,IN ESL_IO_MGMT * pIo)979 EslUdp4TxComplete (
980   IN EFI_EVENT Event,
981   IN ESL_IO_MGMT * pIo
982   )
983 {
984   UINT32 LengthInBytes;
985   ESL_PORT * pPort;
986   ESL_PACKET * pPacket;
987   ESL_SOCKET * pSocket;
988   EFI_STATUS Status;
989 
990   DBG_ENTER ( );
991 
992   //
993   //  Locate the active transmit packet
994   //
995   pPacket = pIo->pPacket;
996   pPort = pIo->pPort;
997   pSocket = pPort->pSocket;
998 
999   //
1000   //  Get the transmit length and status
1001   //
1002   LengthInBytes = pPacket->Op.Udp4Tx.TxData.DataLength;
1003   pSocket->TxBytes -= LengthInBytes;
1004   Status = pIo->Token.Udp4Tx.Status;
1005 
1006   //
1007   //  Ignore the transmit error
1008   //
1009   if ( EFI_ERROR ( Status )) {
1010     DEBUG (( DEBUG_TX,
1011              "0x%08x: Transmit completion error, Packet: 0x%08x, Status: %r\r\n",
1012              pPort,
1013              pPacket,
1014              Status ));
1015     Status = EFI_SUCCESS;
1016   }
1017 
1018   //
1019   //  Complete the transmit operation
1020   //
1021   EslSocketTxComplete ( pIo,
1022                         LengthInBytes,
1023                         Status,
1024                         "UDP ",
1025                         &pSocket->pTxPacketListHead,
1026                         &pSocket->pTxPacketListTail,
1027                         &pPort->pTxActive,
1028                         &pPort->pTxFree );
1029   DBG_EXIT ( );
1030 }
1031 
1032 
1033 /**
1034   Verify the adapter's IP address
1035 
1036   This support routine is called by EslSocketBindTest.
1037 
1038   @param [in] pPort       Address of an ::ESL_PORT structure.
1039   @param [in] pConfigData Address of the configuration data
1040 
1041   @retval EFI_SUCCESS - The IP address is valid
1042   @retval EFI_NOT_STARTED - The IP address is invalid
1043 
1044  **/
1045 EFI_STATUS
EslUdp4VerifyLocalIpAddress(IN ESL_PORT * pPort,IN EFI_UDP4_CONFIG_DATA * pConfigData)1046 EslUdp4VerifyLocalIpAddress (
1047   IN ESL_PORT * pPort,
1048   IN EFI_UDP4_CONFIG_DATA * pConfigData
1049   )
1050 {
1051   UINTN DataSize;
1052   EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo;
1053   EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol;
1054   ESL_SERVICE * pService;
1055   EFI_STATUS Status;
1056 
1057   DBG_ENTER ( );
1058 
1059   //
1060   //  Use break instead of goto
1061   //
1062   pIfInfo = NULL;
1063   for ( ; ; ) {
1064     //
1065     //  Determine if the IP address is specified
1066     //
1067     DEBUG (( DEBUG_BIND,
1068               "UseDefaultAddress: %s\r\n",
1069               pConfigData->UseDefaultAddress ? L"TRUE" : L"FALSE" ));
1070     DEBUG (( DEBUG_BIND,
1071               "Requested IP address: %d.%d.%d.%d\r\n",
1072               pConfigData->StationAddress.Addr [ 0 ],
1073               pConfigData->StationAddress.Addr [ 1 ],
1074               pConfigData->StationAddress.Addr [ 2 ],
1075               pConfigData->StationAddress.Addr [ 3 ]));
1076     if ( pConfigData->UseDefaultAddress
1077       || (( 0 == pConfigData->StationAddress.Addr [ 0 ])
1078       && ( 0 == pConfigData->StationAddress.Addr [ 1 ])
1079       && ( 0 == pConfigData->StationAddress.Addr [ 2 ])
1080       && ( 0 == pConfigData->StationAddress.Addr [ 3 ])))
1081     {
1082       Status = EFI_SUCCESS;
1083       break;
1084     }
1085 
1086     //
1087     //  Open the configuration protocol
1088     //
1089     pService = pPort->pService;
1090     Status = gBS->OpenProtocol (
1091                     pService->Controller,
1092                     &gEfiIp4Config2ProtocolGuid,
1093                     (VOID **)&pIpConfig2Protocol,
1094                     NULL,
1095                     NULL,
1096                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
1097                     );
1098     if ( EFI_ERROR ( Status )) {
1099       DEBUG (( DEBUG_ERROR,
1100                 "ERROR - IP Configuration Protocol not available, Status: %r\r\n",
1101                 Status ));
1102       break;
1103     }
1104 
1105     //
1106     //  Get the interface information size
1107     //
1108     DataSize = 0;
1109     Status = pIpConfig2Protocol->GetData (
1110                                    pIpConfig2Protocol,
1111                                    Ip4Config2DataTypeInterfaceInfo,
1112                                    &DataSize,
1113                                    NULL
1114                                    );
1115     if ( EFI_BUFFER_TOO_SMALL != Status ) {
1116       DEBUG (( DEBUG_ERROR,
1117                 "ERROR - Failed to get the interface information size, Status: %r\r\n",
1118                 Status ));
1119       break;
1120     }
1121 
1122     //
1123     //  Allocate the interface information buffer
1124     //
1125     pIfInfo = AllocatePool ( DataSize );
1126     if ( NULL == pIfInfo ) {
1127       DEBUG (( DEBUG_ERROR,
1128                 "ERROR - Not enough memory to allocate the interface information buffer!\r\n" ));
1129       Status = EFI_OUT_OF_RESOURCES;
1130       break;
1131     }
1132 
1133     //
1134     // Get the interface info.
1135     //
1136     Status = pIpConfig2Protocol->GetData (
1137                                   pIpConfig2Protocol,
1138                                   Ip4Config2DataTypeInterfaceInfo,
1139                                   &DataSize,
1140                                   pIfInfo
1141                                   );
1142     if ( EFI_ERROR ( Status )) {
1143       DEBUG (( DEBUG_ERROR,
1144                 "ERROR - Failed to return the interface info, Status: %r\r\n",
1145                 Status ));
1146       break;
1147     }
1148 
1149     //
1150     //  Display the current configuration
1151     //
1152     DEBUG (( DEBUG_BIND,
1153               "Actual adapter IP address: %d.%d.%d.%d\r\n",
1154               pIfInfo->StationAddress.Addr [ 0 ],
1155               pIfInfo->StationAddress.Addr [ 1 ],
1156               pIfInfo->StationAddress.Addr [ 2 ],
1157               pIfInfo->StationAddress.Addr [ 3 ]));
1158 
1159     //
1160     //  Assume the port is not configured
1161     //
1162     Status = EFI_SUCCESS;
1163     if (( pConfigData->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ])
1164       && ( pConfigData->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ])
1165       && ( pConfigData->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ])
1166       && ( pConfigData->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) {
1167       break;
1168     }
1169 
1170     //
1171     //  The IP address did not match
1172     //
1173     Status = EFI_NOT_STARTED;
1174     break;
1175   }
1176 
1177   //
1178   //  Free the buffer if necessary
1179   //
1180   if ( NULL != pIfInfo ) {
1181     FreePool ( pIfInfo );
1182   }
1183 
1184   //
1185   //  Return the IP address status
1186   //
1187   DBG_EXIT_STATUS ( Status );
1188   return Status;
1189 }
1190 
1191 
1192 /**
1193   Interface between the socket layer and the network specific
1194   code that supports SOCK_DGRAM sockets over UDPv4.
1195 **/
1196 CONST ESL_PROTOCOL_API cEslUdp4Api = {
1197   "UDPv4",
1198   IPPROTO_UDP,
1199   OFFSET_OF ( ESL_PORT, Context.Udp4.ConfigData ),
1200   OFFSET_OF ( ESL_LAYER, pUdp4List ),
1201   OFFSET_OF ( struct sockaddr_in, sin_zero ),
1202   sizeof ( struct sockaddr_in ),
1203   AF_INET,
1204   sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1205   sizeof (((ESL_PACKET *)0 )->Op.Udp4Rx ),
1206   OFFSET_OF ( ESL_IO_MGMT, Token.Udp4Rx.Packet.RxData ),
1207   FALSE,
1208   EADDRINUSE,
1209   NULL,   //  Accept
1210   NULL,   //  ConnectPoll
1211   NULL,   //  ConnectStart
1212   EslUdp4SocketIsConfigured,
1213   EslUdp4LocalAddressGet,
1214   EslUdp4LocalAddressSet,
1215   NULL,   //  Listen
1216   NULL,   //  OptionGet
1217   NULL,   //  OptionSet
1218   EslUdp4PacketFree,
1219   EslUdp4PortAllocate,
1220   NULL,   //  PortClose,
1221   NULL,   //  PortCloseOp
1222   TRUE,
1223   EslUdp4Receive,
1224   EslUdp4RemoteAddressGet,
1225   EslUdp4RemoteAddressSet,
1226   EslUdp4RxComplete,
1227   NULL,   //  RxStart
1228   EslUdp4TxBuffer,
1229   EslUdp4TxComplete,
1230   NULL,   //  TxOobComplete
1231   (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslUdp4VerifyLocalIpAddress
1232 };
1233