diff options
Diffstat (limited to 'AppPkg/Applications/Sockets')
44 files changed, 15399 insertions, 0 deletions
diff --git a/AppPkg/Applications/Sockets/DataSink/DataSink.c b/AppPkg/Applications/Sockets/DataSink/DataSink.c new file mode 100644 index 0000000000..911cf36940 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSink/DataSink.c @@ -0,0 +1,1029 @@ +/** @file
+ Data source for network testing.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <netinet/in.h>
+
+#include <sys/EfiSysCall.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+
+#define MAX_CONNECTIONS ( 1 + 16 ) ///< Maximum number of client connections
+#define RANGE_SWITCH 2048 ///< Switch display ranges
+#define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates
+#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average
+
+#define TPL_DATASINK TPL_CALLBACK ///< Synchronization TPL
+
+#define PACKET_SIZE 1448 ///< Size of data packets
+#define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes
+
+typedef struct _DT_PORT {
+ UINT64 BytesAverage;
+ UINT64 BytesPrevious;
+ UINT64 BytesTotal;
+ struct sockaddr_in RemoteAddress;
+ UINT64 Samples;
+} DT_PORT;
+
+volatile BOOLEAN bTick;
+BOOLEAN bTimerRunning;
+struct sockaddr_in LocalAddress;
+EFI_EVENT pTimer;
+int ListenSocket;
+UINT8 Buffer [ DATA_BUFFER_SIZE ];
+struct pollfd PollFd [ MAX_CONNECTIONS ];
+DT_PORT Port [ MAX_CONNECTIONS ];
+nfds_t MaxPort;
+
+
+//
+// Forward routine declarations
+//
+EFI_STATUS TimerStart ( UINTN Milliseconds );
+
+
+/**
+ Check for control C entered at console
+
+ @retval EFI_SUCCESS Control C not entered
+ @retval EFI_ABORTED Control C entered
+**/
+EFI_STATUS
+ControlCCheck (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume no user intervention
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Display user stop request
+ //
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "User stop request!\r\n" ));
+ }
+
+ //
+ // Return the check status
+ //
+ return Status;
+}
+
+
+/**
+ Accept a socket connection
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval EFI_NOT_STARTED Error with the listen socket
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketAccept (
+ )
+{
+ INT32 SocketStatus;
+ EFI_STATUS Status;
+ INTN Index;
+
+ //
+ // Assume failure
+ //
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // Bind to the local address
+ //
+ SocketStatus = bind ( ListenSocket,
+ (struct sockaddr *) &LocalAddress,
+ LocalAddress.sin_len );
+ if ( 0 == SocketStatus ) {
+ //
+ // Start listening on the local socket
+ //
+ SocketStatus = listen ( ListenSocket, 5 );
+ if ( 0 == SocketStatus ) {
+ //
+ // Local socket in the listen state
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Allocate a port
+ //
+ Index = MaxPort++;
+ PollFd [ Index ].fd = ListenSocket;
+ PollFd [ Index ].events = POLLRDNORM | POLLHUP;
+ PollFd [ Index ].revents = 0;
+ Port [ Index ].BytesAverage = 0;
+ Port [ Index ].BytesPrevious = 0;
+ Port [ Index ].BytesTotal = 0;
+ Port [ Index ].Samples = 0;
+ Port [ Index ].RemoteAddress.sin_len = 0;
+ Port [ Index ].RemoteAddress.sin_family = 0;
+ Port [ Index ].RemoteAddress.sin_port = 0;
+ Port [ Index ].RemoteAddress.sin_addr.s_addr= 0;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Close the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketClose (
+ )
+{
+ INT32 CloseStatus;
+ EFI_STATUS Status;
+
+ //
+ // Determine if the socket is open
+ //
+ Status = EFI_DEVICE_ERROR;
+ if ( -1 != ListenSocket ) {
+ //
+ // Attempt to close the socket
+ //
+ CloseStatus = close ( ListenSocket );
+ if ( 0 == CloseStatus ) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket closed\r\n",
+ ListenSocket ));
+ ListenSocket = -1;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR: Failed to close socket, errno: %d\r\n",
+ errno ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Create the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketNew (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Get the port number
+ //
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));
+ LocalAddress.sin_len = sizeof ( LocalAddress );
+ LocalAddress.sin_family = AF_INET;
+ LocalAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));
+
+ //
+ // Loop creating the socket
+ //
+ DEBUG (( DEBUG_INFO,
+ "Creating the socket\r\n" ));
+
+ //
+ // Check for user stop request
+ //
+ Status = ControlCCheck ( );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Attempt to create the socket
+ //
+ ListenSocket = socket ( AF_INET,
+ SOCK_STREAM,
+ IPPROTO_TCP );
+ if ( -1 != ListenSocket ) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket created\r\n",
+ ListenSocket ));
+ }
+ else
+ {
+ Status = EFI_NOT_STARTED;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Poll the socket for more work
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval EFI_NOT_STARTED Listen socket error
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketPoll (
+ )
+{
+ BOOLEAN bRemoveSocket;
+ BOOLEAN bListenError;
+ size_t BytesReceived;
+ int CloseStatus;
+ nfds_t Entry;
+ INTN EntryPrevious;
+ int FdCount;
+ nfds_t Index;
+ socklen_t LengthInBytes;
+ struct sockaddr_in RemoteAddress;
+ int Socket;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ //
+ // Check for control-C
+ //
+ bListenError = FALSE;
+ Status = ControlCCheck ( );
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Poll the sockets
+ //
+ FdCount = poll ( &PollFd[0],
+ MaxPort,
+ 0 );
+ if ( -1 == FdCount ) {
+ //
+ // Poll error
+ //
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Poll error, errno: %d\r\n",
+ errno ));
+ Status = EFI_DEVICE_ERROR;
+ }
+ else {
+ //
+ // Process the poll output
+ //
+ Index = 0;
+ while ( FdCount ) {
+ bRemoveSocket = FALSE;
+
+ //
+ // Account for this descriptor
+ //
+ if ( 0 != PollFd [ Index ].revents ) {
+ FdCount -= 1;
+ }
+
+ //
+ // Check for a broken connection
+ //
+ if ( 0 != ( PollFd [ Index ].revents & POLLHUP )) {
+ bRemoveSocket = TRUE;
+ if ( ListenSocket == PollFd [ Index ].fd ) {
+ bListenError = TRUE;
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Network closed on listen socket, errno: %d\r\n",
+ errno ));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Network closed on socket %d.%d.%d.%d:%d, errno: %d\r\n",
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port ),
+ errno ));
+
+ //
+ // Close the socket
+ //
+ CloseStatus = close ( PollFd [ Index ].fd );
+ if ( 0 == CloseStatus ) {
+ bRemoveSocket = TRUE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
+ PollFd [ Index ].fd,
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
+ PollFd [ Index ].fd,
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port ),
+ errno ));
+ }
+ }
+ }
+
+ //
+ // Check for a connection or read data
+ //
+ if ( 0 != ( PollFd [ Index ].revents & POLLRDNORM )) {
+ //
+ // Check for a connection
+ //
+ if ( ListenSocket == PollFd [ Index ].fd ) {
+ //
+ // Another client connection was received
+ //
+ LengthInBytes = sizeof ( RemoteAddress );
+ Socket = accept ( ListenSocket,
+ (struct sockaddr *) &RemoteAddress,
+ &LengthInBytes );
+ if ( -1 == Socket ) {
+ //
+ // Listen socket error
+ //
+ bListenError = TRUE;
+ bRemoveSocket = TRUE;
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Listen socket failure, errno: %d\r\n",
+ errno ));
+ }
+ else {
+ //
+ // Determine if there is room for this connection
+ //
+ if (( MAX_CONNECTIONS <= MaxPort )
+ || ((( MAX_CONNECTIONS - 1 ) == MaxPort ) && ( -1 == ListenSocket ))) {
+ //
+ // Display the connection
+ //
+ Print ( L"Rejecting connection to remote system %d.%d.%d.%d:%d\r\n",
+ RemoteAddress.sin_addr.s_addr & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( RemoteAddress.sin_port ));
+
+ //
+ // No room for this connection
+ // Close the connection
+ //
+ CloseStatus = close ( Socket );
+ if ( 0 == CloseStatus ) {
+ bRemoveSocket = TRUE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
+ PollFd [ Index ].fd,
+ RemoteAddress.sin_addr.s_addr & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( RemoteAddress.sin_port )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close socket 0x%08x, errno: %d\r\n",
+ PollFd [ Index ].fd,
+ errno ));
+ }
+
+ //
+ // Keep the application running
+ // No issue with the listen socket
+ //
+ Status = EFI_SUCCESS;
+ }
+ else
+ {
+ //
+ // Display the connection
+ //
+ Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
+ RemoteAddress.sin_addr.s_addr & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( RemoteAddress.sin_port ));
+
+ //
+ // Allocate the client connection
+ //
+ Index = MaxPort++;
+ Port [ Index ].BytesAverage = 0;
+ Port [ Index ].BytesPrevious = 0;
+ Port [ Index ].BytesTotal = 0;
+ Port [ Index ].Samples = 0;
+ Port [ Index ].RemoteAddress.sin_len = RemoteAddress.sin_len;
+ Port [ Index ].RemoteAddress.sin_family = RemoteAddress.sin_family;
+ Port [ Index ].RemoteAddress.sin_port = RemoteAddress.sin_port;
+ Port [ Index ].RemoteAddress.sin_addr = RemoteAddress.sin_addr;
+ PollFd [ Index ].fd = Socket;
+ PollFd [ Index ].events = POLLRDNORM | POLLHUP;
+ PollFd [ Index ].revents = 0;
+ }
+ }
+ }
+ else {
+ //
+ // Data received
+ //
+ BytesReceived = read ( PollFd [ Index ].fd,
+ &Buffer,
+ sizeof ( Buffer ));
+ if ( 0 < BytesReceived ) {
+ //
+ // Display the amount of data received
+ //
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket received 0x%08x bytes from %d.%d.%d.%d:%d\r\n",
+ PollFd [ Index ].fd,
+ BytesReceived,
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port )));
+
+ //
+ // Synchronize with the TimerCallback routine
+ //
+ TplPrevious = gBS->RaiseTPL ( TPL_DATASINK );
+
+ //
+ // Account for the data received
+ //
+ Port [ Index ].BytesTotal += BytesReceived;
+
+ //
+ // Release the synchronization with the TimerCallback routine
+ //
+ gBS->RestoreTPL ( TplPrevious );
+ }
+ else if ( -1 == BytesReceived ) {
+ //
+ // Close the socket
+ //
+ DEBUG (( DEBUG_INFO,
+ "ERROR - Receive failure for %d.%d.%d.%d:%d, errno: %d\r\n",
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port ),
+ errno ));
+ CloseStatus = close ( PollFd [ Index ].fd );
+ if ( 0 == CloseStatus ) {
+ bRemoveSocket = TRUE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket closed for %d.%d.%d.%d:%d\r\n",
+ PollFd [ Index ].fd,
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port )));
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close socket 0x%08x for %d.%d.%d.%d:%d, errno: %d\r\n",
+ PollFd [ Index ].fd,
+ Port [ Index ].RemoteAddress.sin_addr.s_addr & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff,
+ ( Port [ Index ].RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff,
+ htons ( Port [ Index ].RemoteAddress.sin_port ),
+ errno ));
+ }
+ }
+
+ //
+ // Keep the application running
+ // No issue with the listen socket
+ //
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Remove the socket if necessary
+ //
+ if ( bRemoveSocket ) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket removed from polling\r\n",
+ PollFd [ Index ].fd ));
+ MaxPort -= 1;
+ for ( Entry = Index + 1; MaxPort >= Entry; Entry++ ) {
+ EntryPrevious = Entry;
+ Port [ EntryPrevious ].BytesAverage = Port [ Entry ].BytesAverage;
+ Port [ EntryPrevious ].BytesPrevious = Port [ Entry ].BytesPrevious;
+ Port [ EntryPrevious ].BytesTotal = Port [ Entry ].BytesTotal;
+ Port [ EntryPrevious ].RemoteAddress.sin_len = Port [ Entry ].RemoteAddress.sin_len;
+ Port [ EntryPrevious ].RemoteAddress.sin_family = Port [ Entry ].RemoteAddress.sin_family;
+ Port [ EntryPrevious ].RemoteAddress.sin_port = Port [ Entry ].RemoteAddress.sin_port;
+ Port [ EntryPrevious ].RemoteAddress.sin_addr.s_addr = Port [ Entry ].RemoteAddress.sin_addr.s_addr;
+ Port [ EntryPrevious ].Samples = Port [ Entry ].Samples;
+ PollFd [ EntryPrevious ].events = PollFd [ Entry ].events;
+ PollFd [ EntryPrevious ].fd = PollFd [ Entry ].fd;
+ PollFd [ EntryPrevious ].revents = PollFd [ Entry ].revents;
+ }
+ PollFd [ MaxPort ].fd = -1;
+ Index -= 1;
+ }
+
+ //
+ // Account for this socket
+ //
+ Index += 1;
+ }
+ }
+ }
+
+ //
+ // Return the listen failure if necessary
+ //
+ if (( !EFI_ERROR ( Status )) && bListenError ) {
+ Status = EFI_NOT_STARTED;
+ }
+
+ //
+ // Return the poll status
+ //
+ return Status;
+}
+
+
+/**
+ Handle the timer callback
+
+ @param [in] Event Event that caused this callback
+ @param [in] pContext Context for this routine
+**/
+VOID
+TimerCallback (
+ IN EFI_EVENT Event,
+ IN VOID * pContext
+ )
+{
+ UINT64 Average;
+ UINT64 BytesReceived;
+ UINT32 Delta;
+ UINT64 DeltaBytes;
+ nfds_t Index;
+
+ //
+ // Notify the other code of the timer tick
+ //
+ bTick = TRUE;
+
+ //
+ // Walk the list of ports
+ //
+ for ( Index = 0; MaxPort > Index; Index++ ) {
+ //
+ // Determine if any data was received
+ //
+ BytesReceived = Port [ Index ].BytesTotal;
+ if (( ListenSocket != PollFd [ Index ].fd )
+ && ( 0 != BytesReceived )) {
+ //
+ // Update the average bytes per second
+ //
+ DeltaBytes = Port [ Index ].BytesAverage >> AVERAGE_SHIFT_COUNT;
+ Port [ Index ].BytesAverage -= DeltaBytes;
+ DeltaBytes = BytesReceived - Port [ Index ].BytesPrevious;
+ Port [ Index ].BytesPrevious = BytesReceived;
+ Port [ Index ].BytesAverage += DeltaBytes;
+
+ //
+ // Separate the samples
+ //
+ if (( 2 << AVERAGE_SHIFT_COUNT ) == Port [ Index ].Samples ) {
+ Print ( L"---------- Stable average ----------\r\n" );
+ }
+ Port [ Index ].Samples += 1;
+
+ //
+ // Display the data rate
+ //
+ Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );
+ Average = Port [ Index ].BytesAverage >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",
+ Delta,
+ Average );
+ }
+ else {
+ Average >>= 10;
+ Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Create the timer
+
+ @retval EFI_SUCCESS The timer was successfully created
+ @retval Other Timer initialization failed
+**/
+EFI_STATUS
+TimerCreate (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Create the timer
+ //
+ Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_DATASINK,
+ TimerCallback,
+ NULL,
+ &pTimer );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to allocate the timer event, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer created\r\n",
+ pTimer ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Stop the timer
+
+ @retval EFI_SUCCESS The timer was stopped successfully
+ @retval Other The timer failed to stop
+**/
+EFI_STATUS
+TimerStop (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the timer is running
+ //
+ if ( bTimerRunning ) {
+ //
+ // Stop the timer
+ //
+ Status = gBS->SetTimer ( pTimer,
+ TimerCancel,
+ 0 );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to stop the timer, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ //
+ // Timer timer is now stopped
+ //
+ bTimerRunning = FALSE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer stopped\r\n",
+ pTimer ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Start the timer
+
+ @param [in] Milliseconds The number of milliseconds between timer callbacks
+
+ @retval EFI_SUCCESS The timer was successfully created
+ @retval Other Timer initialization failed
+**/
+EFI_STATUS
+TimerStart (
+ UINTN Milliseconds
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TimeDelay;
+
+ //
+ // Stop the timer if necessary
+ //
+ Status = EFI_SUCCESS;
+ if ( bTimerRunning ) {
+ Status = TimerStop ( );
+ }
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Compute the new delay
+ //
+ TimeDelay = Milliseconds;
+ TimeDelay *= 1000 * 10;
+
+ //
+ // Start the timer
+ //
+ Status = gBS->SetTimer ( pTimer,
+ TimerPeriodic,
+ TimeDelay );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to start the timer, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ //
+ // The timer is now running
+ //
+ bTimerRunning = TRUE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer running\r\n",
+ pTimer ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Destroy the timer
+
+ @retval EFI_SUCCESS The timer was destroyed successfully
+ @retval Other Failed to destroy the timer
+**/
+EFI_STATUS
+TimerDestroy (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the timer is running
+ //
+ if ( bTimerRunning ) {
+ //
+ // Stop the timer
+ //
+ Status = TimerStop ( );
+ }
+ if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
+ //
+ // Done with this timer
+ //
+ Status = gBS->CloseEvent ( pTimer );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to free the timer event, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer Destroyed\r\n",
+ pTimer ));
+ pTimer = NULL;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Receive data from the DataSource program to test a network's bandwidth.
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG (( DEBUG_INFO,
+ "DataSink starting\r\n" ));
+
+ //
+ // Use for/break instead of goto
+ //
+ for ( ; ; )
+ {
+ //
+ // Create the timer
+ //
+ bTick = TRUE;
+ Status = TimerCreate ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Start a timer to perform network polling and display updates
+ //
+ Status = TimerStart ( 1 * 1000 );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Loop forever waiting for abuse
+ //
+ do {
+ ListenSocket = -1;
+ do {
+ //
+ // Complete any client operations
+ //
+ Status = SocketPoll ( );
+ if ( EFI_ERROR ( Status )) {
+ //
+ // Control-C
+ //
+ break;
+ }
+
+ //
+ // Wait for a while
+ //
+ } while ( !bTick );
+ if ( EFI_ERROR ( Status )) {
+ //
+ // Control-C
+ //
+ break;
+ }
+
+ //
+ // Wait for the network layer to initialize
+ //
+ Status = SocketNew ( );
+ if ( EFI_ERROR ( Status )) {
+ continue;
+ }
+
+ //
+ // Wait for the remote network application to start
+ //
+ Status = SocketAccept ( );
+ if ( EFI_NOT_STARTED == Status ) {
+ Status = SocketClose ( );
+ continue;
+ }
+ else if ( EFI_SUCCESS != Status ) {
+ //
+ // Control-C
+ //
+ break;
+ }
+
+ //
+ // Send data until the connection breaks
+ //
+ do {
+ Status = SocketPoll ( );
+ } while ( !EFI_ERROR ( Status ));
+
+ //
+ // Done with the socket
+ //
+ Status = SocketClose ( );
+ } while ( !EFI_ERROR ( Status ));
+
+ //
+ // Close the socket if necessary
+ //
+ SocketClose ( );
+
+ //
+ // All done
+ //
+ break;
+ }
+
+ //
+ // Stop the timer if necessary
+ //
+ TimerStop ( );
+ TimerDestroy ( );
+
+ //
+ // Return the operation status
+ //
+ DEBUG (( DEBUG_INFO,
+ "DataSink exiting, Status: %r\r\n",
+ Status ));
+ return Status;
+}
diff --git a/AppPkg/Applications/Sockets/DataSink/DataSink.inf b/AppPkg/Applications/Sockets/DataSink/DataSink.inf new file mode 100644 index 0000000000..7c79ab28f8 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSink/DataSink.inf @@ -0,0 +1,67 @@ +#/** @file
+# DataSink Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DataSink
+ FILE_GUID = A85DCA1B-198F-4e14-A673-874264687E85
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DataSink.c
+
+
+[Pcd]
+ gStdLibTokenSpaceGuid.DataSource_Port
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ EfiSocketLib
+ LibC
+ LibMath
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/DataSource/DataSource.c b/AppPkg/Applications/Sockets/DataSource/DataSource.c new file mode 100644 index 0000000000..d8f7f05d5c --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSource/DataSource.c @@ -0,0 +1,1615 @@ +/** @file
+ Data source for network testing.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <netinet/in.h>
+
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/Tcp4.h>
+
+#include <sys/EfiSysCall.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+
+#define RANGE_SWITCH 2048 ///< Switch display ranges
+#define DATA_RATE_UPDATE_SHIFT 2 ///< 2n seconds between updates
+#define AVERAGE_SHIFT_COUNT ( 6 - DATA_RATE_UPDATE_SHIFT ) ///< 2n samples in average
+
+#define TPL_DATASOURCE TPL_CALLBACK ///< Synchronization TPL
+
+#define PACKET_SIZE 1448 ///< Size of data packets
+#define DATA_BUFFER_SIZE (( 65536 / PACKET_SIZE ) * PACKET_SIZE ) ///< Buffer size in bytes
+
+
+//
+// Socket Data
+//
+int Socket = -1;
+
+//
+// TCP V4 Data
+//
+BOOLEAN bTcp4; ///< TRUE if TCP4 is being used
+BOOLEAN bTcp4Connected; ///< TRUE if connected to remote system
+BOOLEAN bTcp4Connecting; ///< TRUE while connection in progress
+UINTN Tcp4Index; ///< Index into handle array
+EFI_HANDLE Tcp4Controller; ///< Network controller handle
+EFI_HANDLE Tcp4Handle; ///< TCP4 port handle
+EFI_TCP4_PROTOCOL * pTcp4Protocol; ///< TCP4 protocol pointer
+EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service; ///< TCP4 Service binding
+EFI_TCP4_CONFIG_DATA Tcp4ConfigData;///< TCP4 configuration data
+EFI_TCP4_OPTION Tcp4Option; ///< TCP4 port options
+EFI_TCP4_CLOSE_TOKEN Tcp4CloseToken;///< Close control
+EFI_TCP4_CONNECTION_TOKEN Tcp4ConnectToken; ///< Connection control
+EFI_TCP4_LISTEN_TOKEN Tcp4ListenToken; ///< Listen control
+EFI_TCP4_IO_TOKEN Tcp4TxToken; ///< Normal data token
+
+//
+// Timer Data
+//
+volatile BOOLEAN bTick;
+BOOLEAN bTimerRunning;
+EFI_EVENT pTimer;
+
+//
+// Remote IP Address Data
+//
+struct sockaddr_in RemoteHostAddress;
+CHAR8 * pRemoteHost;
+
+//
+// Traffic Data
+//
+UINT64 TotalBytesSent;
+UINT64 PreviousBytes;
+UINT64 AverageBytes;
+UINT64 Samples;
+UINT8 Buffer [ DATA_BUFFER_SIZE ];
+
+
+//
+// Forward routine declarations
+//
+EFI_STATUS TimerStart ( UINTN Milliseconds );
+
+
+/**
+ Check for control C entered at console
+
+ @retval EFI_SUCCESS Control C not entered
+ @retval EFI_ABORTED Control C entered
+**/
+EFI_STATUS
+ControlCCheck (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume no user intervention
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Display user stop request
+ //
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "User stop request!\r\n" ));
+ }
+
+ //
+ // Return the check status
+ //
+ return Status;
+}
+
+
+/**
+ Get a digit
+
+ @param [in] pDigit The address of the next digit
+ @param [out] pValue The address to receive the value
+
+ @returns Returns the address of the separator
+
+**/
+CHAR8 *
+GetDigit (
+ CHAR8 * pDigit,
+ UINT32 * pValue
+ )
+{
+ UINT32 Value;
+
+ //
+ // Walk the digits
+ //
+ Value = 0;
+ while (( '0' <= *pDigit ) && ( '9' >= *pDigit ))
+ {
+ //
+ // Make room for the new least significant digit
+ //
+ Value *= 10;
+
+ //
+ // Convert the digit from ASCII to binary
+ //
+ Value += *pDigit - '0';
+
+ //
+ // Set the next digit
+ //
+ pDigit += 1;
+ }
+
+ //
+ // Return the value
+ //
+ *pValue = Value;
+
+ //
+ // Return the next separator
+ //
+ return pDigit;
+}
+
+
+/**
+ Get the IP address
+
+ @retval EFI_SUCCESS The IP address is valid
+ @retval Other Failure to convert the IP address
+**/
+EFI_STATUS
+IpAddress (
+ )
+{
+ CHAR8 * pSeparator;
+ INT32 RemoteAddress;
+ EFI_STATUS Status;
+ UINT32 Value1;
+ UINT32 Value2;
+ UINT32 Value3;
+ UINT32 Value4;
+
+ //
+ // Assume failure
+ //
+ Status = EFI_INVALID_PARAMETER;
+
+ //
+ // Convert the IP address from a string to a numeric value
+ //
+ pSeparator = GetDigit ( pRemoteHost, &Value1 );
+ if (( 255 >= Value1 ) && ( '.' == *pSeparator )) {
+ pSeparator = GetDigit ( ++pSeparator, &Value2 );
+ if (( 255 >= Value2 ) && ( '.' == *pSeparator )) {
+ pSeparator = GetDigit ( ++pSeparator, &Value3 );
+ if (( 255 >= Value3 ) && ( '.' == *pSeparator )) {
+ pSeparator = GetDigit ( ++pSeparator, &Value4 );
+ if (( 255 >= Value4 ) && ( 0 == *pSeparator )) {
+ RemoteAddress = Value1
+ | ( Value2 << 8 )
+ | ( Value3 << 16 )
+ | ( Value4 << 24 );
+ RemoteHostAddress.sin_addr.s_addr = (UINT32) RemoteAddress;
+ Status = EFI_SUCCESS;
+ DEBUG (( DEBUG_INFO,
+ "%d.%d.%d.%d: Remote host IP address\r\n",
+ Value1,
+ Value2,
+ Value3,
+ Value4 ));
+ }
+ }
+ }
+ }
+ if ( EFI_ERROR ( Status )) {
+ Print ( L"Invalid digit detected: %d\r\n", *pSeparator );
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Close the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketClose (
+ )
+{
+ int CloseStatus;
+ EFI_STATUS Status;
+
+ //
+ // Determine if the socket is open
+ //
+ Status = EFI_DEVICE_ERROR;
+ if ( -1 != Socket ) {
+ //
+ // Attempt to close the socket
+ //
+ CloseStatus = close ( Socket );
+ if ( 0 == CloseStatus ) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket closed\r\n",
+ Socket ));
+ Socket = -1;
+ Status = EFI_SUCCESS;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR: Failed to close socket, errno: %d\r\n",
+ errno ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Connect the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketConnect (
+ )
+{
+ int ConnectStatus;
+ UINT32 RemoteAddress;
+ EFI_STATUS Status;
+
+ //
+ // Display the connecting message
+ //
+ RemoteAddress = RemoteHostAddress.sin_addr.s_addr;
+ Print ( L"Connecting to remote system %d.%d.%d.%d:%d\r\n",
+ RemoteAddress & 0xff,
+ ( RemoteAddress >> 8 ) & 0xff,
+ ( RemoteAddress >> 16 ) & 0xff,
+ ( RemoteAddress >> 24 ) & 0xff,
+ htons ( RemoteHostAddress.sin_port ));
+
+ //
+ // Connect to the remote system
+ //
+ Status = EFI_SUCCESS;
+ do {
+ //
+ // Check for user stop request
+ //
+ while ( ! bTick ) {
+ Status = ControlCCheck ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ }
+ bTick = FALSE;
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Connect to the remote system
+ //
+ ConnectStatus = connect ( Socket,
+ (struct sockaddr *) &RemoteHostAddress,
+ RemoteHostAddress.sin_len );
+ if ( -1 != ConnectStatus ) {
+ Print ( L"Connected to remote system %d.%d.%d.%d:%d\r\n",
+ RemoteAddress & 0xff,
+ ( RemoteAddress >> 8 ) & 0xff,
+ ( RemoteAddress >> 16 ) & 0xff,
+ ( RemoteAddress >> 24 ) & 0xff,
+ htons ( RemoteHostAddress.sin_port ));
+ }
+ else {
+ //
+ // Close the socket and try again
+ //
+ if ( EAGAIN != errno ) {
+ Status = EFI_NOT_STARTED;
+ break;
+ }
+ }
+ } while ( -1 == ConnectStatus );
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Create the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketNew (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Loop creating the socket
+ //
+ DEBUG (( DEBUG_INFO,
+ "Creating the socket\r\n" ));
+ do {
+ //
+ // Check for user stop request
+ //
+ Status = ControlCCheck ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Attempt to create the socket
+ //
+ Socket = socket ( AF_INET,
+ SOCK_STREAM,
+ IPPROTO_TCP );
+ if ( -1 != Socket ) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Socket created\r\n",
+ Socket ));
+ break;
+ }
+ } while ( -1 == Socket );
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Send data over the socket
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+SocketSend (
+ )
+{
+ size_t BytesSent;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ //
+ // Restart the timer
+ //
+ TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );
+
+ //
+ // Loop until the connection breaks or the user stops
+ //
+ do {
+ //
+ // Check for user stop request
+ //
+ Status = ControlCCheck ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Send some bytes
+ //
+ BytesSent = write ( Socket, &Buffer[0], sizeof ( Buffer ));
+ if ( -1 == BytesSent ) {
+ DEBUG (( DEBUG_INFO,
+ "ERROR: send failed, errno: %d\r\n",
+ errno ));
+
+ //
+ // Try again
+ //
+ Status = EFI_SUCCESS;
+
+//
+// Exit now
+//
+Status = EFI_NOT_STARTED;
+ break;
+ }
+
+ //
+ // Synchronize with the TimerCallback routine
+ //
+ TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
+
+ //
+ // Account for the data sent
+ //
+ TotalBytesSent += BytesSent;
+
+ //
+ // Release the TimerCallback routine synchronization
+ //
+ gBS->RestoreTPL ( TplPrevious );
+ } while ( !EFI_ERROR ( Status ));
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Open the network connection and send the data.
+
+ @retval EFI_SUCCESS Continue looping
+ @retval other Stopped by user's Control-C input
+
+**/
+EFI_STATUS
+SocketOpen (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Use do/while and break instead of goto
+ //
+ do
+ {
+ //
+ // Wait for the network layer to initialize
+ //
+ Status = SocketNew ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Wait for the remote network application to start
+ //
+ Status = SocketConnect ( );
+ if ( EFI_NOT_STARTED == Status ) {
+ Status = SocketClose ( );
+ continue;
+ }
+ else if ( EFI_SUCCESS != Status ) {
+ //
+ // Control-C
+ //
+ break;
+ }
+
+ //
+ // Send data until the connection breaks
+ //
+ Status = SocketSend ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+ } while ( FALSE );
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Close the TCP connection
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+Tcp4Close (
+ )
+{
+ UINTN Index;
+ UINT8 * pIpAddress;
+ EFI_STATUS Status;
+
+ //
+ // Close the port
+ //
+ if ( bTcp4Connected ) {
+ Tcp4CloseToken.AbortOnClose = TRUE;
+ Status = pTcp4Protocol->Close ( pTcp4Protocol,
+ &Tcp4CloseToken );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to start the TCP port close, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ Status = gBS->WaitForEvent ( 1,
+ &Tcp4CloseToken.CompletionToken.Event,
+ &Index );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to wait for close event, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ Status = Tcp4CloseToken.CompletionToken.Status;
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the TCP port, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TCP port closed\r\n",
+ pTcp4Protocol ));
+ bTcp4Connected = FALSE;
+
+ //
+ // Display the port closed message
+ //
+ pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
+ Print ( L"Closed connection to %d.%d.%d.%d:%d\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3],
+ htons ( RemoteHostAddress.sin_port ));
+ }
+ }
+ }
+ }
+
+ //
+ // Release the events
+ //
+ if ( NULL != Tcp4TxToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( Tcp4TxToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TX event closed\r\n",
+ Tcp4TxToken.CompletionToken.Event ));
+ Tcp4TxToken.CompletionToken.Event = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the Tcp4TxToken event, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ if ( NULL != Tcp4ListenToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( Tcp4ListenToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Listen event closed\r\n",
+ Tcp4ListenToken.CompletionToken.Event ));
+ Tcp4ListenToken.CompletionToken.Event = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the Tcp4ListenToken event, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ if ( NULL != Tcp4ConnectToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( Tcp4ConnectToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Connect event closed\r\n",
+ Tcp4ConnectToken.CompletionToken.Event ));
+ Tcp4ConnectToken.CompletionToken.Event = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the Tcp4ConnectToken event, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ if ( NULL != Tcp4CloseToken.CompletionToken.Event ) {
+ Status = gBS->CloseEvent ( Tcp4CloseToken.CompletionToken.Event );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Close event closed\r\n",
+ Tcp4CloseToken.CompletionToken.Event ));
+ Tcp4CloseToken.CompletionToken.Event = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the Tcp4CloseToken event, Status: %r\r\n",
+ Status ));
+ }
+ }
+
+ //
+ // Close the TCP protocol
+ //
+ if ( NULL != pTcp4Protocol ) {
+ Status = gBS->CloseProtocol ( Tcp4Handle,
+ &gEfiTcp4ProtocolGuid,
+ gImageHandle,
+ NULL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the TCP protocol, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TCP4 protocol closed\r\n",
+ pTcp4Protocol ));
+ pTcp4Protocol = NULL;
+ }
+ }
+
+ //
+ // Done with the TCP service
+ //
+ if ( NULL != Tcp4Handle ) {
+ Status = pTcp4Service->DestroyChild ( pTcp4Service,
+ Tcp4Handle );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to release TCP service handle, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "Ox%08x: TCP service closed\r\n",
+ Tcp4Handle ));
+ Tcp4Handle = NULL;
+ }
+ }
+
+ //
+ // Close the service protocol
+ //
+ if ( NULL != pTcp4Service ) {
+ Status = gBS->CloseProtocol ( Tcp4Controller,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ gImageHandle,
+ NULL );
+ if ( !EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Controller closed gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
+ Tcp4Controller ));
+ pTcp4Service = NULL;
+ }
+ else {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to close the gEfiTcp4ServiceBindingProtocolGuid protocol, Status: %r\r\n",
+ Status ));
+ }
+ }
+ Tcp4Controller = NULL;
+ bTcp4Connecting = TRUE;
+
+ //
+ // Mark the connection as closed
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Locate TCP protocol
+
+ @retval EFI_SUCCESS Protocol found
+ @retval other Protocl not found
+**/
+EFI_STATUS
+Tcp4Locate (
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE * pHandles;
+ UINT8 * pIpAddress;
+ EFI_STATUS Status;
+
+ //
+ // Use do/while and break instead of goto
+ //
+ do {
+ //
+ // Attempt to locate the next TCP adapter in the system
+ //
+ Status = gBS->LocateHandleBuffer ( ByProtocol,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ NULL,
+ &HandleCount,
+ &pHandles );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_WARN,
+ "WARNING - No network controllers or TCP4 available, Status: %r\r\n",
+ Status ));
+ break;
+ }
+
+ //
+ // Wrap the index if necessary
+ //
+ if ( HandleCount <= Tcp4Index ) {
+ Tcp4Index = 0;
+
+ //
+ // Wait for the next timer tick
+ //
+ do {
+ } while ( !bTick );
+ bTick = FALSE;
+ }
+
+ //
+ // Display the connecting message
+ //
+ if ( bTcp4Connecting ) {
+ pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
+ Print ( L"Connecting to %d.%d.%d.%d:%d\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3],
+ htons ( RemoteHostAddress.sin_port ));
+ bTcp4Connecting = FALSE;
+ }
+
+ //
+ // Open the network controller's service protocol
+ //
+ Tcp4Controller = pHandles [ Tcp4Index++ ];
+ Status = gBS->OpenProtocol (
+ Tcp4Controller,
+ &gEfiTcp4ServiceBindingProtocolGuid,
+ (VOID **) &pTcp4Service,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to open gEfiTcp4ServiceBindingProtocolGuid on controller 0x%08x\r\n",
+ Tcp4Controller ));
+ Tcp4Controller = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Controller opened gEfiTcp4ServiceBindingProtocolGuid protocol\r\n",
+ Tcp4Controller ));
+
+ //
+ // Connect to the TCP service
+ //
+ Status = pTcp4Service->CreateChild ( pTcp4Service,
+ &Tcp4Handle );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to open TCP service, Status: %r\r\n",
+ Status ));
+ Tcp4Handle = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "Ox%08x: TCP service opened\r\n",
+ Tcp4Handle ));
+
+ //
+ // Locate the TCP protcol
+ //
+ Status = gBS->OpenProtocol ( Tcp4Handle,
+ &gEfiTcp4ProtocolGuid,
+ (VOID **)&pTcp4Protocol,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to open the TCP protocol, Status: %r\r\n",
+ Status ));
+ pTcp4Protocol = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TCP4 protocol opened\r\n",
+ pTcp4Protocol ));
+ }while ( FALSE );
+
+ //
+ // Release the handle buffer
+ //
+ gBS->FreePool ( pHandles );
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Send data over the TCP4 connection
+
+ @retval EFI_SUCCESS The application is running normally
+ @retval Other The user stopped the application
+**/
+EFI_STATUS
+Tcp4Send (
+ )
+{
+ UINTN Index;
+ EFI_TCP4_TRANSMIT_DATA Packet;
+ EFI_STATUS Status;
+ EFI_TPL TplPrevious;
+
+ //
+ // Restart the timer
+ //
+ TimerStart ( 1000 << DATA_RATE_UPDATE_SHIFT );
+
+ //
+ // Initialize the packet
+ //
+ Packet.DataLength = sizeof ( Buffer );
+ Packet.FragmentCount = 1;
+ Packet.Push = FALSE;
+ Packet.Urgent = FALSE;
+ Packet.FragmentTable[0].FragmentBuffer = &Buffer[0];
+ Packet.FragmentTable[0].FragmentLength = sizeof ( Buffer );
+ Tcp4TxToken.Packet.TxData = &Packet;
+
+ //
+ // Loop until the connection breaks or the user stops
+ //
+ do {
+ //
+ // Check for user stop request
+ //
+ Status = ControlCCheck ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Send some bytes
+ //
+ Status = pTcp4Protocol->Transmit ( pTcp4Protocol,
+ &Tcp4TxToken );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to start the transmit, Status: %r\r\n",
+ Status ));
+
+ //
+ // Try again
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ //
+ // Wait for the transmit to complete
+ //
+ Status = gBS->WaitForEvent ( 1,
+ &Tcp4TxToken.CompletionToken.Event,
+ &Index );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to wait for transmit completion, Status: %r\r\n",
+ Status ));
+
+ //
+ // Try again
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ //
+ // Get the transmit status
+ //
+ Status = Tcp4TxToken.CompletionToken.Status;
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_WARN,
+ "WARNING - Failed the transmission, Status: %r\r\n",
+ Status ));
+
+ //
+ // Try again
+ //
+ Status = EFI_SUCCESS;
+
+//
+// Exit now
+//
+Status = EFI_NOT_STARTED;
+ break;
+ }
+
+ //
+ // Synchronize with the TimerCallback routine
+ //
+ TplPrevious = gBS->RaiseTPL ( TPL_DATASOURCE );
+
+ //
+ // Account for the data sent
+ //
+ TotalBytesSent += Packet.DataLength;
+
+ //
+ // Release the TimerCallback routine synchronization
+ //
+ gBS->RestoreTPL ( TplPrevious );
+ } while ( !EFI_ERROR ( Status ));
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Open the network connection and send the data.
+
+ @retval EFI_SUCCESS Continue looping
+ @retval other Stopped by user's Control-C input
+
+**/
+EFI_STATUS
+Tcp4Open (
+ )
+{
+ UINTN Index;
+ UINT8 * pIpAddress;
+ EFI_STATUS Status;
+
+ //
+ // Use do/while and break instead of goto
+ //
+ do {
+ //
+ // Locate the TCP protocol
+ //
+ Status = Tcp4Locate ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Create the necessary events
+ //
+ Status = gBS->CreateEvent ( 0,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Tcp4CloseToken.CompletionToken.Event );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to create the close event, Status: %r\r\n",
+ Status ));
+ Tcp4CloseToken.CompletionToken.Event = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Close event open\r\n",
+ Tcp4CloseToken.CompletionToken.Event ));
+
+ Status = gBS->CreateEvent ( 0,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Tcp4ConnectToken.CompletionToken.Event );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to create the connect event, Status: %r\r\n",
+ Status ));
+ Tcp4ConnectToken.CompletionToken.Event = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Connect event open\r\n",
+ Tcp4ConnectToken.CompletionToken.Event ));
+
+ Status = gBS->CreateEvent ( 0,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Tcp4ListenToken.CompletionToken.Event );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to create the listen event, Status: %r\r\n",
+ Status ));
+ Tcp4ListenToken.CompletionToken.Event = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Listen event open\r\n",
+ Tcp4ListenToken.CompletionToken.Event ));
+
+ Status = gBS->CreateEvent ( 0,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &Tcp4TxToken.CompletionToken.Event );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to create the TX event, Status: %r\r\n",
+ Status ));
+ Tcp4TxToken.CompletionToken.Event = NULL;
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TX event open\r\n",
+ Tcp4TxToken.CompletionToken.Event ));
+
+ //
+ // Configure the local TCP port
+ //
+ Tcp4ConfigData.TimeToLive = 255;
+ Tcp4ConfigData.TypeOfService = 0;
+ Tcp4ConfigData.ControlOption = NULL;
+ Tcp4ConfigData.AccessPoint.ActiveFlag = TRUE;
+ Tcp4ConfigData.AccessPoint.StationAddress.Addr[0] = 0;
+ Tcp4ConfigData.AccessPoint.StationAddress.Addr[1] = 0;
+ Tcp4ConfigData.AccessPoint.StationAddress.Addr[2] = 0;
+ Tcp4ConfigData.AccessPoint.StationAddress.Addr[3] = 0;
+ Tcp4ConfigData.AccessPoint.StationPort = 0;
+ Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8) RemoteHostAddress.sin_addr.s_addr;
+ Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 8 );
+ Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 16 );
+ Tcp4ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( RemoteHostAddress.sin_addr.s_addr >> 24 );
+ Tcp4ConfigData.AccessPoint.RemotePort = RemoteHostAddress.sin_port;
+ Tcp4ConfigData.AccessPoint.UseDefaultAddress = TRUE;
+ Tcp4ConfigData.AccessPoint.SubnetMask.Addr[0] = 0;
+ Tcp4ConfigData.AccessPoint.SubnetMask.Addr[1] = 0;
+ Tcp4ConfigData.AccessPoint.SubnetMask.Addr[2] = 0;
+ Tcp4ConfigData.AccessPoint.SubnetMask.Addr[3] = 0;
+ Status = pTcp4Protocol->Configure ( pTcp4Protocol,
+ &Tcp4ConfigData );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to configure TCP port, Status: %r\r\n",
+ Status ));
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TCP4 port configured\r\n",
+ pTcp4Protocol ));
+
+ //
+ // Connect to the remote TCP port
+ //
+ Status = pTcp4Protocol->Connect ( pTcp4Protocol,
+ &Tcp4ConnectToken );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to start the connection to the remote system, Status: %r\r\n",
+ Status ));
+ break;
+ }
+ Status = gBS->WaitForEvent ( 1,
+ &Tcp4ConnectToken.CompletionToken.Event,
+ &Index );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to wait for the connection, Status: %r\r\n",
+ Status ));
+ break;
+ }
+ Status = Tcp4ConnectToken.CompletionToken.Status;
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_WARN,
+ "WARNING - Failed to connect to the remote system, Status: %r\r\n",
+ Status ));
+ break;
+ }
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: TCP4 port connected\r\n",
+ pTcp4Protocol ));
+ bTcp4Connected = TRUE;
+
+ //
+ // Display the connection
+ //
+ pIpAddress = (UINT8 *)&RemoteHostAddress.sin_addr.s_addr;
+ Print ( L"Connected to %d.%d.%d.%d:%d\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3],
+ htons ( RemoteHostAddress.sin_port ));
+ } while ( 0 );
+
+ if ( EFI_ERROR ( Status )) {
+ //
+ // Try again
+ //
+ Status = EFI_SUCCESS;
+ }
+ else {
+ //
+ // Semd data until the connection breaks
+ //
+ Status = Tcp4Send ( );
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Handle the timer callback
+
+ @param [in] Event Event that caused this callback
+ @param [in] pContext Context for this routine
+**/
+VOID
+TimerCallback (
+ IN EFI_EVENT Event,
+ IN VOID * pContext
+ )
+{
+ UINT64 BytesSent;
+ UINT64 DeltaBytes;
+ UINT32 Delta;
+ UINT64 Average;
+
+ //
+ // Notify the other code of the timer tick
+ //
+ bTick = TRUE;
+
+ //
+ // Update the average bytes per second
+ //
+ BytesSent = TotalBytesSent;
+ if ( 0 != BytesSent ) {
+ DeltaBytes = AverageBytes >> AVERAGE_SHIFT_COUNT;
+ AverageBytes -= DeltaBytes;
+ DeltaBytes = BytesSent - PreviousBytes;
+ PreviousBytes = BytesSent;
+ AverageBytes += DeltaBytes;
+
+ //
+ // Separate the samples
+ //
+ if (( 2 << AVERAGE_SHIFT_COUNT ) == Samples ) {
+ Print ( L"---------- Stable average ----------\r\n" );
+ }
+ Samples += 1;
+
+ //
+ // Display the data rate
+ //
+ Delta = (UINT32)( DeltaBytes >> DATA_RATE_UPDATE_SHIFT );
+ Average = AverageBytes >> ( AVERAGE_SHIFT_COUNT + DATA_RATE_UPDATE_SHIFT );
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d Bytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d KiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d MiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d GiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ else {
+ Average >>= 10;
+ if ( Average < RANGE_SWITCH ) {
+ Print ( L"%d Bytes/sec, Ave: %d TiBytes/Sec\r\n",
+ Delta,
+ Average );
+ }
+ else {
+ Average >>= 10;
+ Print ( L"%d Bytes/sec, Ave: %d PiBytes/Sec\r\n",
+ Delta,
+ (UINT32) Average );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Create the timer
+
+ @retval EFI_SUCCESS The timer was successfully created
+ @retval Other Timer initialization failed
+**/
+EFI_STATUS
+TimerCreate (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Create the timer
+ //
+ Status = gBS->CreateEvent ( EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_DATASOURCE,
+ TimerCallback,
+ NULL,
+ &pTimer );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to allocate the timer event, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer created\r\n",
+ pTimer ));
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Stop the timer
+
+ @retval EFI_SUCCESS The timer was stopped successfully
+ @retval Other The timer failed to stop
+**/
+EFI_STATUS
+TimerStop (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the timer is running
+ //
+ if ( bTimerRunning ) {
+ //
+ // Stop the timer
+ //
+ Status = gBS->SetTimer ( pTimer,
+ TimerCancel,
+ 0 );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to stop the timer, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ //
+ // Timer timer is now stopped
+ //
+ bTimerRunning = FALSE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer stopped\r\n",
+ pTimer ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Start the timer
+
+ @param [in] Milliseconds The number of milliseconds between timer callbacks
+
+ @retval EFI_SUCCESS The timer was successfully created
+ @retval Other Timer initialization failed
+**/
+EFI_STATUS
+TimerStart (
+ UINTN Milliseconds
+ )
+{
+ EFI_STATUS Status;
+ UINT64 TimeDelay;
+
+ //
+ // Stop the timer if necessary
+ //
+ Status = EFI_SUCCESS;
+ if ( bTimerRunning ) {
+ Status = TimerStop ( );
+ }
+ if ( !EFI_ERROR ( Status )) {
+ //
+ // Compute the new delay
+ //
+ TimeDelay = Milliseconds;
+ TimeDelay *= 1000 * 10;
+
+ //
+ // Start the timer
+ //
+ Status = gBS->SetTimer ( pTimer,
+ TimerPeriodic,
+ TimeDelay );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to start the timer, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ //
+ // The timer is now running
+ //
+ bTimerRunning = TRUE;
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer running\r\n",
+ pTimer ));
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Destroy the timer
+
+ @retval EFI_SUCCESS The timer was destroyed successfully
+ @retval Other Failed to destroy the timer
+**/
+EFI_STATUS
+TimerDestroy (
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Assume success
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Determine if the timer is running
+ //
+ if ( bTimerRunning ) {
+ //
+ // Stop the timer
+ //
+ Status = TimerStop ( );
+ }
+ if (( !EFI_ERROR ( Status )) && ( NULL != pTimer )) {
+ //
+ // Done with this timer
+ //
+ Status = gBS->CloseEvent ( pTimer );
+ if ( EFI_ERROR ( Status )) {
+ DEBUG (( DEBUG_ERROR,
+ "ERROR - Failed to free the timer event, Status: %r\r\n",
+ Status ));
+ }
+ else {
+ DEBUG (( DEBUG_INFO,
+ "0x%08x: Timer Destroyed\r\n",
+ pTimer ));
+ pTimer = NULL;
+ }
+ }
+
+ //
+ // Return the operation status
+ //
+ return Status;
+}
+
+
+/**
+ Send data to the DataSink program to test a network's bandwidth.
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ EFI_STATUS (* pClose) ();
+ EFI_STATUS (* pOpen) ();
+ EFI_STATUS Status;
+
+ DEBUG (( DEBUG_INFO,
+ "DataSource starting\r\n" ));
+
+ //
+ // Validate the command line
+ //
+ if ( 2 != Argc ) {
+ Print ( L"%s <remote IP address>\r\n", Argv[0] );
+ return -1;
+ }
+
+bTcp4 = TRUE;
+
+ //
+ // Determine the support routines
+ //
+ if ( bTcp4 ) {
+ pOpen = Tcp4Open;
+ pClose = Tcp4Close;
+ bTcp4Connecting = TRUE;
+ }
+ else {
+ pOpen = SocketOpen;
+ pClose = SocketClose;
+ }
+
+ //
+ // Use for/break instead of goto
+ //
+ for ( ; ; )
+ {
+ //
+ // No bytes sent so far
+ //
+ TotalBytesSent = 0;
+ AverageBytes = 0;
+ PreviousBytes = 0;
+ Samples = 0;
+
+ //
+ // Get the port number
+ //
+ ZeroMem ( &RemoteHostAddress, sizeof ( RemoteHostAddress ));
+ RemoteHostAddress.sin_len = sizeof ( RemoteHostAddress );
+ RemoteHostAddress.sin_family = AF_INET;
+ RemoteHostAddress.sin_port = htons ( PcdGet16 ( DataSource_Port ));
+
+Print ( L"Argc: %d\r\n", Argc);
+Print ( L"Argv[0]: %a\r\n", Argv[0]);
+Print ( L"Argv[1]: %a\r\n", Argv[1]);
+
+ //
+ // Get the IP address
+ //
+ pRemoteHost = Argv [1];
+ Status = IpAddress ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Create the timer
+ //
+ bTick = TRUE;
+ Status = TimerCreate ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Loop forever abusing the specified system
+ //
+ do {
+ //
+ // Start a timer to perform connection polling and display updates
+ //
+ Status = TimerStart ( 2 * 1000 );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Open the network connection and send the data
+ //
+ Status = pOpen ( );
+ if ( EFI_ERROR ( Status )) {
+ break;
+ }
+
+ //
+ // Done with the network connection
+ //
+ Status = pClose ( );
+ } while ( !EFI_ERROR ( Status ));
+
+ //
+ // Close the network connection if necessary
+ //
+ pClose ( );
+
+ //
+ // All done
+ //
+ break;
+ }
+
+ //
+ // Stop the timer if necessary
+ //
+ TimerStop ( );
+ TimerDestroy ( );
+
+ //
+ // Return the operation status
+ //
+ DEBUG (( DEBUG_INFO,
+ "DataSource exiting, Status: %r\r\n",
+ Status ));
+ return Status;
+}
diff --git a/AppPkg/Applications/Sockets/DataSource/DataSource.inf b/AppPkg/Applications/Sockets/DataSource/DataSource.inf new file mode 100644 index 0000000000..ec9cf6c185 --- /dev/null +++ b/AppPkg/Applications/Sockets/DataSource/DataSource.inf @@ -0,0 +1,70 @@ +#/** @file
+# DataSource Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DataSource
+ FILE_GUID = 30EB0F26-FC0A-4fd2-B9C9-751EA2BB1980
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DataSource.c
+
+
+[Pcd]
+ gStdLibTokenSpaceGuid.DataSource_Port
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ EfiSocketLib
+ DebugLib
+ LibC
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[Protocols]
+ gEfiTcp4ProtocolGuid
+ gEfiTcp4ServiceBindingProtocolGuid
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c new file mode 100644 index 0000000000..2e626396ca --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.c @@ -0,0 +1,133 @@ +/** @file
+ Translate the port number into a service name
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <arpa\nameser.h>
+#include <arpa\nameser_compat.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+/**
+ Translate the IP address into a host name
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ UINTN Index;
+ UINT8 IpAddress[4];
+ struct hostent * pHost;
+ UINT8 * pIpAddress;
+ char ** ppName;
+ UINT32 RemoteAddress[4];
+
+ //
+ // Determine if the IPv4 address is specified
+ //
+ if (( 2 != Argc )
+ || ( 4 != sscanf ( Argv[1],
+ "%d.%d.%d.%d",
+ &RemoteAddress[0],
+ &RemoteAddress[1],
+ &RemoteAddress[2],
+ &RemoteAddress[3]))
+ || ( 255 < RemoteAddress [0])
+ || ( 255 < RemoteAddress [1])
+ || ( 255 < RemoteAddress [2])
+ || ( 255 < RemoteAddress [3])) {
+ Print ( L"%a <IPv4 Address>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the address into a host name
+ //
+ IpAddress[0] = (UINT8)RemoteAddress[0];
+ IpAddress[1] = (UINT8)RemoteAddress[1];
+ IpAddress[2] = (UINT8)RemoteAddress[2];
+ IpAddress[3] = (UINT8)RemoteAddress[3];
+ pHost = gethostbyaddr ( &IpAddress[0], INADDRSZ, AF_INET );
+ if ( NULL == pHost ) {
+ Print ( L"ERROR - host not found, errno: %d\r\n", errno );
+ }
+ else {
+ pIpAddress = (UINT8 *)pHost->h_addr_list [ 0 ];
+ Print ( L"%d.%d.%d.%d, %a\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3],
+ pHost->h_name );
+
+ //
+ // Display the other addresses
+ //
+ for ( Index = 1; NULL != pHost->h_addr_list[Index]; Index++ ) {
+ pIpAddress = (UINT8 *)pHost->h_addr_list[Index];
+ Print ( L"%d.%d.%d.%d\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3]);
+ }
+
+ //
+ // Display the list of aliases
+ //
+ ppName = pHost->h_aliases;
+ if (( NULL == ppName ) || ( NULL == *ppName )) {
+ Print ( L"No aliases\r\n" );
+ }
+ else {
+ Print ( L"Aliases: " );
+ while ( NULL != *ppName ) {
+ //
+ // Display the alias
+ //
+ Print ( L"%a", *ppName );
+
+ //
+ // Set the next alias
+ //
+ ppName += 1;
+ if ( NULL != *ppName ) {
+ Print ( L", " );
+ }
+ }
+ Print ( L"\r\n" );
+ }
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf new file mode 100644 index 0000000000..f31b8278dd --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByAddr/GetHostByAddr.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetHostByAddr Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetHostByAddr
+ FILE_GUID = C31A6189-639A-458b-B040-D7D506CA8F4F
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetHostByAddr.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c new file mode 100644 index 0000000000..47453aced2 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.c @@ -0,0 +1,85 @@ +/** @file
+ Translate the host name into an IP address
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+struct hostent * _gethostbydnsname(const char *, int);
+
+char mBuffer [65536];
+
+
+/**
+ Translate the host name into an IP address
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+ UINT8 * pIpAddress;
+ struct hostent * pHost;
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Determine if the host name is specified
+ //
+ AppStatus = 0;
+ if ( 1 == Argc ) {
+ Print ( L"%a <host name>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the host name
+ //
+ pHost = _gethostbydnsname ( Argv[1], AF_INET );
+ if ( NULL == pHost ) {
+ Print ( L"ERROR - host not found, errno: %d\r\n", errno );
+ }
+ else {
+ pIpAddress = (UINT8 *)pHost->h_addr;
+ Print ( L"%a: Type %d, %d.%d.%d.%d\r\n",
+ pHost->h_name,
+ pHost->h_addrtype,
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3]);
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf new file mode 100644 index 0000000000..417eb5e228 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByDns/GetHostByDns.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetHostByDns Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetHostByDns
+ FILE_GUID = 3698D2B0-E727-4537-A636-A8770736ABFB
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetHostByDns.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c new file mode 100644 index 0000000000..d539c99481 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.c @@ -0,0 +1,123 @@ +/** @file
+ Translate the host name into an IP address
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+char mBuffer [65536];
+
+
+/**
+ Translate the host name into an IP address
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+ UINTN Index;
+ struct hostent * pHost;
+ UINT8 * pIpAddress;
+ char ** ppName;
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Determine if the host name is specified
+ //
+ AppStatus = 0;
+ if ( 1 == Argc ) {
+ Print ( L"%a <host name>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the host name
+ //
+ pHost = gethostbyname ( Argv[1]);
+ if ( NULL == pHost ) {
+ Print ( L"ERROR - host not found, errno: %d\r\n", errno );
+ }
+ else {
+ pIpAddress = (UINT8 *)pHost->h_addr;
+ Print ( L"%d.%d.%d.%d, Type %d, %a\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3],
+ pHost->h_addrtype,
+ pHost->h_name );
+
+ //
+ // Display the other addresses
+ //
+ for ( Index = 1; NULL != pHost->h_addr_list[Index]; Index++ ) {
+ pIpAddress = (UINT8 *)pHost->h_addr_list[Index];
+ Print ( L"%d.%d.%d.%d\r\n",
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3]);
+ }
+
+ //
+ // Display the list of aliases
+ //
+ ppName = pHost->h_aliases;
+ if (( NULL == ppName ) || ( NULL == *ppName )) {
+ Print ( L"No aliases\r\n" );
+ }
+ else {
+ Print ( L"Aliases: " );
+ while ( NULL != *ppName ) {
+ //
+ // Display the alias
+ //
+ Print ( L"%a", *ppName );
+
+ //
+ // Set the next alias
+ //
+ ppName += 1;
+ if ( NULL != *ppName ) {
+ Print ( L", " );
+ }
+ }
+ Print ( L"\r\n" );
+ }
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf new file mode 100644 index 0000000000..48beb2a26f --- /dev/null +++ b/AppPkg/Applications/Sockets/GetHostByName/GetHostByName.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetHostByName Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetHostByName
+ FILE_GUID = 70FB9CE0-2CB1-4fd7-80EE-AB4B6CF4B43F
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetHostByName.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c new file mode 100644 index 0000000000..51d8c6d101 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.c @@ -0,0 +1,89 @@ +/** @file
+ Translate the IPv4 address into a network name
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+/**
+ Translate the IPv4 address into a network name
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ UINT32 RemoteAddress[4];
+ UINT8 IpAddress[4];
+ struct netent * pNetwork;
+
+ //
+ // Determine if the IPv4 address is specified
+ //
+ if (( 2 != Argc )
+ || ( 4 != sscanf ( Argv[1],
+ "%d.%d.%d.%d",
+ &RemoteAddress[0],
+ &RemoteAddress[1],
+ &RemoteAddress[2],
+ &RemoteAddress[3]))
+ || ( 255 < RemoteAddress [0])
+ || ( 255 < RemoteAddress [1])
+ || ( 255 < RemoteAddress [2])
+ || ( 255 < RemoteAddress [3])) {
+ Print ( L"%a <IPv4 Address>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the address into a network name
+ //
+ IpAddress[0] = (UINT8)RemoteAddress[0];
+ IpAddress[1] = (UINT8)RemoteAddress[1];
+ IpAddress[2] = (UINT8)RemoteAddress[2];
+ IpAddress[3] = (UINT8)RemoteAddress[3];
+ pNetwork = getnetbyaddr ( *(uint32_t *)&IpAddress[0], AF_INET );
+ if ( NULL == pNetwork ) {
+ Print ( L"ERROR - network not found, errno: %d\r\n", errno );
+ }
+ else {
+ Print ( L"%a: %d.%d.%d.%d, 0x%08x\r\n",
+ pNetwork->n_name,
+ IpAddress[0],
+ IpAddress[1],
+ IpAddress[2],
+ IpAddress[3],
+ pNetwork->n_net );
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf new file mode 100644 index 0000000000..c280d186f1 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByAddr/GetNetByAddr.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetNetByAddr Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetNetByAddr
+ FILE_GUID = 22198FD5-4835-4842-BF31-EB957C7DD70D
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetNetByAddr.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c new file mode 100644 index 0000000000..b3609c9374 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.c @@ -0,0 +1,83 @@ +/** @file
+ Translate the network name into an IP address
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+char mBuffer [65536];
+
+
+/**
+ Translate the network name into an IP address
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+ UINT8 * pIpAddress;
+ struct netent * pNetwork;
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Determine if the network name is specified
+ //
+ AppStatus = 0;
+ if ( 1 == Argc ) {
+ Print ( L"%a <network name>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the net name
+ //
+ pNetwork = getnetbyname ( Argv[1]);
+ if ( NULL == pNetwork ) {
+ Print ( L"ERROR - network not found, errno: %d\r\n", errno );
+ }
+ else {
+ pIpAddress = (UINT8 *)pNetwork->n_net;
+ Print ( L"%a: Type %d, %d.%d.%d.%d\r\n",
+ pNetwork->n_name,
+ pNetwork->n_addrtype,
+ pIpAddress[0],
+ pIpAddress[1],
+ pIpAddress[2],
+ pIpAddress[3]);
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf new file mode 100644 index 0000000000..1b9764e54b --- /dev/null +++ b/AppPkg/Applications/Sockets/GetNetByName/GetNetByName.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetNetByName Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetNetByName
+ FILE_GUID = DAF7B0E6-32DE-4619-B63A-2B9173A75B14
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetNetByName.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetServByName/GetServByName.c b/AppPkg/Applications/Sockets/GetServByName/GetServByName.c new file mode 100644 index 0000000000..d7237d342c --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByName/GetServByName.c @@ -0,0 +1,76 @@ +/** @file
+ Translate the service name into a port number
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+char mBuffer [65536];
+
+
+/**
+ Translate the service name into a port number
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+ int PortNumber;
+ struct servent * pService;
+
+ //
+ // Determine if the service name is specified
+ //
+ AppStatus = 0;
+ if ( 1 == Argc ) {
+ Print ( L"%a <service name>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the service name
+ //
+ pService = getservbyname ( Argv[1], NULL );
+ if ( NULL == pService ) {
+ Print ( L"ERROR - service not found, errno: %d\r\n", errno );
+ }
+ else {
+ PortNumber = htons ( pService->s_port );
+ Print ( L"%a: %d, %a\r\n",
+ pService->s_name,
+ PortNumber,
+ pService->s_proto );
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf b/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf new file mode 100644 index 0000000000..290d15e938 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByName/GetServByName.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetServByName Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetServByName
+ FILE_GUID = 5D1F3F9E-8CEE-4299-93C2-4C64EBB58977
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetServByName.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c new file mode 100644 index 0000000000..6a5fc46ea7 --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.c @@ -0,0 +1,77 @@ +/** @file
+ Translate the port number into a service name
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+char mBuffer [65536];
+
+
+/**
+ Translate the port number into a service name
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+ int PortNumber;
+ struct servent * pService;
+
+ //
+ // Determine if the service name is specified
+ //
+ AppStatus = 0;
+ if (( 2 != Argc )
+ || ( 1 != sscanf ( Argv[1], "%d", &PortNumber ))) {
+ Print ( L"%a <port number>\r\n", Argv[0]);
+ }
+ else {
+ //
+ // Translate the port number
+ //
+ pService = getservbyport ( htons ( PortNumber ), NULL );
+ if ( NULL == pService ) {
+ Print ( L"ERROR - service not found, errno: %d\r\n", errno );
+ }
+ else {
+ Print ( L"%a: %d, %a\r\n",
+ pService->s_name,
+ PortNumber,
+ pService->s_proto );
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf new file mode 100644 index 0000000000..1a232c0aad --- /dev/null +++ b/AppPkg/Applications/Sockets/GetServByPort/GetServByPort.inf @@ -0,0 +1,65 @@ +#/** @file
+# GetServByPort Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GetServByPort
+ FILE_GUID = 83381B06-2EEA-4cf3-9B5F-D75B9B5C93DE
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ GetServByPort.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ LibNetUtil
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c new file mode 100644 index 0000000000..7809e80ff8 --- /dev/null +++ b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.c @@ -0,0 +1,116 @@ +/** @file
+ Receive a datagram
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <netinet/in.h>
+
+#include <sys/socket.h>
+#include <sys/time.h>
+
+UINT8 mBuffer [ 65536 ];
+
+/**
+ Receive a datagram
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ struct sockaddr_in Address;
+ socklen_t AddressLength;
+ ssize_t LengthInBytes;
+ int s;
+ int Status;
+ struct timeval Timeout;
+
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Get the socket
+ //
+ s = socket ( AF_INET, SOCK_DGRAM, 0 );
+ if ( -1 == s ) {
+ Print ( L"ERROR - Unable to open the socket, errno: %d\r\n", errno );
+ }
+ else {
+ Timeout.tv_sec = 5;
+ Timeout.tv_usec = 0;
+ Status = setsockopt ( s,
+ SOL_SOCKET,
+ SO_RCVTIMEO,
+ &Timeout,
+ sizeof ( Timeout ));
+ if ( -1 == Status ) {
+ Print ( L"ERROR - Unable to set the receive timeout, errno: %d\r\n", errno );
+ }
+ else {
+ AddressLength = sizeof ( Address );
+ LengthInBytes = recvfrom ( s,
+ &mBuffer[0],
+ sizeof ( mBuffer[0]),
+ 0,
+ (struct sockaddr *)&Address,
+ &AddressLength );
+ if ( -1 == LengthInBytes ) {
+ if ( ETIMEDOUT == errno ) {
+ Print ( L"No datagram received\r\n" );
+ }
+ else {
+ Print ( L"ERROR - No datagram received, errno: %d\r\n", errno );
+ }
+ }
+ else {
+ Print ( L"Received %d bytes from %d.%d.%d.%d:%d\r\n",
+ LengthInBytes,
+ (UINT8)Address.sin_addr.s_addr,
+ (UINT8)( Address.sin_addr.s_addr >> 8 ),
+ (UINT8)( Address.sin_addr.s_addr >> 16 ),
+ (UINT8)( Address.sin_addr.s_addr >> 24 ),
+ htons ( Address.sin_port ));
+ }
+ }
+
+ //
+ // Done with the socket
+ //
+ close ( s );
+ }
+
+ //
+ // All done
+ //
+ DEBUG (( DEBUG_INFO,
+ "%a exiting, errno: %d\r\n",
+ Argv[0],
+ errno ));
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf new file mode 100644 index 0000000000..bef842ad54 --- /dev/null +++ b/AppPkg/Applications/Sockets/RecvDgram/RecvDgram.inf @@ -0,0 +1,64 @@ +#/** @file
+# Receive Datagram Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RecvDgram
+ FILE_GUID = 929189C9-0670-4c0b-AF7D-135D1550C8C0
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ RecvDgram.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/SetHostName/SetHostName.c b/AppPkg/Applications/Sockets/SetHostName/SetHostName.c new file mode 100644 index 0000000000..85dc1c43fe --- /dev/null +++ b/AppPkg/Applications/Sockets/SetHostName/SetHostName.c @@ -0,0 +1,100 @@ +/** @file
+ Set the host name
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+
+char mBuffer [65536];
+
+
+/**
+ Set the host name
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ int AppStatus;
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Determine if the host name is specified
+ //
+ AppStatus = 0;
+ if ( 1 < Argc ) {
+ //
+ // Set the host name
+ //
+ AppStatus = sethostname ( Argv[1], strlen ( Argv[1]));
+ if ( -1 == AppStatus ) {
+ switch ( errno ) {
+ default:
+ Print ( L"ERROR - errno: %d\r\n", errno );
+ break;
+
+ case ENODEV:
+ Print ( L"WARNING - Plarform does not support permanent storage!\r\n" );
+ break;
+
+ case ENOMEM:
+ Print ( L"ERROR - Insufficient storage to save host name!\r\n" );
+ break;
+
+ case ENOTSUP:
+ Print ( L"ERROR - Platform does not support environment variable storage!\r\n" );
+ break;
+ }
+ }
+ }
+ else {
+ //
+ // Display the current host name
+ //
+ AppStatus = gethostname ( &mBuffer[0], sizeof ( mBuffer ));
+ if ( -1 == AppStatus ) {
+ Print ( L"ERROR - Unable to get host name, errno: %d\r\n", errno );
+ }
+ else {
+ if ( 0 == mBuffer[0]) {
+ Print ( L"Host name is not set!\r\n" );
+ }
+ else {
+ Print ( L"Host name: %a", &mBuffer[0]);
+ }
+ }
+ }
+
+ //
+ // All done
+ //
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf b/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf new file mode 100644 index 0000000000..2b0bdc7914 --- /dev/null +++ b/AppPkg/Applications/Sockets/SetHostName/SetHostName.inf @@ -0,0 +1,64 @@ +#/** @file
+# SetHostName Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SetHostName
+ FILE_GUID = 4BC80B15-255D-4858-8072-51D6D98CF90E
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SetHostName.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c new file mode 100644 index 0000000000..fdc4552b60 --- /dev/null +++ b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c @@ -0,0 +1,379 @@ +/** @file
+ Set the socket options
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <Uefi.h>
+#include <unistd.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+
+#include <sys/socket.h>
+#include <sys/time.h>
+
+typedef enum _DATA_TYPE {
+ DATA_TYPE_UNKNOWN = 0,
+ DATA_TYPE_INT32_DECIMAL,
+ DATA_TYPE_SOCKET_TYPE,
+ DATA_TYPE_TIMEVAL
+} DATA_TYPE;
+
+typedef struct {
+ char * pOptionName;
+ int OptionValue;
+ int OptionLevel;
+ BOOLEAN bSetAllowed;
+ DATA_TYPE DataType;
+} OPTIONS;
+
+CONST OPTIONS mOptions [] = {
+ { "SO_ACCEPTCONN", SO_ACCEPTCONN, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN },
+ { "SO_BROADCAST", SO_BROADCAST, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_DEBUG", SO_DEBUG, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_DONTROUTE", SO_DONTROUTE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_ERROR", SO_ERROR, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN },
+ { "SO_KEEPALIVE", SO_KEEPALIVE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_OOBINLINE", SO_OOBINLINE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_OVERFLOWED", SO_OVERFLOWED, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_RCVBUF", SO_RCVBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL },
+ { "SO_RCVLOWAT", SO_RCVLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_RCVTIMEO", SO_RCVTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_TIMEVAL },
+ { "SO_REUSEADDR", SO_REUSEADDR, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_REUSEPORT", SO_REUSEPORT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_SNDBUF", SO_SNDBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL },
+ { "SO_SNDLOWAT", SO_SNDLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_SNDTIMEO", SO_SNDTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_TIMESTAMP", SO_TIMESTAMP, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
+ { "SO_TYPE", SO_TYPE, SOL_SOCKET, FALSE, DATA_TYPE_SOCKET_TYPE },
+ { "SO_USELOOPBACK", SO_USELOOPBACK, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }
+};
+
+
+UINT8 mBuffer [ 65536 ];
+UINT8 mValue [ 65536 ];
+char * mSocketType [] = {
+ "SOCK_STREAM",
+ "SOCK_DGRAM",
+ "SOCK_RAW",
+ "SOCK_RDM",
+ "SOCK_SEQPACKET"
+};
+
+void
+DisplayOption (
+ CONST OPTIONS * pOption,
+ socklen_t LengthInBytes,
+ BOOLEAN bDisplayUpdate,
+ BOOLEAN bDisplayCrLf
+ )
+{
+ UINT8 * pEnd;
+ char * pString;
+ union {
+ UINT8 * u8;
+ INT32 * i32;
+ struct timeval * TimeVal;
+ } Value;
+
+ //
+ // Display the value length
+ //
+ if ( !bDisplayUpdate ) {
+ Print ( L"LengthInBytes: %d\r\n", LengthInBytes );
+ Print ( L"%a: ", pOption->pOptionName );
+ }
+ else {
+ Print ( L" --> " );
+ }
+
+ //
+ // Display the value
+ //
+ Value.u8 = &mBuffer[0];
+ switch ( pOption->DataType )
+ {
+ case DATA_TYPE_UNKNOWN:
+ Print ( L"%a:", pOption->pOptionName );
+ pEnd = &Value.u8 [ LengthInBytes ];
+ while ( pEnd > Value.u8 ) {
+ Print ( L" %02x", *Value.u8 );
+ Value.u8 += 1;
+ }
+ break;
+
+ case DATA_TYPE_INT32_DECIMAL:
+ if ( 4 == LengthInBytes ) {
+ Print ( L"%d", *Value.i32 );
+ }
+ else {
+ errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
+ Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
+ }
+ break;
+
+ case DATA_TYPE_SOCKET_TYPE:
+ if ( 4 == LengthInBytes ) {
+ if (( SOCK_STREAM <= *Value.i32 ) && ( SOCK_SEQPACKET >= *Value.i32 )) {
+ pString = mSocketType [ *Value.i32 - SOCK_STREAM ];
+ Print ( L"%a", pString );
+ }
+ else {
+ Print ( L"%08x (unknown type)", *Value.i32 );
+ }
+ }
+ else {
+ errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
+ Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
+ }
+ break;
+
+ case DATA_TYPE_TIMEVAL:
+ if ( sizeof ( *Value.TimeVal ) == LengthInBytes ) {
+ if (( 0 == Value.TimeVal->tv_sec )
+ && ( 0 == Value.TimeVal->tv_usec )) {
+ Print ( L"Infinite" );
+ }
+ else {
+ Print ( L"%d.%06d sec",
+ Value.TimeVal->tv_sec,
+ Value.TimeVal->tv_usec );
+ }
+ }
+ else {
+ errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
+ Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
+ }
+ break;
+ }
+
+ //
+ // Terminate the line
+ //
+ if ( bDisplayCrLf ) {
+ Print ( L"\r\n" );
+ }
+}
+
+socklen_t
+GetOptionValue (
+ CONST OPTIONS * pOption,
+ char * pValue
+ )
+{
+ socklen_t BytesToWrite;
+ union {
+ UINT8 * u8;
+ INT32 * i32;
+ struct timeval * TimeVal;
+ } Value;
+ int Values;
+
+ //
+ // Assume failure
+ //
+ errno = EINVAL;
+ BytesToWrite = 0;
+
+ //
+ // Determine the type of parameter
+ //
+ if ( pOption->bSetAllowed ) {
+ Value.u8 = &mValue[0];
+ switch ( pOption->DataType ) {
+ case DATA_TYPE_INT32_DECIMAL:
+ Values = sscanf ( pValue, "%d", Value.i32 );
+ if ( 1 == Values ) {
+ BytesToWrite = sizeof ( *Value.i32);
+ errno = 0;
+ }
+ break;
+
+ case DATA_TYPE_TIMEVAL:
+ Values = sscanf ( pValue, "%d.%0d",
+ &Value.TimeVal->tv_sec,
+ &Value.TimeVal->tv_usec );
+ if (( 2 == Values )
+ && ( 0 <= Value.TimeVal->tv_sec )
+ && ( 0 <= Value.TimeVal->tv_usec )
+ && ( 1000000 > Value.TimeVal->tv_usec )){
+ BytesToWrite = sizeof ( *Value.TimeVal );
+ errno = 0;
+ }
+ }
+ }
+
+ //
+ // Display the error
+ //
+ if ( 0 == BytesToWrite ) {
+ Print ( L"ERROR - Invalid value!\r\n" );
+ }
+
+ //
+ // Return the number of bytes to be written
+ //
+ return BytesToWrite;
+}
+
+
+/**
+ Set the socket options
+
+ @param [in] Argc The number of arguments
+ @param [in] Argv The argument value array
+
+ @retval 0 The application exited normally.
+ @retval Other An error occurred.
+**/
+int
+main (
+ IN int Argc,
+ IN char **Argv
+ )
+{
+ socklen_t BytesToWrite;
+ socklen_t LengthInBytes;
+ CONST OPTIONS * pEnd;
+ CONST OPTIONS * pOption;
+ int s;
+ int Status;
+
+ DEBUG (( DEBUG_INFO,
+ "%a starting\r\n",
+ Argv[0]));
+
+ //
+ // Parse the socket option
+ //
+ pOption = &mOptions[0];
+ pEnd = &pOption[sizeof ( mOptions ) / sizeof ( mOptions[0])];
+ if ( 2 <= Argc ) {
+ while ( pEnd > pOption ) {
+ if ( 0 == strcmp ( Argv[1], pOption->pOptionName )) {
+ break;
+ }
+ pOption += 1;
+ }
+ if ( pEnd <= pOption ) {
+ Print ( L"ERROR: Invalid option: %a\r\n", Argv[1]);
+ Argc = 1;
+ }
+ }
+
+ //
+ // Display the help if necessary
+ //
+ if (( 2 > Argc ) || ( 3 < Argc )) {
+ Print ( L"%a <option>\r\n", Argv[0]);
+ Print ( L"\r\n" );
+ Print ( L"Option one of:\r\n" );
+ pOption = &mOptions[0];
+ while ( pEnd > pOption ) {
+ Print ( L" %a: %a\r\n",
+ pOption->pOptionName,
+ pOption->bSetAllowed ? "get/set" : "get" );
+ pOption += 1;
+ }
+ errno = EINVAL;
+ }
+ else {
+ //
+ // Determine if the value is to be set
+ //
+ BytesToWrite = 0;
+ if (( 3 > Argc )
+ || ( 0 < ( BytesToWrite = GetOptionValue ( pOption, Argv [2])))) {
+ //
+ // Get the socket
+ //
+ s = socket ( AF_INET, 0, 0 );
+ if ( -1 == s ) {
+ Print ( L"ERROR - Unable to open the socket, errno: %d\r\n", errno );
+ }
+ else {
+ //
+ // Display the option value
+ //
+ LengthInBytes = sizeof ( mBuffer );
+ Status = getsockopt ( s,
+ pOption->OptionLevel,
+ pOption->OptionValue,
+ &mBuffer,
+ &LengthInBytes );
+ if ( -1 == Status ) {
+ Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
+ }
+ else {
+ DisplayOption ( pOption,
+ LengthInBytes,
+ FALSE,
+ (BOOLEAN)( 0 == BytesToWrite ));
+
+ //
+ // Determine if the value is to be set
+ //
+ if (( 0 < BytesToWrite )
+ && ( BytesToWrite == LengthInBytes )) {
+ //
+ // Set the option value
+ //
+ Status = setsockopt ( s,
+ pOption->OptionLevel,
+ pOption->OptionValue,
+ &mValue,
+ BytesToWrite );
+ if ( -1 == Status ) {
+ Print ( L"ERROR - setsockopt failed, errno: %d\r\n", errno );
+ }
+ else {
+ //
+ // Display the updated option value
+ //
+ Status = getsockopt ( s,
+ pOption->OptionLevel,
+ pOption->OptionValue,
+ &mBuffer,
+ &LengthInBytes );
+ if ( -1 == Status ) {
+ Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
+ }
+ else {
+ DisplayOption ( pOption,
+ LengthInBytes,
+ TRUE,
+ TRUE );
+ }
+ }
+ }
+ }
+
+ //
+ // Done with the socket
+ //
+ close ( s );
+ }
+ }
+ }
+
+ //
+ // All done
+ //
+ DEBUG (( DEBUG_INFO,
+ "%a exiting, errno: %d\r\n",
+ Argv[0],
+ errno ));
+ return errno;
+}
diff --git a/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.inf b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.inf new file mode 100644 index 0000000000..835e1ebb61 --- /dev/null +++ b/AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.inf @@ -0,0 +1,64 @@ +#/** @file
+# SetHostName Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SetSockOpt
+ FILE_GUID = 6E851687-A7A9-4aa2-8DD0-673E03E51433
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SetSockOpt.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ LibMath
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/TftpServer/TftpServer.c b/AppPkg/Applications/Sockets/TftpServer/TftpServer.c new file mode 100644 index 0000000000..a1e19c26f9 --- /dev/null +++ b/AppPkg/Applications/Sockets/TftpServer/TftpServer.c @@ -0,0 +1,1527 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + This is a simple TFTP server application + +**/ + +#include <TftpServer.h> + +TSDT_TFTP_SERVER mTftpServer; ///< TFTP server's control structure + + +/** + Add a connection context to the list of connection contexts. + + @param [in] pTftpServer The TFTP server control structure address. + + @retval Context structure address, NULL if allocation fails + +**/ +TSDT_CONNECTION_CONTEXT * +ContextAdd ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + size_t LengthInBytes; + TSDT_CONNECTION_CONTEXT * pContext; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Allocate a new context + // + LengthInBytes = sizeof ( *pContext ); + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + LengthInBytes, + (VOID **)&pContext ); + if ( EFI_ERROR ( Status )) { + DEBUG (( DEBUG_ERROR | DEBUG_POOL, + "ERROR - Failed to allocate the context, Status: %r\r\n", + Status )); + pContext = NULL; + break; + } + + // + // Initialize the context + // + ZeroMem ( pContext, LengthInBytes ); + CopyMem ( &pContext->RemoteAddress, + &pTftpServer->RemoteAddress, + sizeof ( pContext->RemoteAddress )); + pContext->BlockSize = TFTP_MAX_BLOCK_SIZE; + pContext->pBuffer = &pContext->FileData[0]; + pContext->pEnd = &pContext->pBuffer[sizeof ( pContext->pBuffer )]; + pContext->MaxTransferSize = 0; + pContext->MaxTransferSize -= 1; + + // + // Display the new context + // + DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, + "0x%08x: Context for %d.%d.%d.%d:%d\r\n", + pContext, + (UINT8)pContext->RemoteAddress.sin_addr.s_addr, + (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 8 ), + (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 16 ), + (UINT8)( pContext->RemoteAddress.sin_addr.s_addr >> 24 ), + htons ( pContext->RemoteAddress.sin_port ))); + + // + // Add the context to the context list + // + pContext->pNext = pTftpServer->pContextList; + pTftpServer->pContextList = pContext; + + // + // All done + // + break; + } + + // + // Return the connection context + // + DBG_EXIT_STATUS ( pContext ); + return pContext; +} + + +/** + Locate a remote connection context. + + @param [in] pTftpServer The TFTP server control structure address. + + @param [in] pIpAddress The start of the remote IP address in network order + + @param [in] Port The remote port number + + @retval Context structure address, NULL if not found + +**/ +TSDT_CONNECTION_CONTEXT * +ContextFind ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + TSDT_CONNECTION_CONTEXT * pContext; + + DBG_ENTER ( ); + + // + // Walk the list of connection contexts + // + pContext = pTftpServer->pContextList; + while ( NULL != pContext ) { + // + // Attempt to locate the remote network connection + // + if (( pTftpServer->RemoteAddress.sin_addr.s_addr == pContext->RemoteAddress.sin_addr.s_addr ) + && ( pTftpServer->RemoteAddress.sin_port == pContext->RemoteAddress.sin_port )) { + // + // The connection was found + // + DEBUG (( DEBUG_TFTP_REQUEST, + "0x%08x: pContext found\r\n", + pContext )); + break; + } + + // + // Set the next context + // + pContext = pContext->pNext; + } + + // + // Return the connection context structure address + // + DBG_EXIT_HEX ( pContext ); + return pContext; +} + + +/** + Remove a context from the list. + + @param [in] pTftpServer The TFTP server control structure address. + + @param [in] pContext The context structure address. + +**/ +VOID +ContextRemove ( + IN TSDT_TFTP_SERVER * pTftpServer, + IN TSDT_CONNECTION_CONTEXT * pContext + ) +{ + TSDT_CONNECTION_CONTEXT * pNextContext; + TSDT_CONNECTION_CONTEXT * pPreviousContext; + + DBG_ENTER ( ); + + // + // Attempt to locate the context in the list + // + pPreviousContext = NULL; + pNextContext = pTftpServer->pContextList; + while ( NULL != pNextContext ) { + // + // Determine if the context was found + // + if ( pNextContext == pContext ) { + // + // Remove the context from the list + // + if ( NULL == pPreviousContext ) { + pTftpServer->pContextList = pContext->pNext; + } + else { + pPreviousContext->pNext = pContext->pNext; + } + break; + } + + // + // Set the next context + // + pPreviousContext = pNextContext; + pNextContext = pNextContext->pNext; + } + + // + // Determine if the context was found + // + if ( NULL != pContext ) { + // + // Return the resources + // + gBS->FreePool ( pContext ); + } + + DBG_EXIT ( ); +} + + +/** + Process the work for the sockets. + + @param [in] pTftpServer The TFTP server control structure address. + +**/ +VOID +PortWork ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + TSDT_CONNECTION_CONTEXT * pContext; + socklen_t RemoteAddressLength; + + DBG_ENTER ( ); + + // + // Handle input events + // + if ( 0 != ( pTftpServer->TftpPort.revents & POLLRDNORM )) { + // + // Receive the message from the remote system + // + RemoteAddressLength = sizeof ( pTftpServer->RemoteAddress ); + pTftpServer->RxBytes = recvfrom ( pTftpServer->TftpPort.fd, + &pTftpServer->RxBuffer[0], + sizeof ( pTftpServer->RxBuffer ), + 0, + (struct sockaddr *) &pTftpServer->RemoteAddress, + &RemoteAddressLength ); + if ( -1 != pTftpServer->RxBytes ) { + pTftpServer->RemoteAddress.sin_len = (UINT8) RemoteAddressLength; + DEBUG (( DEBUG_TFTP_PORT, + "Received %d bytes from %d.%d.%d.%d:%d\r\n", + pTftpServer->RxBytes, + pTftpServer->RemoteAddress.sin_addr.s_addr & 0xff, + ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ) & 0xff, + ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ) & 0xff, + ( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ) & 0xff, + htons ( pTftpServer->RemoteAddress.sin_port ))); + + // + // Lookup connection context using the remote system address and port + // to determine if an existing connection to this remote + // system exists + // + pContext = ContextFind ( pTftpServer ); + + // + // Process the received message + // + TftpProcessRequest ( pTftpServer, pContext ); + } + else { + // + // Receive error on the TFTP server port + // Close the server socket + // + DEBUG (( DEBUG_ERROR, + "ERROR - Failed receive on TFTP server port, errno: 0x%08x\r\n", + errno )); + pTftpServer->TftpPort.revents |= POLLHUP; + } + } + + // + // Handle the close event + // + if ( 0 != ( pTftpServer->TftpPort.revents & POLLHUP )) { + // + // Close the port + // + close ( pTftpServer->TftpPort.fd ); + pTftpServer->TftpPort.fd = -1; + } + + DBG_EXIT ( ); +} + + +/** + Scan the list of sockets and process any pending work + + @param [in] pTftpServer The TFTP server control structure address. + +**/ +VOID +SocketPoll ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + int FDCount; + + DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" )); + + // + // Determine if any ports are active + // + FDCount = poll ( &pTftpServer->TftpPort, + 1, + CLIENT_POLL_DELAY ); + if ( -1 == FDCount ) { + DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL, + "ERROR - errno: %d\r\n", + errno )); + } + + if ( 0 < FDCount ) { + // + // Process this port + // + PortWork ( pTftpServer ); + pTftpServer->TftpPort.revents = 0; + } + + DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" )); +} + + +/** + Convert a character to lower case + + @param [in] Character The character to convert + + @returns The lower case equivalent of the character + +**/ +int +tolower ( + int Character + ) +{ + // + // Determine if the character is upper case + // + if (( 'A' <= Character ) && ( 'Z' >= Character )) { + // + // Convert the character to lower caes + // + Character += 'a' - 'A'; + } + + // + // Return the converted character + // + return Character; +} + + +/** + Case independent string comparison + + @param [in] pString1 Zero terminated string address + @param [in] pString2 Zero terminated string address + + @returns Returns the first character difference between string 1 + and string 2. + +**/ +int +stricmp ( + char * pString1, + char * pString2 + ) +{ + int Char1; + int Char2; + int Difference; + + // + // Walk the length of the strings + // + do { + // + // Get the next characters + // + Char1 = (UINT8)*pString1++; + Char2 = (UINT8)*pString2++; + + // + // Convert them to lower case + // + Char1 = tolower ( Char1 ); + Char2 = tolower ( Char2 ); + + // + // Done when the characters differ + // + Difference = Char1 - Char2; + if ( 0 != Difference ) { + break; + } + + // + // Done at the end of the string + // + } while ( 0 != Char1 ); + + // + // Return the difference + // + return Difference; +} + + +/** + Get the next TFTP option + + @param [in] pOption Address of a zero terminated option string + @param [in] pEnd End of buffer address + @param [in] ppNextOption Address to receive the address of the next + zero terminated option string + + @retval EFI_SUCCESS Message processed successfully + +**/ +EFI_STATUS +TftpOptionGet ( + IN UINT8 * pOption, + IN UINT8 * pEnd, + IN UINT8 ** ppNextOption + ) +{ + UINT8 * pNextOption; + EFI_STATUS Status; + + // + // Locate the end of the option + // + pNextOption = pOption; + while (( pEnd > pNextOption ) && ( 0 != *pNextOption )) { + pNextOption += 1; + } + if ( pEnd <= pNextOption ) { + // + // Error - end of buffer reached + // + DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, + "ERROR - Option without zero termination received!\r\n" )); + Status = EFI_INVALID_PARAMETER; + } + else { + // + // Zero terminated option found + // + pNextOption += 1; + + // + // Display the zero terminated ASCII option string + // + DEBUG (( DEBUG_TFTP_REQUEST, + "Option: %a\r\n", + pOption )); + Status = EFI_SUCCESS; + } + + // + // Return the next option address + // + *ppNextOption = pNextOption; + + // + // Return the operation status + // + return Status; +} + + +/** + Place an option value into the option acknowledgement + + @param [in] pOack Option acknowledgement address + @param [in] Value Value to translate into ASCII decimal + + @returns Option acknowledgement address + +**/ +UINT8 * +TftpOptionSet ( + IN UINT8 * pOack, + IN UINT64 Value + ) +{ + UINT64 NextValue; + + // + // Determine the next value + // + NextValue = Value / 10; + + // + // Supress leading zeros + // + if ( 0 != NextValue ) { + pOack = TftpOptionSet ( pOack, NextValue ); + } + + // + // Output this digit + // + *pOack++ = (UINT8)( Value - ( NextValue * 10 ) + '0' ); + + // + // Return the next option acknowledgement location + // + return pOack; +} + + +/** + Process the TFTP request + + @param [in] pContext The context structure address. + @param [in] pOption Address of the first zero terminated option string + @param [in] pEnd End of buffer address + +**/ +VOID +TftpOptions ( + IN TSDT_CONNECTION_CONTEXT * pContext, + IN UINT8 * pOption, + IN UINT8 * pEnd + ) +{ + UINT8 * pNextOption; + UINT8 * pOack; + UINT8 * pTemp; + UINT8 * pValue; + EFI_STATUS Status; + INT32 Value; + + // + // Start the OACK packet + // Let the OACK handle the parsing errors + // See http://tools.ietf.org/html/rfc2347 + // + pOack = &pContext->TxBuffer[0]; + *pOack++ = 0; + *pOack++ = TFTP_OP_OACK; + pContext->TxBytes = 2; + + // + // Walk the list of options + // + do { + // + // Get the next option, skip junk at end of message + // + Status = TftpOptionGet ( pOption, pEnd, &pNextOption ); + if ( !EFI_ERROR ( Status )) { + // + // Process the option + // + + // + // blksize - See http://tools.ietf.org/html/rfc2348 + // + pValue = pNextOption; + if ( 0 == stricmp ((char *)pOption, "blksize" )) { + // + // Get the value + // + Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); + if ( !EFI_ERROR ( Status )) { + // + // Validate the block size, skip non-numeric block sizes + // + Status = TftpOptionValue ( pValue, &Value ); + if ( !EFI_ERROR ( Status )) { + // + // Propose a smaller block size if necessary + // + if ( Value > TFTP_MAX_BLOCK_SIZE ) { + Value = TFTP_MAX_BLOCK_SIZE; + } + + // + // Set the new block size + // + pContext->BlockSize = Value; + DEBUG (( DEBUG_TFTP_REQUEST, + "Using block size of %d bytes\r\n", + pContext->BlockSize )); + + // + // Update the OACK + // + pTemp = pOack; + *pOack++ = 'b'; + *pOack++ = 'l'; + *pOack++ = 'k'; + *pOack++ = 's'; + *pOack++ = 'i'; + *pOack++ = 'z'; + *pOack++ = 'e'; + *pOack++ = 0; + pOack = TftpOptionSet ( pOack, pContext->BlockSize ); + *pOack++ = 0; + pContext->TxBytes += pOack - pTemp; + } + } + } + + // + // timeout - See http://tools.ietf.org/html/rfc2349 + // + else if ( 0 == stricmp ((char *)pOption, "timeout" )) { + // + // Get the value + // + Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); + if ( !EFI_ERROR ( Status )) { + Status = TftpOptionValue ( pValue, &Value ); + if ( !EFI_ERROR ( Status )) { + // + // Set the timeout value + // + pContext->Timeout = Value; + DEBUG (( DEBUG_TFTP_REQUEST, + "Using timeout of %d seconds\r\n", + pContext->Timeout )); + + // + // Update the OACK + // + pTemp = pOack; + *pOack++ = 't'; + *pOack++ = 'i'; + *pOack++ = 'm'; + *pOack++ = 'e'; + *pOack++ = 'o'; + *pOack++ = 'u'; + *pOack++ = 't'; + *pOack++ = 0; + pOack = TftpOptionSet ( pOack, pContext->Timeout ); + *pOack++ = 0; + pContext->TxBytes += pOack - pTemp; + } + } + } + + // + // tsize - See http://tools.ietf.org/html/rfc2349 + // + else if ( 0 == stricmp ((char *)pOption, "tsize" )) { + // + // Get the value + // + Status = TftpOptionGet ( pValue, pEnd, &pNextOption ); + if ( !EFI_ERROR ( Status )) { + Status = TftpOptionValue ( pValue, &Value ); + if ( !EFI_ERROR ( Status )) { + // + // Return the file size + // + DEBUG (( DEBUG_TFTP_REQUEST, + "Returning file size of %Ld bytes\r\n", + pContext->LengthInBytes )); + + // + // Update the OACK + // + pTemp = pOack; + *pOack++ = 't'; + *pOack++ = 's'; + *pOack++ = 'i'; + *pOack++ = 'z'; + *pOack++ = 'e'; + *pOack++ = 0; + pOack = TftpOptionSet ( pOack, pContext->LengthInBytes ); + *pOack++ = 0; + pContext->TxBytes += pOack - pTemp; + } + } + } + else { + // + // Unknown option - Ignore it + // + DEBUG (( DEBUG_WARN | DEBUG_TFTP_REQUEST, + "WARNING - Skipping unknown option: %a\r\n", + pOption )); + } + } + + // + // Set the next option + // + pOption = pNextOption; + } while ( pEnd > pOption ); +} + + +/** + Process the TFTP request + + @param [in] pOption Address of the first zero terminated option string + @param [in] pValue Address to receive the value + + @retval EFI_SUCCESS Option translated into a value + +**/ +EFI_STATUS +TftpOptionValue ( + IN UINT8 * pOption, + IN INT32 * pValue + ) +{ + UINT8 Digit; + EFI_STATUS Status; + INT32 Value; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the characters in the option + // + Value = 0; + while ( 0 != *pOption ) { + // + // Convert the next digit to binary + // + Digit = *pOption++; + if (( '0' <= Digit ) && ( '9' >= Digit )) { + Value *= 10; + Value += Digit - '0'; + } + else { + DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, + "ERROR - Invalid character '0x%02x' in the value\r\n", + Digit )); + Status = EFI_INVALID_PARAMETER; + break; + } + } + + // + // Return the value + // + *pValue = Value; + + // + // Return the conversion status + // + return Status; +} + + +/** + Process the TFTP request + + @param [in] pTftpServer The TFTP server control structure address. + @param [in] pContext Connection context structure address + +**/ +VOID +TftpProcessRequest ( + IN TSDT_TFTP_SERVER * pTftpServer, + IN TSDT_CONNECTION_CONTEXT * pContext + ) +{ + BOOLEAN bCloseContext; + BOOLEAN bIgnorePacket; + UINT16 BlockNumber; + UINT16 Opcode; + UINT8 * pBuffer; + UINT8 * pEnd; + UINT8 * pFileName; + UINT8 * pMode; + UINT8 * pOption; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Get the opcode + // + pBuffer = &pTftpServer->RxBuffer[0]; + Opcode = HTONS ( *(UINT16 *)&pBuffer[0]); +Print ( L"TFTP Opcode: 0x%08x\r\n", Opcode ); + + // + // Validate the parameters + // + bCloseContext = FALSE; + bIgnorePacket = FALSE; + switch ( Opcode ) { + default: + DEBUG (( DEBUG_TFTP_REQUEST, + "ERROR - Unknown TFTP opcode: %d\r\n", + Opcode )); + bIgnorePacket = TRUE; + break; + + case TFTP_OP_READ_REQUEST: + break; + + case TFTP_OP_DATA: + if ( NULL == pContext ) { + DEBUG (( DEBUG_ERROR, + "ERROR - File not open for %d.%d.%d.%d:%d\r\n", + (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), + htons ( pTftpServer->RemoteAddress.sin_port ))); + bIgnorePacket = TRUE; + break; + } + if ( pContext->bExpectAck ) { + DEBUG (( DEBUG_ERROR, + "ERROR - Expecting ACKs not data for pContext 0x%08x\r\n", + pContext )); + bIgnorePacket = TRUE; + break; + } + if ( pTftpServer->RxBytes > (ssize_t)( pContext->BlockSize + 2 + 2 )) + { + DEBUG (( DEBUG_ERROR, + "ERROR - Receive data length of %d > %d bytes (maximum block size) for pContext 0x%08x\r\n", + pTftpServer->RxBytes - 2 - 2, + pContext->BlockSize, + pContext )); + bIgnorePacket = TRUE; + break; + } + break; + + case TFTP_OP_ACK: + if ( NULL == pContext ) { + DEBUG (( DEBUG_ERROR, + "ERROR - File not open for %d.%d.%d.%d:%d\r\n", + (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), + htons ( pTftpServer->RemoteAddress.sin_port ))); + bIgnorePacket = TRUE; + } + if ( !pContext->bExpectAck ) { + DEBUG (( DEBUG_ERROR, + "ERROR - Expecting data not ACKs for pContext 0x%08x\r\n", + pContext )); + bIgnorePacket = TRUE; + break; + } + break; + + case TFTP_OP_ERROR: + if ( NULL == pContext ) { + DEBUG (( DEBUG_ERROR, + "ERROR - File not open for %d.%d.%d.%d:%d\r\n", + (UINT8)pTftpServer->RemoteAddress.sin_addr.s_addr, + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 8 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 16 ), + (UINT8)( pTftpServer->RemoteAddress.sin_addr.s_addr >> 24 ), + htons ( pTftpServer->RemoteAddress.sin_port ))); + bIgnorePacket = TRUE; + } + break; + } + if ( !bIgnorePacket ) { + // + // Process the request + // + switch ( Opcode ) { + default: + DEBUG (( DEBUG_TFTP_REQUEST, + "ERROR - Unable to process TFTP opcode: %d\r\n", + Opcode )); + break; + + case TFTP_OP_READ_REQUEST: + + // + // Close the context if necessary + // + if ( NULL != pContext ) { + ContextRemove ( pTftpServer, pContext ); + } + + // + // Create the connection context + // + pContext = ContextAdd ( pTftpServer ); + if ( NULL == pContext ) { + break; + } + + // + // Locate the mode + // + pFileName = &pBuffer[2]; + pEnd = &pBuffer[pTftpServer->RxBytes]; + pMode = pFileName; + while (( pEnd > pMode ) && ( 0 != *pMode )) { + pMode += 1; + } + if ( pEnd <= pMode ) { + // + // Mode not found + // + DEBUG (( DEBUG_ERROR | DEBUG_RX, + "ERROR - File mode not found\r\n" )); + // + // Tell the client of the error + // + TftpSendError ( pTftpServer, + pContext, + 0, + (UINT8 *)"File open mode not found" ); + break; + } + pMode += 1; + DEBUG (( DEBUG_TFTP_REQUEST, + "TFTP - FileName: %a\n", + pFileName )); + + // + // Locate the options + // + pOption = pMode; + while (( pEnd > pOption ) && ( 0 != *pOption )) { + pOption += 1; + } + if ( pEnd <= pOption ) { + // + // End of mode not found + // + DEBUG (( DEBUG_ERROR | DEBUG_RX, + "ERROR - File mode not valid\r\n" )); + // + // Tell the client of the error + // + TftpSendError ( pTftpServer, + pContext, + 0, + (UINT8 *)"File open mode not valid" ); + break; + } + pOption += 1; + DEBUG (( DEBUG_TFTP_REQUEST, + "TFTP - Mode: %a\r\n", + pMode )); + + // + // Verify the mode is supported + // + if ( 0 != stricmp ((char *)pMode, "octet" )) { + // + // File access mode not supported + // + DEBUG (( DEBUG_ERROR | DEBUG_TFTP_REQUEST, + "ERROR - File mode %a not supported\r\n", + pMode )); + + // + // Tell the client of the error + // + TftpSendError ( pTftpServer, + pContext, + 0, + (UINT8 *)"File open mode not supported" ); + break; + } + + // + // Open the file, close the context on error + // +// TODO: Remove the following line +pContext->File = (EFI_HANDLE)1; + + // + // Determine the file length + // +//fstat + + // + // Process the options + // + TftpOptions ( pContext, pOption, pEnd ); + + // + // Read in the first portion of the file + // + + // + // Send the first block + // + pContext->bExpectAck = TRUE; + if ( 2 < pContext->TxBytes ) { + // + // Send the OACK + // + Status = TftpTxPacket ( pTftpServer, pContext ); + } + else { + // + // Send the first block of data + // + Status = TftpSendNextBlock ( pTftpServer, pContext ); + } + break; + + case TFTP_OP_ACK: + // + // Get the block number that is being ACKed + // + BlockNumber = pTftpServer->RxBuffer[2]; + BlockNumber <<= 8; + BlockNumber |= pTftpServer->RxBuffer[3]; + + // + // Determine if this is the correct ACK + // + DEBUG (( DEBUG_TFTP_ACK, + "ACK for block 0x%04x received\r\n", + BlockNumber )); + if (( !pContext->bExpectAck ) + || ( BlockNumber != pContext->AckNext )) + { + DEBUG (( DEBUG_WARN | DEBUG_TFTP_ACK, + "WARNING - Expecting ACK 0x%0x4 not received ACK 0x%08x\r\n", + pContext->AckNext, + BlockNumber )); + } + else { + // + // Process the expected ACK + // + if ( pContext->bEofSent ) { + bCloseContext = TRUE; + } + else { + // + // Set the next expected ACK + // + pContext->AckNext += 1; + + // + // Send the next packet of data + // + Status = TftpSendNextBlock ( pTftpServer, pContext ); + } + } + break; + } + } + + // + // Determine if the context should be closed + // + if ( bCloseContext ) { + ContextRemove ( pTftpServer, pContext ); + } + + DBG_EXIT ( ); +} + + +/** + Build and send an error packet + + @param [in] pTftpServer The TFTP server control structure address. + @param [in] pContext The context structure address. + @param [in] Error Error number for the packet + @param [in] pError Zero terminated error string address + + @retval EFI_SUCCESS Message processed successfully + +**/ +EFI_STATUS +TftpSendError ( + IN TSDT_TFTP_SERVER * pTftpServer, + IN TSDT_CONNECTION_CONTEXT * pContext, + IN UINT16 Error, + IN UINT8 * pError + ) +{ + UINT8 Character; + UINT8 * pBuffer; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Build the error packet + // + pBuffer = &pContext->TxBuffer[0]; + pBuffer[0] = 0; + pBuffer[1] = TFTP_OP_ERROR; + pBuffer[2] = (UINT8)( Error >> 8 ); + pBuffer[3] = (UINT8)Error; + + // + // Copy the zero terminated string into the buffer + // + pBuffer += 4; + do { + Character = *pError++; + *pBuffer++ = Character; + } while ( 0 != Character ); + + // + // Send the error message + // + pContext->TxBytes = pBuffer - &pContext->TxBuffer[0]; + Status = TftpTxPacket ( pTftpServer, pContext ); + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Send the next block of file system data + + @param [in] pTftpServer The TFTP server control structure address. + @param [in] pContext The context structure address. + + @retval EFI_SUCCESS Message processed successfully + +**/ +EFI_STATUS +TftpSendNextBlock ( + IN TSDT_TFTP_SERVER * pTftpServer, + IN TSDT_CONNECTION_CONTEXT * pContext + ) +{ + ssize_t LengthInBytes; + UINT8 * pBuffer; + EFI_STATUS Status; + + // + // Determine how much data needs to be sent + // + LengthInBytes = pContext->BlockSize; + if (( pContext->LengthInBytes < TFTP_MAX_BLOCK_SIZE ) + || ( LengthInBytes > (ssize_t)pContext->LengthInBytes )) { + LengthInBytes = (ssize_t)pContext->LengthInBytes; + pContext->bEofSent = TRUE; + } + + // + // Set the TFTP opcode and block number + // + pBuffer = &pContext->TxBuffer[0]; + *pBuffer++ = 0; + *pBuffer++ = TFTP_OP_DATA; + *pBuffer++ = (UINT8)( pContext->AckNext >> 8 ); + *pBuffer++ = (UINT8)pContext->AckNext; + + // + // Copy the file data into the transmit buffer + // + pContext->TxBytes = 2 + 2 + LengthInBytes; + if ( 0 < LengthInBytes ) { + CopyMem ( &pBuffer, + pContext->pBuffer, + LengthInBytes ); + } + + // + // Send the next block + // + Status = TftpTxPacket ( pTftpServer, pContext ); + + // + // Return the operation status + // + return Status; +} + + +/** + Create the port for the TFTP server + + This routine polls the network layer to create the TFTP port for the + TFTP server. More than one attempt may be necessary since it may take + some time to get the IP address and initialize the upper layers of + the network stack. + + @param [in] pTftpServer The TFTP server control structure address. + +**/ +VOID +TftpServerTimer ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + UINT16 TftpPort; + int SocketStatus; + EFI_STATUS Status; + + DEBUG (( DEBUG_SERVER_TIMER, "Entering TftpServerTimer\r\n" )); + + // + // Open the TFTP port on the server + // + do { + do { + // + // Wait for a while + // + Status = gBS->CheckEvent ( pTftpServer->TimerEvent ); + } while ( EFI_SUCCESS != Status ); + + // + // Attempt to create the socket for the TFTP server + // + pTftpServer->TftpPort.events = POLLRDNORM | POLLHUP; + pTftpServer->TftpPort.revents = 0; + pTftpServer->TftpPort.fd = socket ( AF_INET, + SOCK_DGRAM, + IPPROTO_UDP ); + if ( -1 != pTftpServer->TftpPort.fd ) + { + // + // Set the socket address + // + ZeroMem ( &pTftpServer->TftpServerAddress, + sizeof ( pTftpServer->TftpServerAddress )); + TftpPort = 69; + DEBUG (( DEBUG_TFTP_PORT, + "TFTP Port: %d\r\n", + TftpPort )); + pTftpServer->TftpServerAddress.sin_len = sizeof ( pTftpServer->TftpServerAddress ); + pTftpServer->TftpServerAddress.sin_family = AF_INET; + pTftpServer->TftpServerAddress.sin_addr.s_addr = INADDR_ANY; + pTftpServer->TftpServerAddress.sin_port = htons ( TftpPort ); + + // + // Bind the socket to the TFTP port + // + SocketStatus = bind ( pTftpServer->TftpPort.fd, + (struct sockaddr *) &pTftpServer->TftpServerAddress, + pTftpServer->TftpServerAddress.sin_len ); + if ( -1 != SocketStatus ) { + DEBUG (( DEBUG_TFTP_PORT, + "0x%08x: Socket bound to port %d\r\n", + pTftpServer->TftpPort.fd, + TftpPort )); + } + + // + // Release the socket if necessary + // + if ( -1 == SocketStatus ) { + close ( pTftpServer->TftpPort.fd ); + pTftpServer->TftpPort.fd = -1; + } + } + + // + // Wait until the socket is open + // + }while ( -1 == pTftpServer->TftpPort.fd ); + + DEBUG (( DEBUG_SERVER_TIMER, "Exiting TftpServerTimer\r\n" )); +} + + +/** + Start the TFTP server port creation timer + + @param [in] pTftpServer The TFTP server control structure address. + + @retval EFI_SUCCESS The timer was successfully started. + @retval EFI_ALREADY_STARTED The timer is already running. + @retval Other The timer failed to start. + +**/ +EFI_STATUS +TftpServerTimerStart ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + EFI_STATUS Status; + UINT64 TriggerTime; + + DBG_ENTER ( ); + + // + // Assume the timer is already running + // + Status = EFI_ALREADY_STARTED; + if ( !pTftpServer->bTimerRunning ) { + // + // Compute the poll interval + // + TriggerTime = TFTP_PORT_POLL_DELAY * ( 1000 * 10 ); + Status = gBS->SetTimer ( pTftpServer->TimerEvent, + TimerPeriodic, + TriggerTime ); + if ( !EFI_ERROR ( Status )) { + DEBUG (( DEBUG_TFTP_PORT, "TFTP port timer started\r\n" )); + + // + // Mark the timer running + // + pTftpServer->bTimerRunning = TRUE; + } + else { + DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT, + "ERROR - Failed to start TFTP port timer, Status: %r\r\n", + Status )); + } + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Stop the TFTP server port creation timer + + @param [in] pTftpServer The TFTP server control structure address. + + @retval EFI_SUCCESS The TFTP port timer is stopped + @retval Other Failed to stop the TFTP port timer + +**/ +EFI_STATUS +TftpServerTimerStop ( + IN TSDT_TFTP_SERVER * pTftpServer + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Assume the timer is stopped + // + Status = EFI_SUCCESS; + if ( pTftpServer->bTimerRunning ) { + // + // Stop the port creation polling + // + Status = gBS->SetTimer ( pTftpServer->TimerEvent, + TimerCancel, + 0 ); + if ( !EFI_ERROR ( Status )) { + DEBUG (( DEBUG_TFTP_PORT, "TFT[ port timer stopped\r\n" )); + + // + // Mark the timer stopped + // + pTftpServer->bTimerRunning = FALSE; + } + else { + DEBUG (( DEBUG_ERROR | DEBUG_TFTP_PORT, + "ERROR - Failed to stop TFT[ port timer, Status: %r\r\n", + Status )); + } + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + +/** + Send the next TFTP packet + + @param [in] pTftpServer The TFTP server control structure address. + @param [in] pContext The context structure address. + + @retval EFI_SUCCESS Message processed successfully + +**/ +EFI_STATUS +TftpTxPacket ( + IN TSDT_TFTP_SERVER * pTftpServer, + IN TSDT_CONNECTION_CONTEXT * pContext + ) +{ + ssize_t LengthInBytes; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Send the TFTP packet + // + DEBUG (( DEBUG_TX, + "0x%08x: pContext sending 0x%08x bytes\r\n", + pContext, + pContext->TxBytes )); + LengthInBytes = sendto ( pTftpServer->TftpPort.fd, + &pContext->TxBuffer[0], + pContext->TxBytes, + 0, + (struct sockaddr *)&pContext->RemoteAddress, + pContext->RemoteAddress.sin_len ); + if ( -1 == LengthInBytes ) { + DEBUG (( DEBUG_ERROR | DEBUG_TX, + "ERROR - Transmit failure, errno: 0x%08x\r\n", + errno )); + Status = EFI_DEVICE_ERROR; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Entry point for the TFTP server application. + + @param [in] Argc The number of arguments + @param [in] Argv The argument value array + + @retval 0 The application exited normally. + @retval Other An error occurred. +**/ +int +main ( + IN int Argc, + IN char **Argv + ) +{ + TSDT_TFTP_SERVER * pTftpServer; + EFI_STATUS Status; + + // + // Create a timer event to start TFTP port + // + pTftpServer = &mTftpServer; + Status = gBS->CreateEvent ( EVT_TIMER, + TPL_TFTP_SERVER, + NULL, + NULL, + &pTftpServer->TimerEvent ); + if ( !EFI_ERROR ( Status )) { + Status = TftpServerTimerStart ( pTftpServer ); + if ( !EFI_ERROR ( Status )) { + // + // Run the TFTP server forever + // + for ( ; ; ) { + // + // Poll the network layer to create the TFTP port + // for the tftp server. More than one attempt may + // be necessary since it may take some time to get + // the IP address and initialize the upper layers + // of the network stack. + // + TftpServerTimer ( pTftpServer ); + + // + // Poll the socket for activity + // + do { + SocketPoll ( pTftpServer ); + } while ( -1 != pTftpServer->TftpPort.fd ); + +// +// TODO: Remove the following test code +// Exit when the network connection is broken +// +break; + } + + // + // Done with the timer event + // + TftpServerTimerStop ( pTftpServer ); + Status = gBS->CloseEvent ( pTftpServer->TimerEvent ); + } + } + + // + // Return the final status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/TftpServer/TftpServer.h b/AppPkg/Applications/Sockets/TftpServer/TftpServer.h new file mode 100644 index 0000000000..e56d21be78 --- /dev/null +++ b/AppPkg/Applications/Sockets/TftpServer/TftpServer.h @@ -0,0 +1,331 @@ +/** @file
+ Definitions for the TFTP server.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TFTP_SERVER_H_
+#define _TFTP_SERVER_H_
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <Uefi.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/BlockIo.h>
+
+#include <netinet/in.h>
+
+#include <sys/EfiSysCall.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */
+#define DBG_ENTER() DEBUG (( DEBUG_INFO, "Entering " __FUNCTION__ "\n" )) ///< Display routine entry
+#define DBG_EXIT() DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ "\n" )) ///< Display routine exit
+#define DBG_EXIT_DEC(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %d\n", Status )) ///< Display routine exit with decimal value
+#define DBG_EXIT_HEX(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status )) ///< Display routine exit with hex value
+#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %r\n", Status )) ///< Display routine exit with status value
+#define DBG_EXIT_TF(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" )) ///< Display routine with TRUE/FALSE value
+#else // _MSC_VER
+#define DBG_ENTER()
+#define DBG_EXIT()
+#define DBG_EXIT_DEC(Status)
+#define DBG_EXIT_HEX(Status)
+#define DBG_EXIT_STATUS(Status)
+#define DBG_EXIT_TF(Status)
+#endif // _MSC_VER
+
+#define DIM(x) ( sizeof ( x ) / sizeof ( x[0] )) ///< Compute the number of entries in an array
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+#define DEBUG_SOCKET_POLL 0x40000000 ///< Display the socket poll messages
+#define DEBUG_PORT_WORK 0x20000000 ///< Display the port work messages
+#define DEBUG_SERVER_TIMER 0x10000000 ///< Display the socket poll messages
+#define DEBUG_TFTP_PORT 0x08000000 ///< Display the TFTP port messages
+#define DEBUG_TFTP_REQUEST 0x04000000 ///< Display the TFTP request messages
+#define DEBUG_TX 0x02000000 ///< Display transmit messages
+#define DEBUG_RX 0x01000000 ///< Display receive messages
+#define DEBUG_TFTP_ACK 0x00800000 ///< Display the TFTP ACK messages
+
+#define TFTP_PORT_POLL_DELAY ( 2 * 1000 ) ///< Delay in milliseconds for attempts to open the TFTP port
+#define CLIENT_POLL_DELAY 50 ///< Delay in milliseconds between client polls
+
+#define TPL_TFTP_SERVER TPL_CALLBACK ///< TPL for routine synchronization
+
+/**
+ Verify new TPL value
+
+ This macro which is enabled when debug is enabled verifies that
+ the new TPL value is >= the current TPL value.
+**/
+#ifdef VERIFY_TPL
+#undef VERIFY_TPL
+#endif // VERIFY_TPL
+
+#if !defined(MDEPKG_NDEBUG)
+
+#define VERIFY_TPL(tpl) \
+{ \
+ EFI_TPL PreviousTpl; \
+ \
+ PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \
+ gBS->RestoreTPL ( PreviousTpl ); \
+ if ( PreviousTpl > tpl ) { \
+ DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl )); \
+ ASSERT ( PreviousTpl <= tpl ); \
+ } \
+}
+
+#else // MDEPKG_NDEBUG
+
+#define VERIFY_TPL(tpl)
+
+#endif // MDEPKG_NDEBUG
+
+#define TFTP_SERVER_SIGNATURE SIGNATURE_32('T','F','T','P') ///< TSDT_TFTP_SERVER memory signature
+
+//
+// See: http://www.rfc-editor.org/rfc/pdfrfc/rfc1350.txt.pdf
+//
+// TFTP Operations
+//
+
+#define TFTP_OP_READ_REQUEST 1 ///< Read request, zero terminated file name, zero terminated mode
+#define TFTP_OP_WRITE_REQUEST 2 ///< Write request, zero terminated file name, zero terminated mode
+#define TFTP_OP_DATA 3 ///< Data block, end-of-file indicated by short block
+#define TFTP_OP_ACK 4 ///< ACK block number
+#define TFTP_OP_ERROR 5 ///< Error number and explaination
+#define TFTP_OP_OACK 6 ///< ACK the options
+
+#define TFTP_MAX_BLOCK_SIZE 4096 ///< Maximum block size
+
+//------------------------------------------------------------------------------
+// Data Types
+//------------------------------------------------------------------------------
+
+/**
+ Port control structure
+**/
+typedef struct _TSDT_CONNECTION_CONTEXT TSDT_CONNECTION_CONTEXT;
+typedef struct _TSDT_CONNECTION_CONTEXT {
+ //
+ // Remote connection management
+ //
+ TSDT_CONNECTION_CONTEXT * pNext; ///< Next context in the connection list
+ struct sockaddr_in RemoteAddress; ///< Remote address
+
+ //
+ // TFTP management parameters
+ //
+ UINT16 AckNext; ///< Next block to be received
+ BOOLEAN bExpectAck; ///< TRUE for read, FALSE for write
+ UINT32 BlockSize; ///< Negotiated block size
+ UINT32 Timeout; ///< Number of seconds to wait before retransmission
+
+ //
+ // File management parameters
+ //
+ EFI_HANDLE File; ///< NULL while file is closed
+ UINT64 LengthInBytes; ///< Size of the file
+ UINT64 MaxTransferSize; ///< Maximum transfer size
+ BOOLEAN bEofSent; ///< End of file sent
+ UINT8 * pBuffer; ///< Pointer into the file data
+ UINT8 * pEnd; ///< End of the file data
+ UINT8 FileData [ 64 * TFTP_MAX_BLOCK_SIZE ]; ///< File data to send
+
+ //
+ // Buffer management
+ //
+ ssize_t TxBytes; ///< Bytes in the TX buffer
+ UINT8 TxBuffer [ 2 + 2 + TFTP_MAX_BLOCK_SIZE ]; ///< Transmit buffer
+}GCC_TSDT_CONNECTION_CONTEXT;
+
+/**
+ TFTP server control structure
+**/
+typedef struct {
+ UINTN Signature; ///< Structure identification
+
+ //
+ // Image attributes
+ //
+ EFI_HANDLE ImageHandle; ///< Image handle
+
+ //
+ // TFTP port management
+ //
+ BOOLEAN bTimerRunning; ///< Port creation timer status
+ EFI_EVENT TimerEvent; ///< Timer to open TFTP port
+ struct pollfd TftpPort; ///< Poll descriptor for the TFTP port
+ struct sockaddr_in TftpServerAddress; ///< Address of the local TFTP server
+
+ //
+ // Request management
+ //
+ struct sockaddr_in RemoteAddress; ///< Remote address
+ ssize_t RxBytes; ///< Receive data length in bytes
+ UINT8 RxBuffer [ 2 + 2 + TFTP_MAX_BLOCK_SIZE ]; ///< Receive buffer
+
+ //
+ // Client port management
+ //
+ TSDT_CONNECTION_CONTEXT * pContextList; ///< List of connection context structures
+} TSDT_TFTP_SERVER;
+
+//#define SERVER_FROM_SERVICE(a) CR(a, TSDT_TFTP_SERVER, ServiceBinding, TFTP_SERVER_SIGNATURE) ///< Locate DT_LAYER from service binding
+
+extern TSDT_TFTP_SERVER mTftpServer;
+
+//------------------------------------------------------------------------------
+// Support routines
+//------------------------------------------------------------------------------
+
+/**
+ Process the TFTP request
+
+ @param [in] pOption Address of the first zero terminated option string
+ @param [in] pValue Address to receive the value
+
+ @retval EFI_SUCCESS Option translated into a value
+
+**/
+EFI_STATUS
+TftpOptionValue (
+ IN UINT8 * pOption,
+ IN INT32 * pValue
+ );
+
+/**
+ Process the TFTP request
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext Connection context structure address
+
+**/
+VOID
+TftpProcessRequest (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ );
+
+/**
+ Build and send an error packet
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext The context structure address.
+ @param [in] Error Error number for the packet
+ @param [in] pError Zero terminated error string address
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpSendError (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext,
+ IN UINT16 Error,
+ IN UINT8 * pError
+ );
+
+/**
+ Send the next block of file system data
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext The context structure address.
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpSendNextBlock (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ );
+
+/**
+ TFTP port creation timer routine
+
+ This routine polls the socket layer waiting for the initial network connection
+ which will enable the creation of the TFTP port. The socket layer will manage
+ the coming and going of the network connections after that until the last network
+ connection is broken.
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+**/
+VOID
+TftpServerTimer (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ );
+
+/**
+ Start the TFTP server port creation timer
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @retval EFI_SUCCESS The timer was successfully started.
+ @retval EFI_ALREADY_STARTED The timer is already running.
+ @retval Other The timer failed to start.
+
+**/
+EFI_STATUS
+TftpServerTimerStart (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ );
+
+/**
+ Stop the TFTP server port creation timer
+
+ @param [in] pTftpServer The TFTP server control structure address.
+
+ @retval EFI_SUCCESS The TFTP port timer is stopped
+ @retval Other Failed to stop the TFTP port timer
+
+**/
+EFI_STATUS
+TftpServerTimerStop (
+ IN TSDT_TFTP_SERVER * pTftpServer
+ );
+
+/**
+ Send the next TFTP packet
+
+ @param [in] pTftpServer The TFTP server control structure address.
+ @param [in] pContext The context structure address.
+
+ @retval EFI_SUCCESS Message processed successfully
+
+**/
+EFI_STATUS
+TftpTxPacket (
+ IN TSDT_TFTP_SERVER * pTftpServer,
+ IN TSDT_CONNECTION_CONTEXT * pContext
+ );
+
+//------------------------------------------------------------------------------
+
+#endif // _TFTP_SERVER_H_
diff --git a/AppPkg/Applications/Sockets/TftpServer/TftpServer.inf b/AppPkg/Applications/Sockets/TftpServer/TftpServer.inf new file mode 100644 index 0000000000..f48724289f --- /dev/null +++ b/AppPkg/Applications/Sockets/TftpServer/TftpServer.inf @@ -0,0 +1,66 @@ +#/** @file
+# TFTP Server Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TftpServer
+ FILE_GUID = 94621F9E-B5CA-4cfd-82BE-0C542EB0D9BE
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TftpServer.h
+ TftpServer.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+ EfiSocketLib
+ LibC
+ ShellLib
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+# UseSocketDxe
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
diff --git a/AppPkg/Applications/Sockets/WebServer/ACPI.c b/AppPkg/Applications/Sockets/WebServer/ACPI.c new file mode 100644 index 0000000000..a7da233e22 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/ACPI.c @@ -0,0 +1,1918 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the runtime services table + +**/ + +#include <WebServer.h> +#include <Guid/Acpi.h> +#include <IndustryStandard/Acpi10.h> +#include <IndustryStandard/Acpi30.h> + +#pragma warning ( disable : 4305 ) + +// +// Ensure proper structure formats +// +#pragma pack(1) + +typedef struct { + UINT8 AddressSpaceId; + UINT8 RegisterBitWidth; + UINT8 RegisterBitOffset; + UINT8 AccessSize; + UINT64 Address; +} GENERIC_ADDRESS; + + +typedef struct { + UINT32 Signature; // 0 + UINT32 Length; // 4 + UINT8 Revision; // 8 + UINT8 Checksum; // 9 + UINT8 OemId[6]; // 10 + UINT8 OemTableId[8]; // 16 + UINT32 OemRevision; // 24 + UINT32 CreatorId; // 28 + UINT32 CreatorRevision; // 32 + UINT8 DefinitionBlock[1]; // 36 +} ACPI_DSDT; + + +typedef struct { + UINT32 Signature; // 0 + UINT32 Length; // 4 + UINT8 Revision; // 8 + UINT8 Checksum; // 9 + UINT8 OemId[6]; // 10 + UINT8 OemTableId[8]; // 16 + UINT32 OemRevision; // 24 + UINT32 CreatorId; // 28 + UINT32 CreatorRevision; // 32 + UINT32 FirmwareCtrl; // 36 + UINT32 DSDT; // 40 + UINT8 Reserved; // 44 + UINT8 PreferredPmProfile; // 45 + UINT16 SciInt; // 46 + UINT32 SmiCmd; // 48 + UINT8 AcpiEnable; // 52 + UINT8 AcpiDisable; // 53 + UINT8 S4BiosReq; // 54 + UINT8 PStateCnt; // 55 + UINT32 Pm1aEvtBlk; // 56 + UINT32 Pm1bEvtBlk; // 60 + UINT32 Pm1aCntBlk; // 64 + UINT32 Pm1bCntBlk; // 68 + UINT32 Pm2CntBlk; // 72 + UINT32 PmTmrBlk; // 76 + UINT32 Gpe0Blk; // 80 + UINT32 Gpe1Blk; // 84 + UINT8 Pm1EvtLen; // 88 + UINT8 Pm1CntLen; // 89 + UINT8 PM2CntLen; // 90 + UINT8 PmTmrLen; // 91 + UINT8 Gpe0BlkLen; // 92 + UINT8 Gpe1BlkLen; // 93 + UINT8 Gpe1Base; // 94 + UINT8 CstCnt; // 95 + UINT16 PLvl2Lat; // 96 + UINT16 PLvl3Lat; // 98 + UINT16 FlushSize; // 100 + UINT16 FlushStride; // 102 + UINT8 DutyOffset; // 104 + UINT8 DutyWidth; // 105 + UINT8 DayAlrm; // 106 + UINT8 MonAlrm; // 107 + UINT8 Century; // 108 + UINT16 IapcBootArch; // 109 + UINT8 Reserved2; // 111 + UINT32 Flags; // 112 + UINT32 ResetReg [3]; // 116 + UINT8 ResetValue; // 128 + UINT8 Reserved3 [3]; // 129 + UINT64 XFirmwareCtrl; // 132 + UINT64 XDsdt; // 140 + UINT32 XPm1aEvtBlk [3]; // 148 + UINT32 XPm1bEvtBlk [3]; // 160 + UINT32 XPm1aCntBlk [3]; // 172 + UINT32 XPm1bCntBlk [3]; // 184 + UINT32 XPm2CntBlk [3]; // 196 + UINT32 XPmTmrBlk [3]; // 208 + UINT32 XGpe0Blk [3]; // 220 + UINT32 XGpe1Blk [3]; // 232 +} ACPI_FADT; + + +typedef struct { + UINT32 Signature; + UINT32 Length; + UINT8 Revision; + UINT8 Checksum; + UINT8 OemId[6]; + UINT8 OemTableId[8]; + UINT32 OemRevision; + UINT32 CreatorId; + UINT32 CreatorRevision; + UINT32 Entry[1]; +} ACPI_RSDT; + + +#pragma pack() + + +typedef struct { + UINT32 Signature; + CONST CHAR8 * pTableName; + CONST CHAR16 * pWebPage; +} TABLE_SIGNATURE; + + +CONST TABLE_SIGNATURE mTableId [] = { + { DSDT_SIGNATURE, "DSDT", PAGE_ACPI_DSDT }, + { FADT_SIGNATURE, "FADT", PAGE_ACPI_FADT } +}; + + +/** + Locate the RSDT table + + @returns Table address or NULL if not found + +**/ +CONST ACPI_RSDT * +LocateRsdt ( + VOID + ) +{ + CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b; + CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30; + CONST ACPI_RSDT * pRsdt; + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + pRsdt = NULL; + for ( ; ; ) { + // + // Locate the RSDT + // + Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **)&pRsdp30 ); + if ( !EFI_ERROR ( Status )) { + pRsdt = (ACPI_RSDT *)pRsdp30->RsdtAddress; + } + else { + Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&pRsdp10b ); + if ( EFI_ERROR ( Status )) { + break; + } + pRsdt = (ACPI_RSDT *)pRsdp10b->RsdtAddress; + } + break; + } + + // + // The entry was not found + // + return pRsdt; +} + + +/** + Locate the specified table + + @param [in] Signature Table signature + + @returns Table address or NULL if not found + +**/ +CONST VOID * +LocateTable ( + IN UINT32 Signature + ) +{ + CONST UINT32 * pEnd; + CONST UINT32 * pEntry; + CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b; + CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30; + CONST ACPI_RSDT * pRsdt; + CONST UINT32 * pSignature; + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Locate the RSDT + // + Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **)&pRsdp30 ); + if ( !EFI_ERROR ( Status )) { + pRsdt = (ACPI_RSDT *)pRsdp30->RsdtAddress; + } + else { + Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&pRsdp10b ); + if ( EFI_ERROR ( Status )) { + break; + } + pRsdt = (ACPI_RSDT *)pRsdp10b->RsdtAddress; + } + + // + // Walk the list of entries + // + pEntry = &pRsdt->Entry [ 0 ]; + pEnd = &pEntry [(( pRsdt->Length - sizeof ( *pRsdt )) >> 2 ) + 1 ]; + while ( pEnd > pEntry ) { + // + // The entry is actually a 32-bit physical table address + // The first entry in the table is the 32-bit table signature + // + pSignature = (UINT32 *)*pEntry; + if ( *pSignature == Signature ) { + return (CONST VOID *) *pEntry; + } + + // + // Set the next entry + // + pEntry++; + } + break; + } + + // + // The entry was not found + // + return NULL; +} + + +/** + Display a row containing a hex value + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] Length Length in bytes + @param [in] pChar Address of the first character + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowAnsiArray ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN UINTN Length, + IN CONST CHAR8 * pChar + ) +{ + CONST CHAR8 * pData; + CONST CHAR8 * pEnd; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Start the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the characters + // + pData = pChar; + pEnd = &pChar [ Length ]; + while ( pEnd > pData ) { + Status = HttpSendCharacter ( SocketFD, + pPort, + *pData++, + " " ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the byte values + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + pData = pChar; + while ( pEnd > pData ) { + Status = HttpSendHexBits ( SocketFD, + pPort, + 8, + *pData++ ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( pEnd > pData ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + " 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + } + + // + // Terminate the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Format a row with a list of bytes + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Zero terminated name string + @param [in] ByteCount The number of bytes to display + @param [in] pData Address of the byte array + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowBytes ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CHAR8 * pName, + IN UINTN ByteCount, + IN CONST UINT8 * pData + ) +{ + CONST UINT8 * pEnd; + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Start the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the field name + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the field value + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + pEnd = &pData [ ByteCount ]; + while ( pEnd > pData ) { + Status = HttpSendHexBits ( SocketFD, + pPort, + 8, + *pData++ ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( pEnd > pData ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + " 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Terminate the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + return Status; +} + + +/** + Format a row with a list of bytes + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Zero terminated name string + @param [in] ByteCount The number of bytes to display + @param [in] pData Address of the byte array + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowDump ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CHAR8 * pName, + IN UINTN ByteCount, + IN CONST UINT8 * pData + ) +{ + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Start the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the field name + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Start the field value + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Dump the buffer + // + Status = HttpSendDump ( SocketFD, + pPort, + ByteCount, + pData ); + + // + // Terminate the field value and row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + return Status; +} + + +/** + Format a row with a general address + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Zero terminated name string + @param [in] pAddr Address of the general address buffer + @param [in] pWebPage Zero terminated web page address + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowGenericAddress ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CHAR8 * pName, + IN CONST UINT32 * pAddr, + IN CONST CHAR16 * pWebPage + ) +{ + CONST GENERIC_ADDRESS * pGenericAddress; + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Start the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the field name + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the field value + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine the type of address + // + pGenericAddress = (CONST GENERIC_ADDRESS *)pAddr; + if ( 0 == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "System Memory" ); + } + else if ( 1 == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "I/O Space" ); + } + else if ( 2 == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "PCI Configuration Space" ); + } + else if ( 3 == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "Embedded Controller" ); + } + else if ( 4 == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "SMBus" ); + } + else if ( 0x7f == pGenericAddress->AddressSpaceId ) { + Status = HttpSendAnsiString ( SocketFD, pPort, "Functional Fixed Hardware" ); + } + else if (( 0xc0 <= pGenericAddress->AddressSpaceId ) + && ( 0xff >= pGenericAddress->AddressSpaceId )) { + Status = HttpSendAnsiString ( SocketFD, pPort, "OEM Defined" ); + } + else { + Status = HttpSendAnsiString ( SocketFD, pPort, "Reserved" ); + } + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>Register Bit Width: " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + pGenericAddress->RegisterBitWidth ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>Register Bit Offset: " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexValue ( SocketFD, + pPort, + pGenericAddress->RegisterBitOffset ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>Access Size: " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + pGenericAddress->AccessSize ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>Address: " ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Add the web-page link if necessary + // + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<a target=\"_blank\" href=\"" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pWebPage ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "\">" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Display the address + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + 64, + pGenericAddress->Address ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Finish the web-page link if necessary + // + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</a>" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Terminate the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + return Status; +} + + +/** + Translate a table address into a web page + + @param [in] pSignature Address of the table signature + @param [out] ppTableName Address to receive the table name address + + @returns Zero terminated web page address or NULL if not found + +**/ +CONST CHAR16 * +SignatureLookup ( + IN UINT32 * pSignature, + OUT CONST CHAR8 ** ppTableName + ) +{ + CONST TABLE_SIGNATURE * pTableId; + CONST TABLE_SIGNATURE * pEnd; + UINT32 Signature; + + // + // Walk the list of tables + // + Signature = *pSignature; + pTableId = &mTableId [ 0 ]; + pEnd = &pTableId [ sizeof ( mTableId ) / sizeof ( mTableId [ 0 ])]; + while ( pEnd > pTableId ) { + // + // Attempt to locate the table signature + // + if ( pTableId->Signature == Signature ) { + // + // The signature was found + // Return the web page + // + *ppTableName = pTableId->pTableName; + return pTableId->pWebPage; + } + + // + // Set the next table + // + pTableId += 1; + } + + // + // The table was not found + // + *ppTableName = (CONST CHAR8 *)pSignature; + return NULL; +} + + +/** + Respond with the ACPI DSDT table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +AcpiDsdtPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST ACPI_DSDT * pDsdt; + CONST ACPI_FADT * pFadt; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the DADT page + // + for ( ; ; ) { + // + // Locate the DADT + // + pFadt = (ACPI_FADT *)LocateTable ( FADT_SIGNATURE ); + if ( NULL == pFadt ) { + Status = EFI_NOT_FOUND; + break; + } + pDsdt = (VOID *)pFadt->XDsdt; + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"DSDT - Differentiated System Description Table", pDsdt ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the DSDT header + // + Status = RowAnsiArray ( SocketFD, + pPort, + "Signature", + sizeof ( pDsdt->Signature ), + (CHAR8 *)&pDsdt->Signature ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Length", + pDsdt->Length ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Revision", + pDsdt->Revision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Checksum", + pDsdt->Checksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEMID", + sizeof ( pDsdt->OemId ), + &pDsdt->OemId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEM Table ID", + sizeof ( pDsdt->OemTableId ), + &pDsdt->OemTableId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "OEM Revision", + pDsdt->OemRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "Creator ID", + sizeof ( pDsdt->CreatorId ), + (CHAR8 *)&pDsdt->CreatorId ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "Creator Revision", + pDsdt->CreatorRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the data from the DSDT + // + Status = RowDump ( SocketFD, + pPort, + "Definition Block", + pDsdt->Length - sizeof ( *pDsdt ) + 1, + &pDsdt->DefinitionBlock[0]); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the ACPI FADT table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +AcpiFadtPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST ACPI_FADT * pFadt; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the FADT page + // + for ( ; ; ) { + // + // Locate the FADT + // + pFadt = (ACPI_FADT *)LocateTable ( FADT_SIGNATURE ); + if ( NULL == pFadt ) { + Status = EFI_NOT_FOUND; + break; + } + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"FADT - Fixed ACPI Description Table", pFadt ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the FSDT header + // + Status = RowAnsiArray ( SocketFD, + pPort, + "Signature", + sizeof ( pFadt->Signature ), + (CHAR8 *)&pFadt->Signature ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Length", + pFadt->Length ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Revision", + pFadt->Revision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Checksum", + pFadt->Checksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEMID", + sizeof ( pFadt->OemId ), + &pFadt->OemId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEM Table ID", + sizeof ( pFadt->OemTableId ), + &pFadt->OemTableId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "OEM Revision", + pFadt->OemRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "Creator ID", + sizeof ( pFadt->CreatorId ), + (CHAR8 *)&pFadt->CreatorId ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "Creator Revision", + pFadt->CreatorRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the data from the FADT + // + Status = RowPointer ( SocketFD, + pPort, + "FIRMWARE_CTRL", + (CONST VOID *)pFadt->FirmwareCtrl, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "DSDT", + (CONST VOID *)pFadt->DSDT, + ( pFadt->DSDT == pFadt->XDsdt ) ? PAGE_ACPI_DSDT : NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pFadt->Reserved, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Preferred_PM_Profile", + pFadt->PreferredPmProfile, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "SCI_INT", + pFadt->SciInt, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "SMI_CMD", + pFadt->SmiCmd, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "ACPI_ENABLE", + pFadt->AcpiEnable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "ACPI_DISABLE", + pFadt->AcpiDisable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "S4BIOS_REQ", + pFadt->S4BiosReq, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PSTATE_CNT", + pFadt->PStateCnt, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM1a_EVT_BLK", + pFadt->Pm1aEvtBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM1b_EVT_BLK", + pFadt->Pm1bEvtBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM1a_CNT_BLK", + pFadt->Pm1aCntBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM1b_CNT_BLK", + pFadt->Pm1bCntBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM2_CNT_BLK", + pFadt->Pm2CntBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "PM_TMR_BLK", + pFadt->PmTmrBlk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + Status = RowHexValue ( SocketFD, + pPort, + "GPE0_BLK", + pFadt->Gpe0Blk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "GPE1_BLK", + pFadt->Gpe1Blk, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "PM1_EVT_LEN", + pFadt->Pm1EvtLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "PM1_CNT_LEN", + pFadt->Pm1CntLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "PM2_CNT_LEN", + pFadt->PM2CntLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "PM_TMR_LEN", + pFadt->PmTmrLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "GPE0_BLK_LEN", + pFadt->Gpe0BlkLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "GPE1_BLK_LEN", + pFadt->Gpe1BlkLen ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "GPE1_BASE", + pFadt->Gpe1Base, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "CST_CNT", + pFadt->CstCnt ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "P_LVL2_LAT", + pFadt->PLvl2Lat, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "P_LVL3_LAT", + pFadt->PLvl3Lat, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "FLUSH_SIZE", + pFadt->FlushSize ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "FLUSH_Stride", + pFadt->FlushStride ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "DUTY_OFFSET", + pFadt->DutyOffset, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "DUTY_WIDTH", + pFadt->DutyWidth, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "DAY_ALRM", + pFadt->DayAlrm, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "MON_ALRM", + pFadt->MonAlrm, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "CENTURY", + pFadt->Century, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "IAPC_BOOT_ARCH", + pFadt->IapcBootArch, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pFadt->Reserved2, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Flags", + pFadt->Flags, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "RESET_REG", + &pFadt->ResetReg[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "RESET_VALUE", + pFadt->ResetValue, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pFadt->Reserved3[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pFadt->Reserved3[1], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pFadt->Reserved3[2], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "X_FIRMWARE_CTRL", + pFadt->XFirmwareCtrl, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "X_DSDT", + pFadt->XDsdt, + PAGE_ACPI_DSDT ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM1a_EVT_BLK", + &pFadt->XPm1aEvtBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM1b_EVT_BLK", + &pFadt->XPm1bEvtBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM1a_CNT_BLK", + &pFadt->XPm1aCntBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM1b_CNT_BLK", + &pFadt->XPm1bCntBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM2_CNT_BLK", + &pFadt->XPm2CntBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_PM_TMR_BLK", + &pFadt->XPmTmrBlk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_GPE0_BLK", + &pFadt->XGpe0Blk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowGenericAddress ( SocketFD, + pPort, + "X_GPE1_BLK", + &pFadt->XGpe1Blk[0], + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the ACPI RSDP 1.0b table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +AcpiRsdp10Page ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the RSDP page + // + for ( ; ; ) { + // + // Locate the RSDP + // + Status = EfiGetSystemConfigurationTable ( &gEfiAcpi10TableGuid, (VOID **) &pRsdp10b ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"RSDP - ACPI 1.0b Root System Description Pointer", pRsdp10b ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the RSDP + // + Status = RowAnsiArray ( SocketFD, + pPort, + "Signature", + sizeof ( pRsdp10b->Signature ), + (CHAR8 *)&pRsdp10b->Signature ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Checksum", + pRsdp10b->Checksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OemId", + sizeof ( pRsdp10b->OemId ), + &pRsdp10b->OemId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Reserved", + pRsdp10b->Reserved, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RsdtAddress", + (VOID *)pRsdp10b->RsdtAddress, + PAGE_ACPI_RSDT ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the ACPI RSDP 3.0 table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +AcpiRsdp30Page ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the RSDP page + // + for ( ; ; ) { + // + // Locate the RSDP + // + Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **) &pRsdp30 ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"RSDP - ACPI 3.0 Root System Description Pointer", pRsdp30 ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the RSDP + // + Status = RowAnsiArray ( SocketFD, + pPort, + "Signature", + sizeof ( pRsdp30->Signature ), + (CHAR8 *)&pRsdp30->Signature ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Checksum", + pRsdp30->Checksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OemId", + sizeof ( pRsdp30->OemId ), + &pRsdp30->OemId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Revision", + pRsdp30->Revision, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RsdtAddress", + (VOID *)pRsdp30->RsdtAddress, + PAGE_ACPI_RSDT ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Length", + pRsdp30->Length ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "XsdtAddress", + (VOID *)pRsdp30->XsdtAddress, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "ExtendedChecksum", + pRsdp30->ExtendedChecksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowBytes ( SocketFD, + pPort, + "Reserved", + sizeof ( pRsdp30->Reserved ), + &pRsdp30->Reserved [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the ACPI RSDT table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +AcpiRsdtPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST UINT32 * pEnd; + CONST UINT32 * pEntry; + CONST ACPI_RSDT * pRsdt; + CONST CHAR8 * pTableName; + CONST CHAR16 * pWebPage; + EFI_STATUS Status; + UINT32 TableName [ 2 ]; + + DBG_ENTER ( ); + + // + // Send the RSDT page + // + for ( ; ; ) { + // + // Locate the RSDT + // + pRsdt = LocateRsdt ( ); + if ( NULL == pRsdt ) { + Status = EFI_NOT_FOUND; + break; + } + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"RSDT - ACPI Root System Description Table", pRsdt ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the RSDT + // + Status = RowAnsiArray ( SocketFD, + pPort, + "Signature", + sizeof ( pRsdt->Signature ), + (CHAR8 *)&pRsdt->Signature ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Length", + pRsdt->Length ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowDecimalValue ( SocketFD, + pPort, + "Revision", + pRsdt->Revision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowHexValue ( SocketFD, + pPort, + "Checksum", + pRsdt->Checksum, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEMID", + sizeof ( pRsdt->OemId ), + &pRsdt->OemId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "OEM Table ID", + sizeof ( pRsdt->OemTableId ), + &pRsdt->OemTableId [ 0 ]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "OEM Revision", + pRsdt->OemRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowAnsiArray ( SocketFD, + pPort, + "Creator ID", + sizeof ( pRsdt->CreatorId ), + (CHAR8 *)&pRsdt->CreatorId ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowRevision ( SocketFD, + pPort, + "Creator Revision", + pRsdt->CreatorRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Walk the list of entries + // + pEntry = &pRsdt->Entry [ 0 ]; + pEnd = &pEntry [(( pRsdt->Length - sizeof ( *pRsdt )) >> 2 ) + 1 ]; + TableName [ 1 ] = 0; + while ( pEnd > pEntry ) { + // + // The entry is actually a 32-bit physical table address + // The first entry in the table is the 32-bit table signature + // + TableName [ 0 ] = *(UINT32 *)*pEntry; + pWebPage = SignatureLookup ( &TableName [ 0 ], &pTableName ); + + // + // Display the table address + // + Status = RowPointer ( SocketFD, + pPort, + pTableName, + (VOID *)*pEntry, + pWebPage ); + if ( EFI_ERROR ( Status )) { + break; + } + pEntry++; + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + diff --git a/AppPkg/Applications/Sockets/WebServer/BootServicesTable.c b/AppPkg/Applications/Sockets/WebServer/BootServicesTable.c new file mode 100644 index 0000000000..ab0164976f --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/BootServicesTable.c @@ -0,0 +1,481 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the boot services table + +**/ + +#include <WebServer.h> + +/** + Respond with the boot services table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +BootServicesTablePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the boot services page + // + for ( ; ; ) { + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"Boot Services Table", gBS ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The table header for the EFI Boot Services Table. + /// + Status = EfiTableHeader ( SocketFD, + pPort, + &gBS->Hdr ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Task Priority Services + // + Status = RowPointer ( SocketFD, + pPort, + "RaiseTPL", + (CONST VOID *)gBS->RaiseTPL, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RestoreTPL", + (CONST VOID *)gBS->RestoreTPL, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Memory Services + // + Status = RowPointer ( SocketFD, + pPort, + "AllocatePages", + (CONST VOID *)gBS->AllocatePages, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "FreePages", + (CONST VOID *)gBS->FreePages, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetMemoryMap", + (CONST VOID *)gBS->GetMemoryMap, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "AllocatePool", + (CONST VOID *)gBS->AllocatePool, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "FreePool", + (CONST VOID *)gBS->FreePool, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Event & Timer Services + // + Status = RowPointer ( SocketFD, + pPort, + "CreateEvent", + (CONST VOID *)gBS->CreateEvent, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetTimer", + (CONST VOID *)gBS->SetTimer, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "WaitForEvent", + (CONST VOID *)gBS->WaitForEvent, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SignalEvent", + (CONST VOID *)gBS->SignalEvent, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "CloseEvent", + (CONST VOID *)gBS->CloseEvent, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "CheckEvent", + (CONST VOID *)gBS->CheckEvent, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Protocol Handler Services + // + Status = RowPointer ( SocketFD, + pPort, + "InstallProtocolInterface", + (CONST VOID *)gBS->InstallProtocolInterface, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "ReinstallProtocolInterface", + (CONST VOID *)gBS->ReinstallProtocolInterface, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "UninstallProtocolInterface", + (CONST VOID *)gBS->UninstallProtocolInterface, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "HandleProtocol", + (CONST VOID *)gBS->HandleProtocol, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "Reserved", + (CONST VOID *)gBS->Reserved, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RegisterProtocolNotify", + (CONST VOID *)gBS->RegisterProtocolNotify, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "LocateHandle", + (CONST VOID *)gBS->LocateHandle, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "LocateDevicePath", + (CONST VOID *)gBS->LocateDevicePath, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "InstallConfigurationTable", + (CONST VOID *)gBS->InstallConfigurationTable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Image Services + // + Status = RowPointer ( SocketFD, + pPort, + "LoadImage", + (CONST VOID *)gBS->LoadImage, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "StartImage", + (CONST VOID *)gBS->StartImage, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "Exit", + (CONST VOID *)gBS->Exit, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "UnloadImage", + (CONST VOID *)gBS->UnloadImage, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "ExitBootServices", + (CONST VOID *)gBS->ExitBootServices, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Miscellaneous Services + // + Status = RowPointer ( SocketFD, + pPort, + "GetNextMonotonicCount", + (CONST VOID *)gBS->GetNextMonotonicCount, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "Stall", + (CONST VOID *)gBS->Stall, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetWatchdogTimer", + (CONST VOID *)gBS->SetWatchdogTimer, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // DriverSupport Services + // + Status = RowPointer ( SocketFD, + pPort, + "ConnectController", + (CONST VOID *)gBS->ConnectController, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "DisconnectController", + (CONST VOID *)gBS->DisconnectController, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Open and Close Protocol Services + // + Status = RowPointer ( SocketFD, + pPort, + "OpenProtocol", + (CONST VOID *)gBS->OpenProtocol, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "CloseProtocol", + (CONST VOID *)gBS->CloseProtocol, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "OpenProtocolInformation", + (CONST VOID *)gBS->OpenProtocolInformation, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Library Services + // + Status = RowPointer ( SocketFD, + pPort, + "ProtocolsPerHandle", + (CONST VOID *)gBS->ProtocolsPerHandle, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "LocateHandleBuffer", + (CONST VOID *)gBS->LocateHandleBuffer, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "LocateProtocol", + (CONST VOID *)gBS->LocateProtocol, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "InstallMultipleProtocolInterfaces", + (CONST VOID *)gBS->InstallMultipleProtocolInterfaces, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "UninstallMultipleProtocolInterfaces", + (CONST VOID *)gBS->UninstallMultipleProtocolInterfaces, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // 32-bit CRC Services + // + Status = RowPointer ( SocketFD, + pPort, + "CalculateCrc32", + (CONST VOID *)gBS->CalculateCrc32, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Miscellaneous Services + // + Status = RowPointer ( SocketFD, + pPort, + "CopyMem", + (CONST VOID *)gBS->CopyMem, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetMem", + (CONST VOID *)gBS->SetMem, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "CreateEventEx", + (CONST VOID *)gBS->CreateEventEx, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/ConfigurationTable.c b/AppPkg/Applications/Sockets/WebServer/ConfigurationTable.c new file mode 100644 index 0000000000..8a3de87ed4 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/ConfigurationTable.c @@ -0,0 +1,380 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the configuration table + +**/ + +#include <WebServer.h> +#include <Guid\Acpi.h> +#include <Guid\DebugImageInfoTable.h> +#include <Guid\DxeServices.h> +#include <Guid\HobList.h> +#include <Guid\MemoryTypeInformation.h> +#include <Guid\LoadModuleAtFixedAddress.h> + + +typedef struct { + CHAR16 * GuidName; + EFI_GUID * pGuid; + CHAR16 * pWebPage; +} GUID_NAME; + +CONST GUID_NAME mGuidName [] = { + { L"gEfiAcpi10TableGuid", &gEfiAcpi10TableGuid, PAGE_ACPI_RSDP_10B }, + { L"gEfiAcpiTableGuid", &gEfiAcpiTableGuid, PAGE_ACPI_RSDP_30 }, + { L"gEfiDebugImageInfoTableGuid", &gEfiDebugImageInfoTableGuid, NULL }, + { L"gEfiDxeServicesTableGuid", &gEfiDxeServicesTableGuid, PAGE_DXE_SERVICES_TABLE }, + { L"gEfiHobListGuid", &gEfiHobListGuid, NULL }, + { L"gEfiMemoryTypeInformationGuid", &gEfiMemoryTypeInformationGuid, NULL }, + { L"gLoadFixedAddressConfigurationTableGuid", &gLoadFixedAddressConfigurationTableGuid, NULL } +}; + +/** + Display a row containing a GUID value + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] pGuid Address of the GUID to display + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowGuid ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN CONST EFI_GUID * pGuid + ) +{ + CONST GUID_NAME * pGuidName; + CONST GUID_NAME * pGuidNameEnd; + EFI_STATUS Status; + UINTN Value; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine if this is a known GUID + // + pGuidName = &mGuidName[0]; + pGuidNameEnd = &pGuidName [ sizeof ( mGuidName ) / sizeof ( mGuidName[0])]; + while ( pGuidNameEnd > pGuidName ) { + if ( CompareGuid ( pGuidName->pGuid, pGuid )) { + // + // Display the web link if available + // + if ( NULL != pGuidName->pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<a target=\"_blank\" href=\"" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pGuidName->pWebPage ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "\">" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Display the GUID name + // + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pGuidName->GuidName ); + + // + // Complete the web link if available + // + if ( NULL != pGuidName->pWebPage ) { + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</a>" ); + } + break; + } + + // + // Set the next GUID name + // + pGuidName += 1; + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Only if the entry is not known, display the GUID and type + // + if ( pGuidNameEnd <= pGuidName ) { + // + // Display the GUID + // + Status = HttpSendGuid ( SocketFD, + pPort, + pGuid ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the GUID type + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/><a target=\"_blank\" href=\"http://www.ietf.org/rfc/rfc4122.txt\">Guid Type</a>: " ); + if ( EFI_ERROR ( Status )) { + break; + } + Value = pGuid->Data4[1]; + Value >>= 5; + if ( 3 >= Value ) { + // + // Network type + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Network " ); + } + else if ( 5 >= Value ) { + // + // Standard type + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Standard " ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Decode the standard type using RFC 4122 + // + Value = pGuid->Data3; + Value >>= 12; + switch ( Value ) { + default: + // + // Display the MAC address + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Version " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + pGuid->Data3 >> 12 ); + break; + + case 1: + Status = HttpSendAnsiString ( SocketFD, + pPort, + "MAC address" ); + break; + + case 2: + Status = HttpSendAnsiString ( SocketFD, + pPort, + "DCE Security" ); + break; + + case 3: + Status = HttpSendAnsiString ( SocketFD, + pPort, + "MD5 hash" ); + break; + + case 4: + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Random" ); + break; + + case 5: + Status = HttpSendAnsiString ( SocketFD, + pPort, + "SHA-1 hash" ); + break; + } + } + else if ( 6 == Value ) { + // + // Microsoft's Component Object Model (COM) type + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Microsoft COM" ); + } + else { + // + // Reserved type + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Reserved" ); + } + } + + // + // Done with this entry + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the configuration tables + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +ConfigurationTablePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_CONFIGURATION_TABLE * pEnd; + EFI_CONFIGURATION_TABLE * pTable; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the system table page + // + for ( ; ; ) { + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"Configuration Tables", gST ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the table size + // + Status = RowDecimalValue ( SocketFD, + pPort, + "Entries", + gST->NumberOfTableEntries ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine the location of the configuration tables + // + pTable = gST->ConfigurationTable; + pEnd = &pTable [ gST->NumberOfTableEntries ]; + while ( pEnd > pTable ) { + Status = RowGuid ( SocketFD, + pPort, + "VendorGuid", + &pTable->VendorGuid ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "VendorTable", + (VOID *)pTable->VendorTable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Set the next row + // + pTable += 1; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/DhcpOptions.c b/AppPkg/Applications/Sockets/WebServer/DhcpOptions.c new file mode 100644 index 0000000000..fe37d3deb7 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/DhcpOptions.c @@ -0,0 +1,235 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the DHCP options + +**/ + +#include <WebServer.h> +#include <Guid/DxeServices.h> +#include <pi/PiDxeCis.h> + +#include <protocol/Dhcp4.h> +#include <protocol/ServiceBinding.h> + +/** + Respond with the DHCP options + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +DhcpOptionsPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ +// EFI_HANDLE Dhcp4Handle; + EFI_DHCP4_MODE_DATA Dhcp4Mode; + UINTN HandleCount; + EFI_DHCP4_PROTOCOL * pDhcp4; + EFI_DHCP4_PACKET * pDhcp4Packet; + EFI_HANDLE * pEnd; + EFI_HANDLE * pHandle; +// EFI_SERVICE_BINDING_PROTOCOL * pService; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the DHCP options + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"DHCP Options" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the header + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + L"DHCP Options" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</h1>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Attempt to locate DHCP clients + // + Status = gBS->LocateHandleBuffer ( ByProtocol, +// &gEfiDhcp4ServiceBindingProtocolGuid, + &gEfiDhcp4ProtocolGuid, + NULL, + &HandleCount, + &pHandle ); + if ( EFI_ERROR ( Status )) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "DHCP not in use" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + else { + // + // Walk the list of handles + // + pEnd = &pHandle [ HandleCount ]; + while ( pEnd > pHandle ) { +/* + // + // Get the DHCP service binding + // + Status = gBS->OpenProtocol ( *pHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + &pService, + NULL, + gImageHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + if ( EFI_ERROR ( Status )) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Failed to open gEfiDhcp4ServiceBindingProtocolGuid" ); + break; + } + + // + // Get the DHCP handle + // + Status = pService->CreateChild ( pService, + &Dhcp4Handle ); + if ( EFI_ERROR ( Status )) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Failed to create DHCP4 child" ); + } + else { +*/ + // + // Get the DHCP protocol + // + Status = gBS->OpenProtocol ( *pHandle, +// Dhcp4Handle, + &gEfiDhcp4ProtocolGuid, + &pDhcp4, + NULL, + gImageHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + if ( EFI_ERROR ( Status )) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Failed to open gEfiDhcp4ProtocolGuid" ); + } + else { + // + // Get the DHCP packet + // + Status = pDhcp4->GetModeData ( pDhcp4, + &Dhcp4Mode ); + if ( EFI_ERROR ( Status )) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "Failed to get DHCP4 mode" ); + } + else { + // + // Get the last packet + // + pDhcp4Packet = Dhcp4Mode.ReplyPacket; + if ( NULL == pDhcp4Packet ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "No DHCP reply received!<br/>DHCP Mode:<br/>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the DHCP mode data + // + Status = HttpSendDump ( SocketFD, + pPort, + sizeof ( Dhcp4Mode ), + (UINT8 *)&Dhcp4Mode ); + } + else { + // + // Display the DHCP packet + // + Status = HttpSendDump ( SocketFD, + pPort, + pDhcp4Packet->Length, + (UINT8 *)&pDhcp4Packet->Dhcp4 ); + } + } +/* + } + + // + // Done with the DHCP protocol + // + pService->DestroyChild ( pService, + Dhcp4Handle ); +*/ + } + + // + // Set the next service binding + // + pHandle += 1; + } + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/DxeServicesTable.c b/AppPkg/Applications/Sockets/WebServer/DxeServicesTable.c new file mode 100644 index 0000000000..bfe90cd907 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/DxeServicesTable.c @@ -0,0 +1,245 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the DXE services table + +**/ + +#include <WebServer.h> +#include <Guid/DxeServices.h> +#include <pi/PiDxeCis.h> + +/** + Respond with the DXE services table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +DxeServicesTablePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_DXE_SERVICES * pDS; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the DXE services page + // + for ( ; ; ) { + // + // Get the DXE services table + // + Status = EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &pDS); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"DXE Services Table", pDS ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The table header for the DXE Services Table. + /// This header contains the DXE_SERVICES_SIGNATURE and DXE_SERVICES_REVISION values. + /// + Status = EfiTableHeader ( SocketFD, + pPort, + &pDS->Hdr ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Global Coherency Domain Services + // + Status = RowPointer ( SocketFD, + pPort, + "AddMemorySpace", + (VOID *)pDS->AddMemorySpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "AllocateMemorySpace", + (VOID *)pDS->AllocateMemorySpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "FreeMemorySpace", + (VOID *)pDS->FreeMemorySpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RemoveMemorySpace", + (VOID *)pDS->RemoveMemorySpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetMemorySpaceDescriptor", + (VOID *)pDS->GetMemorySpaceDescriptor, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetMemorySpaceAttributes", + (VOID *)pDS->SetMemorySpaceAttributes, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetMemorySpaceMap", + (VOID *)pDS->GetMemorySpaceMap, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "AddIoSpace", + (VOID *)pDS->AddIoSpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "AllocateIoSpace", + (VOID *)pDS->AllocateIoSpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "FreeIoSpace", + (VOID *)pDS->FreeIoSpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "RemoveIoSpace", + (VOID *)pDS->RemoveIoSpace, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetIoSpaceDescriptor", + (VOID *)pDS->GetIoSpaceDescriptor, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetIoSpaceMap", + (VOID *)pDS->GetIoSpaceMap, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Dispatcher Services + // + Status = RowPointer ( SocketFD, + pPort, + "Dispatch", + (VOID *)pDS->Dispatch, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "Schedule", + (VOID *)pDS->Schedule, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "Trust", + (VOID *)pDS->Trust, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Service to process a single firmware volume found in a capsule + // + Status = RowPointer ( SocketFD, + pPort, + "ProcessFirmwareVolume", + (VOID *)pDS->ProcessFirmwareVolume, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/Firmware.c b/AppPkg/Applications/Sockets/WebServer/Firmware.c new file mode 100644 index 0000000000..4d5aad6d8f --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/Firmware.c @@ -0,0 +1,106 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the firmware + +**/ + +#include <WebServer.h> + + +/** + Respond with the firmware status + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +FirmwarePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the system table page + // + for ( ; ; ) { + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"Firmware", NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the firmware vendor and revision + // + Status = RowUnicodeString ( SocketFD, + pPort, + "Vendor", + gST->FirmwareVendor ); + if ( EFI_ERROR ( Status )) { + break; + } + + Status = RowRevision ( SocketFD, + pPort, + "Revision", + gST->FirmwareRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the UEFI version + // + Status = RowRevision ( SocketFD, + pPort, + "UEFI", + gST->Hdr.Revision ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/HTTP.c b/AppPkg/Applications/Sockets/WebServer/HTTP.c new file mode 100644 index 0000000000..a1716b2dbf --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/HTTP.c @@ -0,0 +1,1570 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + HTTP processing for the web server. + +**/ + +#include <WebServer.h> + +/** + Get a UTF-8 character from the buffer + + @param [in] pData The address of the buffer containing the character + @param [out] ppData The address to receive the next character address + + @returns The character value + +**/ +INTN +HttpCharGet ( + IN UINT8 * pData, + IN UINT8 ** ppData + ) +{ + INTN Data; + INTN Character; + INTN Control; + INTN Mask; + + // + // Verify that there is some data left + // + if ( NULL == pData ) { + // + // No data to return + // + pData = NULL; + Character = 0; + } + else { + // + // Get the first portion of the character + // + Character = *pData++; + Control = Character; + Mask = 0xc0; + + // + // Append the rest of the character + // + if ( 0 != ( Control & 0x80 )) { + while ( 0 != ( Control & 0x40 )) { + Character &= Mask; + Mask <<= 5; + Control <<= 1; + Character <<= 6; + Data = *pData++ & 0x3f; + if ( 0x80 != ( Data & 0xc0 )) { + // + // Invalid character + // + pData = NULL; + Character = 0; + break; + } + Character |= Data & 0x3f; + } + } + } + + // + // Return the next character location and the character + // + *ppData = pData; + return Character; +} + + +/** + Transmit a portion of the HTTP response + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpFlush ( + IN int SocketFD, + IN WSDT_PORT * pPort + ) +{ + INTN LengthInBytes; + UINT8 * pBuffer; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Assume success + // + Status = EFI_SUCCESS; + pBuffer = &pPort->TxBuffer[0]; + do { + // + // Attempt to send the data + // + LengthInBytes = send ( SocketFD, + pBuffer, + pPort->TxBytes, + 0 ); + if ( -1 != LengthInBytes ) { + // + // Account for the data sent + // + pBuffer += LengthInBytes; + pPort->TxBytes -= LengthInBytes; + } + else { + // + // Transmit error + // + Status = EFI_DEVICE_ERROR; + break; + } + } while ( 0 < pPort->TxBytes ); + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Convert the ANSI character to lower case + + @param [in] Character The character to convert to lower case. + + @returns The lower case character + +**/ +INTN +HttpLowerCase ( + IN INTN Character + ) +{ + // + // Determine if the character is upper case + // + if (( 'A' <= Character ) && ( 'Z' >= Character )) { + Character += 'a' - 'A'; + } + + // + // Return the lower case value of the character + // + return Character; +} + + +/** + Match a Unicode string against a UTF-8 string + + @param [in] pString A zero terminated Unicode string + @param [in] pData A zero terminated UTF-8 string + @param [in] bIgnoreCase TRUE if case is to be ignored + + @returns The difference between the last two characters tested. + Returns -1 for error. + +**/ +INTN +HttpMatch ( + IN UINT16 * pString, + IN UINT8 * pData, + IN BOOLEAN bIgnoreCase + ) +{ + INTN Character1; + INTN Character2; + INTN Difference; + + do { + // + // Get the character from the comparison string + // + Character1 = *pString++; + + // + // Convert the character to lower case + // + if ( bIgnoreCase ) { + Character1 = HttpLowerCase ( Character1 ); + } + + // + // Get the character from the request + // + Character2 = HttpCharGet ( pData, &pData ); + if ( NULL == pData ) { + // + // Error getting character + // + Difference = -1; + break; + } + + // + // Convert the character to lower case + // + if ( bIgnoreCase ) { + Character2 = HttpLowerCase ( Character2 ); + } + + // + // Compare the characters + // + Difference = Character1 - Character2; + if ( 0 != Difference ) { + return Difference; + } + } while ( 0 != Character1 ); + + // + // Return the difference + // + return Difference; +} + + +/** + Buffer the HTTP page header + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pTitle A zero terminated Unicode title string + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpPageHeader ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR16 * pTitle + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Build the page header + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<!DOCTYPE " + "HTML " + "PUBLIC " + "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " + "\"http://www.w3.org/TR/html4/loose.dtd\">\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, "<html lang=\"en-US\">\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pTitle ) { + Status = HttpSendAnsiString ( SocketFD, pPort, " <head>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " <title>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, pPort, pTitle ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, "</title>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " </head>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, pPort, " <body>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with an error indicating that the page was not found + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpPageNotFound ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the page not found + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"404 Not found" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page body + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "ERROR <b>404</b><br />" + "Requested page is not available\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Buffer and send the HTTP page trailer + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpPageTrailer ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN BOOLEAN * pbDone + ) +{ + int RetVal; + EFI_STATUS Status; + socklen_t LengthInBytes; + struct sockaddr_in LocalAddress; + struct sockaddr_in RemoteAddress; + + DBG_ENTER ( ); + + // + // Build the page header + // + for ( ; ; ) { + LengthInBytes = sizeof ( LocalAddress ); + RetVal = getsockname ( SocketFD, (struct sockaddr *)&LocalAddress, &LengthInBytes ); + if ( 0 == RetVal ) { + RetVal = getpeername ( SocketFD, (struct sockaddr *)&RemoteAddress, &LengthInBytes ); + if ( 0 == RetVal ) { + // + // Seperate the body from the trailer + // + Status = HttpSendAnsiString ( SocketFD, pPort, " <hr>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the system addresses and the page transfer direction + // + Status = HttpSendIpAddress ( SocketFD, pPort, &LocalAddress ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " --> " ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendIpAddress ( SocketFD, pPort, &RemoteAddress ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, "\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + } + + // + // Terminate the page + // + Status = HttpSendAnsiString ( SocketFD, pPort, " </body>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, pPort, " </html>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpFlush ( SocketFD, pPort ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Mark the page as complete + // + *pbDone = TRUE; + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Replace a space with a zero + + @param [in] pData The request buffer address + @param [in] pEnd End of buffer address + + @returns The next character location + +**/ +UINT8 * +HttpReplaceSpace ( + IN UINT8 * pData, + IN UINT8 * pEnd + ) +{ + INTN Character; + UINT8 * pSpace; + + pSpace = pData; + while ( pEnd > pData ) { + // + // Get the character from the request + // + Character = HttpCharGet ( pData, &pData ); + if ( ' ' == Character ) { + break; + } + pSpace = pData; + } + + // + // Replace the space character with zero + // + ZeroMem ( pSpace, pData - pSpace ); + + // + // Return the next character location + // + return pData; +} + + +/** + Process an HTTP request + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpRequest ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + UINT8 * pData; + UINT8 * pEnd; + CONST DT_PAGE * pPage; + CONST DT_PAGE * pPageEnd; + UINT8 * pVerb; + UINT8 * pVersion; + UINT8 * pWebPage; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Assume the request is not finished + // + *pbDone = FALSE; + Status = EFI_SUCCESS; + for ( ; ; ) { + + // + // Attempt to parse the command + // + pData = &pPort->Request[0]; + pEnd = &pData [ pPort->RequestLength ]; + pVerb = pData; + pWebPage = HttpReplaceSpace ( pVerb, pEnd ); + if ( pEnd <= pWebPage ) { + break; + } + pVersion = HttpReplaceSpace ( pWebPage, pEnd ); + if ( pEnd <= pVersion ) { + break; + } + + // + // Validate the request + // + if ( 0 != HttpMatch ( L"GET", pVerb, TRUE )) { + // + // Invalid request type + // + DEBUG (( DEBUG_REQUEST, + "HTTP: Invalid verb\r\n" )); + Status = EFI_NOT_FOUND; + break; + } + + // + // Walk the page table + // + pPage = &mPageList[0]; + pPageEnd = &pPage [ mPageCount ]; + while ( pPageEnd > pPage ) { + // + // Determine if the page was located + // + if ( 0 == HttpMatch ( pPage->pPageName, pWebPage, FALSE )) { + break; + } + + // + // Set the next page + // + pPage += 1; + } + if ( pPageEnd <= pPage ) { + // + // The page was not found + // + DEBUG (( DEBUG_REQUEST, + "HTTP: Page not found in page table\r\n" )); + Status = EFI_NOT_FOUND; + break; + } + + // + // Respond with the page contents + // + Status = pPage->pfnResponse ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return page not found if necessary + // + if ( EFI_NOT_FOUND == Status ) { + Status = HttpPageNotFound ( SocketFD, pPort, pbDone ); + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Buffer data for sending + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] LengthInBytes Length of valid data in the buffer + @param [in] pBuffer Buffer of data to send + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSend ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN size_t LengthInBytes, + IN CONST UINT8 * pBuffer + ) +{ + size_t DataBytes; + size_t MaxBytes; + EFI_STATUS Status; + + // + // Assume success + // + Status = EFI_SUCCESS; + do { + // + // Determine how much data fits into the buffer + // + MaxBytes = sizeof ( pPort->TxBuffer ); + DataBytes = MaxBytes - pPort->TxBytes; + if ( DataBytes > LengthInBytes ) + { + DataBytes = LengthInBytes; + } + + // + // Copy the data into the buffer + // + CopyMem ( &pPort->TxBuffer [ pPort->TxBytes ], + pBuffer, + DataBytes ); + + // + // Account for the data copied + // + pPort->TxBytes += DataBytes; + LengthInBytes -= DataBytes; + + // + // Transmit the buffer if it is full + // + if ( MaxBytes <= pPort->TxBytes ) { + Status = HttpFlush ( SocketFD, pPort ); + } + } while (( EFI_SUCCESS == Status ) && ( 0 < LengthInBytes )); + + // + // Return the operation status + // + return Status; +} + + +/** + Send an ANSI string + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pString A zero terminated Unicode string + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendAnsiString ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST char * pString + ) +{ + CONST char * pData; + EFI_STATUS Status; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the characters in he string + // + pData = pString; + while ( 0 != *pData ) { + pData += 1; + } + + // + // Send the string + // + Status = HttpSend ( SocketFD, + pPort, + pData - pString, + (CONST UINT8 *)pString ); + + // + // Return the operation status + // + return Status; +} + + +/** + Buffer a single byte + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] Data The data byte to send + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendByte ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN UINT8 Data + ) +{ + EFI_STATUS Status; + + // + // Send the data byte + // + Status = HttpSend ( SocketFD, + pPort, + 1, + &Data ); + + // + // Return the operation status + // + return Status; +} + + +/** + Display a character + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] Character Character to display + @param [in] pReplacement Replacement character string + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendCharacter ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CHAR8 Character, + IN CHAR8 * pReplacement + ) +{ + EFI_STATUS Status; + + // + // Determine if this is a printable character + // + if (( 0x20 <= Character ) && ( 0x7f > Character )) { + if ( '<' == Character ) { + // + // Replace with HTML equivalent + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<" ); + } + else if ( '>' == Character ) { + // + // Replace with HTML equivalent + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + ">" ); + } + else if ( '&' == Character ) { + // + // Replace with HTML equivalent + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "&" ); + } + else if ( '\"' == Character ) { + // + // Replace with HTML equivalent + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + """ ); + } + else { + // + // Display the character + // + Status = HttpSendByte ( SocketFD, + pPort, + Character ); + } + } + else { + // + // Not a displayable character + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + pReplacement ); + } + + // + // Return the operation status + // + return Status; +} + + +/** + Send a buffer dump + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] ByteCount The number of bytes to display + @param [in] pData Address of the byte array + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendDump ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN UINTN ByteCount, + IN CONST UINT8 * pData + ) +{ + INTN BytesToDisplay; + UINT8 Character; + INTN Index; + INTN InitialSpaces; + CONST UINT8 * pDataEnd; + CONST UINT8 * pEnd; + CONST UINT8 * pTemp; + EFI_STATUS Status; + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Start the field value + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Walk the bytes to be displayed + // + pEnd = &pData [ ByteCount ]; + while ( pEnd > pData ) { + // + // Display the address + // + Status = HttpSendHexBits ( SocketFD, + pPort, + sizeof ( pData ) * 8, + (UINT64)pData ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Separate the address and data + // + Status = HttpSendByte ( SocketFD, pPort, ':' ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Position the starting data correctly + // + InitialSpaces = (UINTN)pData; + InitialSpaces &= BYTES_ON_A_LINE - 1; + for ( Index = SPACES_ADDRESS_TO_DATA + + (( 2 + SPACES_BETWEEN_BYTES ) + * InitialSpaces ); + 0 < Index; Index-- ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + " " ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the data + // + BytesToDisplay = pEnd - pData; + if (( BYTES_ON_A_LINE - InitialSpaces ) < BytesToDisplay ) { + BytesToDisplay = BYTES_ON_A_LINE - InitialSpaces; + } + pDataEnd = &pData [ BytesToDisplay ]; + pTemp = pData; + while ( pDataEnd > pTemp ) { + Status = HttpSendHexBits ( SocketFD, + pPort, + 8, + *pTemp++ ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Separate the data bytes + // + for ( Index = SPACES_BETWEEN_BYTES; 0 < Index; Index-- ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + " " ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Separate the data from the ASCII display + // + for ( Index = (( 2 + SPACES_BETWEEN_BYTES ) + * ( BYTES_ON_A_LINE - BytesToDisplay - InitialSpaces )) + - SPACES_BETWEEN_BYTES + + SPACES_DATA_TO_ASCII + + InitialSpaces; + 0 < Index; Index-- ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + " " ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the ASCII data + // + while ( pDataEnd > pData ) { + Character = *pData++; + Status = HttpSendCharacter ( SocketFD, + pPort, + Character, + "." ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Terminate the line + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Terminate the field value and row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code>\r\n" ); + break; + } + + // + // Return the operation status + // + return Status; +} + + +/** + Display a row containing a GUID value + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pGuid Address of the GUID to display + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendGuid ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST EFI_GUID * pGuid + ) +{ + UINT32 Index; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Display the GUID in a form found in the code + // + // E.g. 0xca16005f, 0x11ec, 0x4bdc, { 0x99, 0x97, 0x27, 0x2c, 0xa9, 0xba, 0x15, 0xe5 } + // + + // + // Display the first 32 bits + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + 32, + pGuid->Data1 ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the second 16 bits + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + ", 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + 16, + pGuid->Data2 ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Display the thrid 16 bits + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + ", 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + 16, + pGuid->Data3 ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Place the last 64 bits in braces + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + ", { 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + for ( Index = 0; 7 >= Index; Index++ ) { + // + // Display the next 8 bits + // + Status = HttpSendHexBits ( SocketFD, + pPort, + 8, + pGuid->Data4 [ Index ]); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Separate the bytes + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + ( 7 != Index ) ? ", 0x" : " }" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Output a hex value to the HTML page + + @param [in] SocketFD Socket file descriptor + @param [in] pPort The WSDT_PORT structure address + @param [in] Bits Number of bits to display + @param [in] Value Value to display + + @retval EFI_SUCCESS Successfully displayed the address +**/ +EFI_STATUS +HttpSendHexBits ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN INT32 Bits, + IN UINT64 Value + ) +{ + UINT32 Digit; + INT32 Shift; + EFI_STATUS Status; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the list of divisors + // + Shift = (( Bits + 3 ) & ( ~3 )) - 4; + while ( 0 <= Shift ) { + // + // Determine the next digit + // + Digit = (UINT32)(( Value >> Shift ) & 0xf ); + if ( 10 <= Digit ) { + Digit += 'A' - '0' - 10; + } + + // + // Display the digit + // + Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Set the next shift + // + Shift -= 4; + } + + // + // Return the operation status + // + return Status; +} + + +/** + Output a hex value to the HTML page + + @param [in] SocketFD Socket file descriptor + @param [in] pPort The WSDT_PORT structure address + @param [in] Value Value to display + + @retval EFI_SUCCESS Successfully displayed the address +**/ +EFI_STATUS +HttpSendHexValue ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN UINT64 Value + ) +{ + BOOLEAN bDisplayZeros; + UINT32 Digit; + INT32 Shift; + EFI_STATUS Status; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the list of divisors + // + bDisplayZeros = FALSE; + Shift = 60; + do { + // + // Determine the next digit + // + Digit = (UINT32)(( Value >> Shift ) & 0xf ); + if ( 10 <= Digit ) { + Digit += 'A' - '0' - 10; + } + + // + // Suppress leading zeros + // + if (( 0 != Digit ) || bDisplayZeros || ( 0 == Shift )) { + bDisplayZeros = TRUE; + + // + // Display the digit + // + Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Set the next shift + // + Shift -= 4; + } while ( 0 <= Shift ); + + // + // Return the operation status + // + return Status; +} + + +/** + Output an IP address to the HTML page + + @param [in] SocketFD Socket file descriptor + @param [in] pPort The WSDT_PORT structure address + @param [in] pAddress Address of the socket address + + @retval EFI_SUCCESS Successfully displayed the address +**/ +EFI_STATUS +HttpSendIpAddress ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN struct sockaddr_in * pAddress + ) +{ + EFI_STATUS Status; + + // + // Output the IPv4 address + // + Status = HttpSendValue ( SocketFD, pPort, (UINT8)pAddress->sin_addr.s_addr ); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendByte ( SocketFD, pPort, '.' ); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 8 )); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendByte ( SocketFD, pPort, '.' ); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 16 )); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendByte ( SocketFD, pPort, '.' ); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendValue ( SocketFD, pPort, (UINT8)( pAddress->sin_addr.s_addr >> 24 )); + if ( !EFI_ERROR ( Status )) { + // + // Output the port number + // + Status = HttpSendByte ( SocketFD, pPort, ':' ); + if ( !EFI_ERROR ( Status )) { + Status = HttpSendValue ( SocketFD, pPort, htons ( pAddress->sin_port )); + } + } + } + } + } + } + } + } + + // + // Return the operation status + // + return Status; +} + + +/** + Send a Unicode string + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pString A zero terminated Unicode string + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HttpSendUnicodeString ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST UINT16 * pString + ) +{ + UINT8 Data; + UINT16 Character; + EFI_STATUS Status; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the characters in he string + // + while ( 0 != ( Character = *pString++ )) { + // + // Convert the character to UTF-8 + // + if ( 0 != ( Character & 0xf800 )) { + // + // Send the upper 4 bits + // + Data = (UINT8)(( Character >> 12 ) & 0xf ); + Data |= 0xe0; + Status = HttpSendByte ( SocketFD, + pPort, + Data ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the next 6 bits + // + Data = (UINT8)(( Character >> 6 ) & 0x3f ); + Data |= 0x80; + Status = HttpSendByte ( SocketFD, + pPort, + Data ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the last 6 bits + // + Data = (UINT8)( Character & 0x3f ); + Data |= 0x80; + } + else if ( 0 != ( Character & 0x0780 )) { + // + // Send the upper 5 bits + // + Data = (UINT8)(( Character >> 6 ) & 0x1f ); + Data |= 0xc0; + Status = HttpSendByte ( SocketFD, + pPort, + Data ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the last 6 bits + // + Data = (UINT8)( Character & 0x3f ); + Data |= 0x80; + } + else { + Data = (UINT8)( Character & 0x7f ); + } + + // + // Send the last data byte + // + Status = HttpSendByte ( SocketFD, + pPort, + Data ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Return the operation status + // + return Status; +} + + +/** + Output a value to the HTML page + + @param [in] SocketFD Socket file descriptor + @param [in] pPort The WSDT_PORT structure address + @param [in] Value Value to display + + @retval EFI_SUCCESS Successfully displayed the address +**/ +EFI_STATUS +HttpSendValue ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN UINT64 Value + ) +{ + BOOLEAN bDisplayZeros; + UINT64 Digit; + CONST UINT64 * pEnd; + CONST UINT64 * pDivisor; + CONST UINT64 pDivisors [ ] = { + 10000000000000000000L, + 1000000000000000000L, + 100000000000000000L, + 10000000000000000L, + 1000000000000000L, + 100000000000000L, + 10000000000000L, + 1000000000000L, + 100000000000L, + 10000000000L, + 1000000000L, + 100000000L, + 10000000L, + 1000000L, + 100000L, + 10000L, + 1000L, + 100L, + 10L + }; + EFI_STATUS Status; + UINT64 Temp; + + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Walk the list of divisors + // + bDisplayZeros = FALSE; + pDivisor = &pDivisors[0]; + pEnd = &pDivisor [ sizeof ( pDivisors ) / sizeof ( pDivisors [0])]; + while ( pEnd > pDivisor ) { + // + // Determine the next digit + // + Digit = Value / *pDivisor; + + // + // Suppress leading zeros + // + if (( 0 != Digit ) || bDisplayZeros ) { + bDisplayZeros = TRUE; + + // + // Display the digit + // + Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Digit )); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine the remainder + // + Temp = *pDivisor * Digit; + Value -= Temp; + } + + // + // Set the next divisor + // + pDivisor += 1; + } + + // + // Display the final digit + // + if ( !EFI_ERROR ( Status )) { + Status = HttpSendByte ( SocketFD, pPort, (UINT8)( '0' + Value )); + } + + // + // Return the operation status + // + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/Handles.c b/AppPkg/Applications/Sockets/WebServer/Handles.c new file mode 100644 index 0000000000..f39620aa48 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/Handles.c @@ -0,0 +1,294 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the handles in the system + +**/ + +#include <WebServer.h> + + +/** + Respond with the handles in the system + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HandlePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + INTN Digit; + INTN Entries; + INTN Index; + UINTN GuidCount; + UINTN LengthInBytes; + UINT8 * pDigit; + EFI_HANDLE * pHandleArray; + EFI_HANDLE * pHandle; + EFI_HANDLE * pHandleEnd; + EFI_GUID ** ppGuidArray; + EFI_GUID ** ppGuid; + EFI_GUID ** ppGuidEnd; + INTN Shift; + EFI_STATUS Status; + UINTN Value; + CONST UINTN cDigit [] = { + 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; + + DBG_ENTER ( ); + + // + // Send the handles page + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"Handle Database" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table header + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>Handle Database</h1>\r\n" + "<table border=\"1\">\r\n" + " <tr bgcolor=\"c0c0ff\"><th>Handle</th><th>Protocol Guids</th></tr>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine the number of handles in the database + // + LengthInBytes = 0; + Status = gBS->LocateHandle ( AllHandles, + NULL, + NULL, + &LengthInBytes, + NULL ); + if ( EFI_BUFFER_TOO_SMALL == Status ) { + // + // Allocate space for the handles + // + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + LengthInBytes, + (VOID **) &pHandleArray ); + if ( !EFI_ERROR ( Status )) { + // + // Get the list of handles + // + Status = gBS->LocateHandle ( AllHandles, + NULL, + NULL, + &LengthInBytes, + pHandleArray ); + if ( !EFI_ERROR ( Status )) { + Entries = LengthInBytes / sizeof ( *pHandleArray ); + pHandle = pHandleArray; + pHandleEnd = &pHandle [ Entries ]; + while ( pHandleEnd > pHandle ) { + // + // Build the table entry for this page + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td><code>0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Value = (UINTN) *pHandle; + for ( Shift = ( sizeof ( Shift ) << 3 ) - 4; 0 <= Shift; Shift -= 4 ) { + // + // Convert the next address nibble to ANSI hex + // + Digit = (( Value >> Shift ) & 0xf ) | '0'; + if ( '9' < Digit ) { + Digit += 'a' - '0' - 10; + } + + // + // Display the address digit + // + Status = HttpSendByte ( SocketFD, + pPort, + (UINT8) Digit ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Start the second column + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td><td><code>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine the number of protocols connected to this handle + // + Status = gBS->ProtocolsPerHandle ( *pHandle, + &ppGuidArray, + &GuidCount ); + if ( EFI_ERROR ( Status )) { + break; + } + ppGuid = ppGuidArray; + ppGuidEnd = &ppGuid [ GuidCount ]; + while ( ppGuidEnd > ppGuid ) { + // + // Display the guid + // + pDigit = (UINT8 *) *ppGuid; + for ( Index = 0; 16 > Index; Index++ ) { + // + // Separate the portions of the GUID + // 99E87DCF-6162-40c5-9FA1-32111F5197F7 + // + if (( 4 == Index ) + || ( 6 == Index ) + || ( 8 == Index ) + || ( 10 == Index )) { + Status = HttpSendByte ( SocketFD, + pPort, + '-' ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Display the GUID digits + // + Value = pDigit [ cDigit [ Index ]]; + for ( Shift = 4; 0 <= Shift; Shift -= 4 ) { + // + // Convert the next address nibble to ANSI hex + // + Digit = (( Value >> Shift ) & 0xf ) | '0'; + if ( '9' < Digit ) { + Digit += 'a' - '0' - 10; + } + + // + // Display the address digit + // + Status = HttpSendByte ( SocketFD, + pPort, + (UINT8) Digit ); + if ( EFI_ERROR ( Status )) { + break; + } + } + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Separate each GUID + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<br/>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Set the next protocol + // + ppGuid+= 1; + } + + // + // Free the GUID array + // + gBS->FreePool ( ppGuidArray ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // End the row + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Set the next handle + // + pHandle += 1; + } + } + + // + // Done with the handle array + // + gBS->FreePool ( pHandleArray ); + } + } + + // + // Build the table trailer + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</table>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/Hello.c b/AppPkg/Applications/Sockets/WebServer/Hello.c new file mode 100644 index 0000000000..5f65133f47 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/Hello.c @@ -0,0 +1,87 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Hello World response page + +**/ + +#include <WebServer.h> + + +/** + Respond with the Hello World page + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +HelloPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the Hello World page + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"Hello World" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page body + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>Hello World</h1>\r\n" + "<p>\r\n" + " This response was generated by the UEFI web server application.\r\n" + "</p>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/Index.c b/AppPkg/Applications/Sockets/WebServer/Index.c new file mode 100644 index 0000000000..688d197282 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/Index.c @@ -0,0 +1,161 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Generate the list of known pages. + +**/ + +#include <WebServer.h> + + +/** + Respond with the list of known pages + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +IndexPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + CONST DT_PAGE * pPage; + CONST DT_PAGE * pPageEnd; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the index page + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"Index" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table header + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>UEFI Web Server</h1>\r\n" + "<table border=\"1\">\r\n" + " <tr bgcolor=\"c0c0ff\"><th>Page</th><th>Description</th></tr>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Walk the list of pages + // Skip the first page + // + pPage = &mPageList[0]; + pPageEnd = &pPage[mPageCount]; + pPage += 1; + while ( pPageEnd > pPage ) { + // + // Build the table entry for this page + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td><a target=\"_blank\" href=\"" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + &pPage->pPageName[1]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "\">" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + &pPage->pPageName[1]); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</a></td><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pPage->pDescription ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td></tr>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Set the next page + // + pPage += 1; + } + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</table>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/PageList.c b/AppPkg/Applications/Sockets/WebServer/PageList.c new file mode 100644 index 0000000000..5eccfb2181 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/PageList.c @@ -0,0 +1,59 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + List of pages to display + +**/ + +#include <WebServer.h> + + +/** + List of pages in the system +**/ +CONST DT_PAGE mPageList [] = { + + // + // The index page must be first + // + { L"/", IndexPage, L"Index of pages" }, ///< List the pages + + // + // All other pages follow in alphabetical order + // + { PAGE_BOOT_SERVICES_TABLE, BootServicesTablePage, L"Boot Services Table" }, ///< Format boot services table + { PAGE_CONFIGURATION_TABLE, ConfigurationTablePage, L"Configuration Table" }, ///< Format configuration table + { L"/DhcpOptions", DhcpOptionsPage, L"DHCP Options" }, ///< Display the DHCP options + { PAGE_ACPI_DSDT, AcpiDsdtPage, L"DSDT - Differentiated System Description Table" }, ///< Format DSDT + { PAGE_DXE_SERVICES_TABLE, DxeServicesTablePage, L"DXE Services Table" }, ///< Format DXE services table + { PAGE_ACPI_FADT, AcpiFadtPage, L"FADT - Fixed ACPI Description Table" }, ///< Format FADT + { L"/Firmware", FirmwarePage, L"Firmware" }, ///< Firmware status + { L"/Handles", HandlePage, L"Display handles and associated protocol GUIDs" }, ///< Handle database page + { L"/Hello", HelloPage, L"Hello World" }, ///< Hello world page + { L"/Reboot", RebootPage, L"Reboot the sytem" }, ///< Reboot page + { PAGE_ACPI_RSDP_10B, AcpiRsdp10Page, L"RSDP 1.0b - ACPI Root System Description Pointer" }, ///< Format RSDP 1.0b table + { PAGE_ACPI_RSDP_30, AcpiRsdp30Page, L"RSDP 3.0 - ACPI Root System Description Pointer" }, ///< Format RSDP 3.0 table + { PAGE_ACPI_RSDT, AcpiRsdtPage, L"RSDT - ACPI Root System Description Table" }, ///< Format RSDT + { PAGE_RUNTIME_SERVICES_TABLE, RuntimeSservicesTablePage, L"Runtime Services Table" },///< Format runtime services table + { L"/SystemTable", SystemTablePage, L"System Table" } ///< Format system table +}; + +CONST UINTN mPageCount = DIM ( mPageList ); diff --git a/AppPkg/Applications/Sockets/WebServer/Reboot.c b/AppPkg/Applications/Sockets/WebServer/Reboot.c new file mode 100644 index 0000000000..51c72d67ec --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/Reboot.c @@ -0,0 +1,105 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Reboot the system + +**/ + +#include <WebServer.h> +#include <Library/UefiRuntimeServicesTableLib.h> + + +/** + Page to reboot the system + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RebootPage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the Hello World page + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, L"Reboot" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page body + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>Reboot</h1>\r\n" + "<p>\r\n" + " Ouch! The system is rebooting!\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Deliver the data to the remote system by + // closing the socket + // + close ( SocketFD ); + + // + // Attempt to reboot the system + // + DEBUG (( DEBUG_REQUEST, "Reseting System\r\n" )); + gRT->ResetSystem ( EfiResetCold, + EFI_SUCCESS, + 0, + NULL ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/RuntimeServicesTable.c b/AppPkg/Applications/Sockets/WebServer/RuntimeServicesTable.c new file mode 100644 index 0000000000..778d3bbba9 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/RuntimeServicesTable.c @@ -0,0 +1,227 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the runtime services table + +**/ + +#include <WebServer.h> +#include <Library/UefiRuntimeServicesTableLib.h> + +/** + Respond with the runtime services table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RuntimeSservicesTablePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the runtime services page + // + for ( ; ; ) { + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"Runtime Services Table", gRT ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The table header for the EFI Runtime Services Table. + /// + Status = EfiTableHeader ( SocketFD, + pPort, + &gRT->Hdr ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Time Services + // + Status = RowPointer ( SocketFD, + pPort, + "GetTime", + (VOID *)gRT->GetTime, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetTime", + (VOID *)gRT->SetTime, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetWakeupTime", + (VOID *)gRT->GetWakeupTime, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetWakeupTime", + (VOID *)gRT->SetWakeupTime, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Virtual Memory Services + // + Status = RowPointer ( SocketFD, + pPort, + "SetVirtualAddressMap", + (VOID *)gRT->SetVirtualAddressMap, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "ConvertPointer", + (VOID *)gRT->ConvertPointer, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Variable Services + // + Status = RowPointer ( SocketFD, + pPort, + "GetVariable", + (VOID *)gRT->GetVariable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "GetNextVariableName", + (VOID *)gRT->GetNextVariableName, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "SetVariable", + (VOID *)gRT->SetVariable, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Miscellaneous Services + // + Status = RowPointer ( SocketFD, + pPort, + "GetNextHighNonotonicCount", + (VOID *)gRT->GetNextHighMonotonicCount, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "ResetSystem", + (VOID *)gRT->ResetSystem, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Determine if the structures supports 2.0 services + // + if ( 2 <= ( gRT->Hdr.Revision >> 16 )) { + // + // UEFI 2.0 Capsule Services + // + Status = RowPointer ( SocketFD, + pPort, + "UpdateCapsule", + (VOID *)gRT->UpdateCapsule, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = RowPointer ( SocketFD, + pPort, + "QueryCapsuleCapabilities", + (VOID *)gRT->QueryCapsuleCapabilities, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Miscellaneous UEFI 2.0 Service + // + Status = RowPointer ( SocketFD, + pPort, + "QueryVariableInfo", + (VOID *)gRT->QueryVariableInfo, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/SystemTable.c b/AppPkg/Applications/Sockets/WebServer/SystemTable.c new file mode 100644 index 0000000000..0d2a1f2040 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/SystemTable.c @@ -0,0 +1,863 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + Display the system table + +**/ + +#include <WebServer.h> + + +/** + Display the EFI Table Header + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pHeader Address of the EFI_TABLE_HEADER structure + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +EfiTableHeader ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN EFI_TABLE_HEADER * pHeader + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the handles page + // + for ( ; ; ) { + /// + /// A 64-bit signature that identifies the type of table that follows. + /// Unique signatures have been generated for the EFI System Table, + /// the EFI Boot Services Table, and the EFI Runtime Services Table. + /// + Status = RowHexValue ( SocketFD, + pPort, + "Hdr.Signature", + pHeader->Signature, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The revision of the EFI Specification to which this table + /// conforms. The upper 16 bits of this field contain the major + /// revision value, and the lower 16 bits contain the minor revision + /// value. The minor revision values are limited to the range of 00..99. + /// + Status = RowRevision ( SocketFD, + pPort, + "Hdr.Revision", + pHeader->Revision ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The size, in bytes, of the entire table including the EFI_TABLE_HEADER. + /// + Status = RowDecimalValue ( SocketFD, + pPort, + "Hdr.HeaderSize", + pHeader->HeaderSize ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The 32-bit CRC for the entire table. This value is computed by + /// setting this field to 0, and computing the 32-bit CRC for HeaderSize bytes. + /// + Status = RowHexValue ( SocketFD, + pPort, + "Hdr.CRC", + pHeader->CRC32, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// Reserved field that must be set to 0. + /// + Status = RowHexValue ( SocketFD, + pPort, + "Hdr.Reserved", + pHeader->Reserved, + NULL ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Display a row containing a decimal value + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] Value The value to display + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowDecimalValue ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN UINT64 Value + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + Value ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Display a row containing a hex value + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] Value The value to display + @param [in] pWebPage Address of a zero terminated web page name + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowHexValue ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN UINT64 Value, + IN CONST CHAR16 * pWebPage + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<a target=\"_blank\" href=\"" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pWebPage ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "\">" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendHexValue ( SocketFD, + pPort, + Value ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</a>" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Display a row containing a pointer + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] pAddress The address to display + @param [in] pWebPage Address of a zero terminated web page name + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowPointer ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN CONST VOID * pAddress, + IN CONST CHAR16 * pWebPage + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<a target=\"_blank\" href=\"" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pWebPage ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "\">" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + sizeof ( pAddress ) * 8, + (UINT64) pAddress ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pWebPage ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</a>" ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Display a row containing a revision + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] Revision The revision to display + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowRevision ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN UINT32 Revision + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td><code>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + Revision >> 16 ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendByte ( SocketFD, + pPort, + '.' ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendValue ( SocketFD, + pPort, + Revision & 0xFFFF ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</code></td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Display a row containing a unicode string + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] pString Address of a zero terminated unicode string + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +RowUnicodeString ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR8 * pName, + IN CONST CHAR16 * pString + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<tr><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td><td>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pString ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</td></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Start the table page + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [in] pName Address of a zero terminated name string + @param [in] pTable Address of the table + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +TableHeader ( + IN int SocketFD, + IN WSDT_PORT * pPort, + IN CONST CHAR16 * pName, + IN CONST VOID * pTable + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Send the page header + // + Status = HttpPageHeader ( SocketFD, pPort, pName ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table header + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "<h1>" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendUnicodeString ( SocketFD, + pPort, + pName ); + if ( EFI_ERROR ( Status )) { + break; + } + if ( NULL != pTable ) { + Status = HttpSendAnsiString ( SocketFD, + pPort, + ": 0x" ); + if ( EFI_ERROR ( Status )) { + break; + } + Status = HttpSendHexBits ( SocketFD, + pPort, + sizeof ( pTable ) * 8, + (UINT64)pTable ); + if ( EFI_ERROR ( Status )) { + break; + } + } + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</h1>\r\n" + "<table border=\"1\">\r\n" + " <tr bgcolor=\"c0c0ff\"><th>Field Name</th><th>Value</th></tr>\r\n" ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + End the table page + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +TableTrailer ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN *pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Build the table trailer + // + Status = HttpSendAnsiString ( SocketFD, + pPort, + "</table>\r\n" ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Send the page trailer + // + Status = HttpPageTrailer ( SocketFD, pPort, pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Respond with the system table + + @param [in] SocketFD The socket's file descriptor to add to the list. + @param [in] pPort The WSDT_PORT structure address + @param [out] pbDone Address to receive the request completion status + + @retval EFI_SUCCESS The request was successfully processed + +**/ +EFI_STATUS +SystemTablePage ( + IN int SocketFD, + IN WSDT_PORT * pPort, + OUT BOOLEAN * pbDone + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Send the system table page + // + for ( ; ; ) { + // + // Send the page and table header + // + Status = TableHeader ( SocketFD, pPort, L"System Table", gST ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The table header for the EFI System Table. + /// + Status = EfiTableHeader ( SocketFD, + pPort, + &gST->Hdr ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to a null terminated string that identifies the vendor + /// that produces the system firmware for the platform. + /// + Status = RowUnicodeString ( SocketFD, + pPort, + "FirmwareVendor", + gST->FirmwareVendor ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A firmware vendor specific value that identifies the revision + /// of the system firmware for the platform. + /// + Status = RowRevision ( SocketFD, + pPort, + "FirmwareRevision", + gST->FirmwareRevision ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The handle for the active console input device. This handle must support + /// EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. + /// + Status = RowPointer ( SocketFD, + pPort, + "ConsoleInHandle", + (VOID *)gST->ConsoleInHandle, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is + /// associated with ConsoleInHandle. + /// + Status = RowPointer ( SocketFD, + pPort, + "ConIn", + (VOID *)gST->ConIn, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The handle for the active console output device. + /// + Status = RowPointer ( SocketFD, + pPort, + "ConsoleOutHandle", + (VOID *)gST->ConsoleOutHandle, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface + /// that is associated with ConsoleOutHandle. + /// + Status = RowPointer ( SocketFD, + pPort, + "ConOut", + (VOID *)gST->ConOut, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The handle for the active standard error console device. + /// This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + /// + Status = RowPointer ( SocketFD, + pPort, + "StandardErrorHandle", + (VOID *)gST->StandardErrorHandle, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface + /// that is associated with StandardErrorHandle. + /// + Status = RowPointer ( SocketFD, + pPort, + "StdErr", + (VOID *)gST->StdErr, + NULL ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to the EFI Runtime Services Table. + /// + Status = RowPointer ( SocketFD, + pPort, + "RuntimeServices", + (VOID *)gST->RuntimeServices, + PAGE_RUNTIME_SERVICES_TABLE ); + + /// + /// A pointer to the EFI Boot Services Table. + /// + Status = RowPointer ( SocketFD, + pPort, + "BootServices", + (VOID *)gST->BootServices, + PAGE_BOOT_SERVICES_TABLE ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// The number of system configuration tables in the buffer ConfigurationTable. + /// + Status = RowDecimalValue ( SocketFD, + pPort, + "NumberOfTableEntries", + gST->NumberOfTableEntries ); + if ( EFI_ERROR ( Status )) { + break; + } + + /// + /// A pointer to the system configuration tables. + /// The number of entries in the table is NumberOfTableEntries. + /// + Status = RowPointer ( SocketFD, + pPort, + "ConfigurationTable", + (VOID *)gST->ConfigurationTable, + PAGE_CONFIGURATION_TABLE ); + if ( EFI_ERROR ( Status )) { + break; + } + + // + // Build the table trailer + // + Status = TableTrailer ( SocketFD, + pPort, + pbDone ); + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/WebServer.c b/AppPkg/Applications/Sockets/WebServer/WebServer.c new file mode 100644 index 0000000000..00bf4b6fef --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/WebServer.c @@ -0,0 +1,853 @@ +/*++ + This file contains an 'Intel UEFI Application' and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2011 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +--*/ + +/** @file + This is a simple shell application + + This should be executed with "/Param2 Val1" and "/Param1" as the 2 command line options! + +**/ + +#include <WebServer.h> + +DT_WEB_SERVER mWebServer; ///< Web server's control structure + + +/** + Add a port to the list of ports to be polled. + + @param [in] pWebServer The web server control structure address. + + @param [in] SocketFD The socket's file descriptor to add to the list. + + @retval EFI_SUCCESS The port was successfully added + @retval EFI_NO_RESOURCES Insufficient memory to add the port + +**/ +EFI_STATUS +PortAdd ( + IN DT_WEB_SERVER * pWebServer, + IN int SocketFD + ) +{ + nfds_t Index; + size_t LengthInBytes; + nfds_t MaxEntries; + nfds_t MaxEntriesNew; + struct pollfd * pFdList; + struct pollfd * pFdListNew; + WSDT_PORT ** ppPortListNew; + WSDT_PORT * pPort; + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Use for/break instead of goto + // + for ( ; ; ) { + // + // Assume success + // + Status = EFI_SUCCESS; + + // + // Create a new list if necessary + // + pFdList = pWebServer->pFdList; + MaxEntries = pWebServer->MaxEntries; + if ( pWebServer->Entries >= MaxEntries ) { + MaxEntriesNew = 16 + MaxEntries; + + // + // The current FD list is full + // Allocate a new FD list + // + LengthInBytes = sizeof ( *pFdList ) * MaxEntriesNew; + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + LengthInBytes, + (VOID **)&pFdListNew ); + if ( EFI_ERROR ( Status )) { + DEBUG (( DEBUG_ERROR | DEBUG_POOL, + "ERROR - Failed to allocate the FD list, Status: %r\r\n", + Status )); + break; + } + + // + // Allocate a new port list + // + LengthInBytes = sizeof ( *ppPortListNew ) * MaxEntriesNew; + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + LengthInBytes, + (VOID **) &ppPortListNew ); + if ( EFI_ERROR ( Status )) { + DEBUG (( DEBUG_ERROR | DEBUG_POOL, + "ERROR - Failed to allocate the port list, Status: %r\r\n", + Status )); + + // + // Free the new FD list + // + gBS->FreePool ( pFdListNew ); + break; + } + + // + // Duplicate the FD list + // + Index = MaxEntries; + if ( NULL != pFdList ) { + CopyMem ( pFdListNew, + pFdList, + Index * sizeof ( *pFdList )); + } + + // + // Initialize the new entries in the FD list + // + for ( ; MaxEntriesNew > Index; Index++ ) { + pFdListNew [ Index ].fd = -1; + pFdListNew [ Index ].events = 0; + pFdListNew [ Index ].revents = 0; + } + + // + // Free the old FD list + // + if ( NULL != pFdList ) { + gBS->FreePool ( pFdList ); + } + + // + // Switch to the new FD list + // + pWebServer->pFdList = pFdListNew; + pFdList = pWebServer->pFdList; + + // + // Duplicate the port list + // + Index = MaxEntries; + if ( NULL != pWebServer->ppPortList ) { + CopyMem ( ppPortListNew, + pWebServer->ppPortList, + Index * sizeof ( *ppPortListNew )); + } + + // + // Initialize the new entries in the port list + // + for ( ; MaxEntriesNew > Index; Index++ ) { + ppPortListNew [ Index ] = NULL; + } + + // + // Free the old port list + // + if ( NULL != pWebServer->ppPortList ) { + gBS->FreePool ( pWebServer->ppPortList ); + } + + // + // Switch to the new port list + // + pWebServer->ppPortList = ppPortListNew; + + // + // Update the list size + // + pWebServer->MaxEntries = MaxEntriesNew; + } + + // + // Allocate a new port + // + LengthInBytes = sizeof ( *pPort ); + Status = gBS->AllocatePool ( EfiRuntimeServicesData, + LengthInBytes, + (VOID **)&pPort ); + if ( EFI_ERROR ( Status )) { + DEBUG (( DEBUG_ERROR | DEBUG_POOL, + "ERROR - Failed to allocate the port, Status: %r\r\n", + Status )); + break; + } + + // + // Initialize the port + // + pPort->RequestLength = 0; + pPort->TxBytes = 0; + + // + // Add the socket to the FD list + // + pFdList [ pWebServer->Entries ].fd = SocketFD; + pFdList [ pWebServer->Entries ].events = POLLRDNORM + | POLLHUP; + pFdList [ pWebServer->Entries ].revents = 0; + + // + // Add the port to the port list + // + pWebServer->ppPortList [ pWebServer->Entries ] = pPort; + + // + // Account for the new entry + // + pWebServer->Entries += 1; + DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, + "WebServer handling %d ports\r\n", + pWebServer->Entries )); + + // + // All done + // + break; + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Remove a port from the list of ports to be polled. + + @param [in] pWebServer The web server control structure address. + + @param [in] SocketFD The socket's file descriptor to add to the list. + +**/ +VOID +PortRemove ( + IN DT_WEB_SERVER * pWebServer, + IN int SocketFD + ) +{ + nfds_t Entries; + nfds_t Index; + struct pollfd * pFdList; + WSDT_PORT ** ppPortList; + + DBG_ENTER ( ); + + // + // Attempt to remove the entry from the list + // + Entries = pWebServer->Entries; + pFdList = pWebServer->pFdList; + ppPortList = pWebServer->ppPortList; + for ( Index = 0; Entries > Index; Index++ ) { + // + // Locate the specified socket file descriptor + // + if ( SocketFD == pFdList [ Index ].fd ) { + // + // Determine if this is the listen port + // + if ( SocketFD == pWebServer->HttpListenPort ) { + pWebServer->HttpListenPort = -1; + } + + // + // Close the socket + // + close ( SocketFD ); + + // + // Free the port structure + // + gBS->FreePool ( ppPortList [ Index ]); + + // + // Remove this port from the list by copying + // the rest of the list down one entry + // + Entries -= 1; + for ( ; Entries > Index; Index++ ) { + pFdList [ Index ] = pFdList [ Index + 1 ]; + ppPortList [ Index ] = ppPortList [ Index + 1 ]; + } + pFdList [ Index ].fd = -1; + pFdList [ Index ].events = 0; + pFdList [ Index ].revents = 0; + ppPortList [ Index ] = NULL; + + // + // Update the number of entries in the list + // + pWebServer->Entries = Entries; + DEBUG (( DEBUG_PORT_WORK | DEBUG_INFO, + "WebServer handling %d ports\r\n", + pWebServer->Entries )); + break; + } + } + + DBG_EXIT ( ); +} + + +/** + Process the work for the sockets. + + @param [in] pWebServer The web server control structure address. + + @param [in] SocketFD The socket's file descriptor to add to the list. + + @param [in] events everts is a bitmask of the work to be done + + @param [in] pPort The address of a WSDT_PORT structure + + @retval EFI_SUCCESS The operation was successful + @retval EFI_DEVICE_ERROR Error, close the port + +**/ +EFI_STATUS +PortWork ( + IN DT_WEB_SERVER * pWebServer, + IN int SocketFD, + IN INTN events, + IN WSDT_PORT * pPort + ) +{ + BOOLEAN bDone; + size_t LengthInBytes; + int NewSocket; + EFI_STATUS OpStatus; + struct sockaddr RemoteAddress; + socklen_t RemoteAddressLength; + EFI_STATUS Status; + + DEBUG (( DEBUG_PORT_WORK, "Entering PortWork\r\n" )); + + // + // Assume success + // + OpStatus = EFI_SUCCESS; + + // + // Handle input events + // + if ( 0 != ( events & POLLRDNORM )) { + // + // Determine if this is a connection attempt + // + if ( SocketFD == pWebServer->HttpListenPort ) { + // + // Handle connection attempts + // Accepts arrive as read events + // + RemoteAddressLength = sizeof ( RemoteAddress ); + NewSocket = accept ( SocketFD, + &RemoteAddress, + &RemoteAddressLength ); + if ( -1 != NewSocket ) { + if ( 0 != NewSocket ) { + // + // Add this port to the list monitored by the web server + // + Status = PortAdd ( pWebServer, NewSocket ); + if ( EFI_ERROR ( Status )) { + DEBUG (( DEBUG_ERROR, + "ERROR - Failed to add the port 0x%08x, Status: %r\r\n", + NewSocket, + Status )); + + // + // Done with the new socket + // + close ( NewSocket ); + } + } + else { + DEBUG (( DEBUG_ERROR, + "ERROR - Socket not available!\r\n" )); + } + + // + // Leave the listen port open + // + } + else { + // + // Listen port error + // Close the listen port by returning error status + // + OpStatus = EFI_DEVICE_ERROR; + DEBUG (( DEBUG_ERROR, + "ERROR - Failed to accept new connection, errno: 0x%08x\r\n", + errno )); + } + } + else { + // + // Handle the data received event + // + if ( 0 == pPort->RequestLength ) { + // + // Receive the page request + // + pPort->RequestLength = recv ( SocketFD, + &pPort->Request[0], + DIM ( pPort->Request ), + 0 ); + if ( -1 == pPort->RequestLength ) { + // + // Receive error detected + // Close the port + // + OpStatus = EFI_DEVICE_ERROR; + } + else { + DEBUG (( DEBUG_REQUEST, + "0x%08x: Socket - Received %d bytes of HTTP request\r\n", + SocketFD, + pPort->RequestLength )); + + // + // Process the request + // + OpStatus = HttpRequest ( SocketFD, pPort, &bDone ); + if ( bDone ) { + // + // Notify the upper layer to close the socket + // + OpStatus = EFI_DEVICE_ERROR; + } + } + } + else + { + // + // Receive the file data + // + LengthInBytes = recv ( SocketFD, + &pPort->RxBuffer[0], + DIM ( pPort->RxBuffer ), + 0 ); + if ( -1 == LengthInBytes ) { + // + // Receive error detected + // Close the port + // + OpStatus = EFI_DEVICE_ERROR; + } + else { + DEBUG (( DEBUG_REQUEST, + "0x%08x: Socket - Received %d bytes of file data\r\n", + SocketFD, + LengthInBytes )); + + // + // TODO: Process the file data + // + } + } + } + } + + // + // Handle the close event + // + if ( 0 != ( events & POLLHUP )) { + // + // Close the port + // + OpStatus = EFI_DEVICE_ERROR; + } + + // + // Return the operation status + // + DEBUG (( DEBUG_PORT_WORK, + "Exiting PortWork, Status: %r\r\n", + OpStatus )); + return OpStatus; +} + + +/** + Scan the list of sockets and process any pending work + + @param [in] pWebServer The web server control structure address. + +**/ +VOID +SocketPoll ( + IN DT_WEB_SERVER * pWebServer + ) +{ + int FDCount; + struct pollfd * pPoll; + WSDT_PORT ** ppPort; + EFI_STATUS Status; + + DEBUG (( DEBUG_SOCKET_POLL, "Entering SocketPoll\r\n" )); + + // + // Determine if any ports are active + // + FDCount = poll ( pWebServer->pFdList, + pWebServer->Entries, + CLIENT_POLL_DELAY ); + if ( -1 == FDCount ) { + DEBUG (( DEBUG_ERROR | DEBUG_SOCKET_POLL, + "ERROR - errno: %d\r\n", + errno )); + } + + pPoll = pWebServer->pFdList; + ppPort = pWebServer->ppPortList; + while ( 0 < FDCount ) { + // + // Walk the list of ports to determine what work needs to be done + // + if ( 0 != pPoll->revents ) { + // + // Process this port + // + Status = PortWork ( pWebServer, + pPoll->fd, + pPoll->revents, + *ppPort ); + pPoll->revents = 0; + + // + // Close the port if necessary + // + if ( EFI_ERROR ( Status )) { + PortRemove ( pWebServer, pPoll->fd ); + pPoll -= 1; + ppPort -= 1; + } + + // + // Account for this file descriptor + // + FDCount -= 1; + } + + // + // Set the next port + // + pPoll += 1; + ppPort += 1; + } + + DEBUG (( DEBUG_SOCKET_POLL, "Exiting SocketPoll\r\n" )); +} + + +/** + Create the HTTP port for the web server + + This routine polls the network layer to create the HTTP port for the + web server. More than one attempt may be necessary since it may take + some time to get the IP address and initialize the upper layers of + the network stack. + + After the HTTP port is created, the socket layer will manage the + coming and going of the network connections until the last network + connection is broken. + + @param [in] pWebServer The web server control structure address. + +**/ +VOID +WebServerTimer ( + IN DT_WEB_SERVER * pWebServer + ) +{ + UINT16 HttpPort; + struct sockaddr_in WebServerAddress; + int SocketStatus; + EFI_STATUS Status; + + DEBUG (( DEBUG_SERVER_TIMER, "Entering WebServerTimer\r\n" )); + + // + // Open the HTTP port on the server + // + do { + do { + // + // Complete the client operations + // + SocketPoll ( pWebServer ); + + // + // Wait for a while + // + Status = gBS->CheckEvent ( pWebServer->TimerEvent ); + } while ( EFI_SUCCESS != Status ); + + // + // Attempt to create the socket for the web server + // + pWebServer->HttpListenPort = socket ( AF_INET, + SOCK_STREAM, + IPPROTO_TCP ); + if ( -1 != pWebServer->HttpListenPort ) + { + // + // Set the socket address + // + ZeroMem ( &WebServerAddress, sizeof ( WebServerAddress )); + HttpPort = PcdGet16 ( WebServer_HttpPort ); + DEBUG (( DEBUG_HTTP_PORT, + "HTTP Port: %d\r\n", + HttpPort )); + WebServerAddress.sin_len = sizeof ( WebServerAddress ); + WebServerAddress.sin_family = AF_INET; + WebServerAddress.sin_addr.s_addr = INADDR_ANY; + WebServerAddress.sin_port = htons ( HttpPort ); + + // + // Bind the socket to the HTTP port + // + SocketStatus = bind ( pWebServer->HttpListenPort, + (struct sockaddr *) &WebServerAddress, + WebServerAddress.sin_len ); + if ( -1 != SocketStatus ) { + // + // Enable connections to the HTTP port + // + SocketStatus = listen ( pWebServer->HttpListenPort, + SOMAXCONN ); + } + + // + // Release the socket if necessary + // + if ( -1 == SocketStatus ) { + close ( pWebServer->HttpListenPort ); + pWebServer->HttpListenPort = -1; + } + } + + // + // Wait until the socket is open + // + }while ( -1 == pWebServer->HttpListenPort ); + + DEBUG (( DEBUG_SERVER_TIMER, "Exiting WebServerTimer\r\n" )); +} + + +/** + Start the web server port creation timer + + @param [in] pWebServer The web server control structure address. + + @retval EFI_SUCCESS The timer was successfully started. + @retval EFI_ALREADY_STARTED The timer is already running. + @retval Other The timer failed to start. + +**/ +EFI_STATUS +WebServerTimerStart ( + IN DT_WEB_SERVER * pWebServer + ) +{ + EFI_STATUS Status; + UINT64 TriggerTime; + + DBG_ENTER ( ); + + // + // Assume the timer is already running + // + Status = EFI_ALREADY_STARTED; + if ( !pWebServer->bTimerRunning ) { + // + // Compute the poll interval + // + TriggerTime = HTTP_PORT_POLL_DELAY * ( 1000 * 10 ); + Status = gBS->SetTimer ( pWebServer->TimerEvent, + TimerPeriodic, + TriggerTime ); + if ( !EFI_ERROR ( Status )) { + DEBUG (( DEBUG_HTTP_PORT, "HTTP port timer started\r\n" )); + + // + // Mark the timer running + // + pWebServer->bTimerRunning = TRUE; + } + else { + DEBUG (( DEBUG_ERROR | DEBUG_HTTP_PORT, + "ERROR - Failed to start HTTP port timer, Status: %r\r\n", + Status )); + } + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + + +/** + Stop the web server port creation timer + + @param [in] pWebServer The web server control structure address. + + @retval EFI_SUCCESS The HTTP port timer is stopped + @retval Other Failed to stop the HTTP port timer + +**/ +EFI_STATUS +WebServerTimerStop ( + IN DT_WEB_SERVER * pWebServer + ) +{ + EFI_STATUS Status; + + DBG_ENTER ( ); + + // + // Assume the timer is stopped + // + Status = EFI_SUCCESS; + if ( pWebServer->bTimerRunning ) { + // + // Stop the port creation polling + // + Status = gBS->SetTimer ( pWebServer->TimerEvent, + TimerCancel, + 0 ); + if ( !EFI_ERROR ( Status )) { + DEBUG (( DEBUG_HTTP_PORT, "HTTP port timer stopped\r\n" )); + + // + // Mark the timer stopped + // + pWebServer->bTimerRunning = FALSE; + } + else { + DEBUG (( DEBUG_ERROR | DEBUG_HTTP_PORT, + "ERROR - Failed to stop HTTP port timer, Status: %r\r\n", + Status )); + } + } + + // + // Return the operation status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} + +/** + Entry point for the web server application. + + @param [in] Argc The number of arguments + @param [in] Argv The argument value array + + @retval 0 The application exited normally. + @retval Other An error occurred. +**/ +int +main ( + IN int Argc, + IN char **Argv + ) +{ + DT_WEB_SERVER * pWebServer; + EFI_STATUS Status; + + // + // Create a timer event to start HTTP port + // + pWebServer = &mWebServer; + Status = gBS->CreateEvent ( EVT_TIMER, + TPL_WEB_SERVER, + NULL, + NULL, + &pWebServer->TimerEvent ); + if ( !EFI_ERROR ( Status )) { + Status = WebServerTimerStart ( pWebServer ); + if ( !EFI_ERROR ( Status )) { + // + // Run the web server forever + // + for ( ; ; ) { + // + // Poll the network layer to create the HTTP port + // for the web server. More than one attempt may + // be necessary since it may take some time to get + // the IP address and initialize the upper layers + // of the network stack. + // + WebServerTimer ( pWebServer ); + + // + // Add the HTTP port to the list of ports + // + Status = PortAdd ( pWebServer, pWebServer->HttpListenPort ); + if ( !EFI_ERROR ( Status )) { + // + // Poll the sockets for activity + // + do { + SocketPoll ( pWebServer ); + } while ( -1 != pWebServer->HttpListenPort ); + + // + // The HTTP port failed the accept and was closed + // + } + + // + // Close the HTTP port if necessary + // + if ( -1 != pWebServer->HttpListenPort ) { + close ( pWebServer->HttpListenPort ); + pWebServer->HttpListenPort = -1; + } +// +// TODO: Remove the following test code +// Exit when the network connection is broken +// +break; + } + + // + // Done with the timer event + // + WebServerTimerStop ( pWebServer ); + Status = gBS->CloseEvent ( pWebServer->TimerEvent ); + } + } + + // + // Return the final status + // + DBG_EXIT_STATUS ( Status ); + return Status; +} diff --git a/AppPkg/Applications/Sockets/WebServer/WebServer.h b/AppPkg/Applications/Sockets/WebServer/WebServer.h new file mode 100644 index 0000000000..6078df0362 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/WebServer.h @@ -0,0 +1,1105 @@ +/** @file
+ Definitions for the web server.
+
+ Copyright (c) 2011, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _WEB_SERVER_H_
+#define _WEB_SERVER_H_
+
+#include <errno.h>
+#include <Uefi.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/BlockIo.h>
+
+#include <netinet/in.h>
+
+#include <sys/EfiSysCall.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+
+#pragma warning ( disable : 4054 )
+#pragma warning ( disable : 4152 )
+
+//------------------------------------------------------------------------------
+// Pages
+//------------------------------------------------------------------------------
+
+#define PAGE_ACPI_DSDT L"/DSDT"
+#define PAGE_ACPI_FADT L"/FADT"
+#define PAGE_ACPI_RSDP_10B L"/RSDP1.0b"
+#define PAGE_ACPI_RSDP_30 L"/RSDP3.0"
+#define PAGE_ACPI_RSDT L"/RSDT"
+#define PAGE_BOOT_SERVICES_TABLE L"/BootServicesTable"
+#define PAGE_CONFIGURATION_TABLE L"/ConfigurationTable"
+#define PAGE_DXE_SERVICES_TABLE L"/DxeServicesTable"
+#define PAGE_RUNTIME_SERVICES_TABLE L"/RuntimeServicesTable"
+
+//------------------------------------------------------------------------------
+// Signatures
+//------------------------------------------------------------------------------
+
+#define DSDT_SIGNATURE 0x54445344
+#define FADT_SIGNATURE 0x50434146
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#if defined(_MSC_VER) /* Handle Microsoft VC++ compiler specifics. */
+#define DBG_ENTER() DEBUG (( DEBUG_INFO, "Entering " __FUNCTION__ "\n" )) ///< Display routine entry
+#define DBG_EXIT() DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ "\n" )) ///< Display routine exit
+#define DBG_EXIT_DEC(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %d\n", Status )) ///< Display routine exit with decimal value
+#define DBG_EXIT_HEX(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: 0x%08x\n", Status )) ///< Display routine exit with hex value
+#define DBG_EXIT_STATUS(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", Status: %r\n", Status )) ///< Display routine exit with status value
+#define DBG_EXIT_TF(Status) DEBUG (( DEBUG_INFO, "Exiting " __FUNCTION__ ", returning %s\n", (FALSE == Status) ? L"FALSE" : L"TRUE" )) ///< Display routine with TRUE/FALSE value
+#else // _MSC_VER
+#define DBG_ENTER()
+#define DBG_EXIT()
+#define DBG_EXIT_DEC(Status)
+#define DBG_EXIT_HEX(Status)
+#define DBG_EXIT_STATUS(Status)
+#define DBG_EXIT_TF(Status)
+#endif // _MSC_VER
+
+#define DIM(x) ( sizeof ( x ) / sizeof ( x[0] )) ///< Compute the number of entries in an array
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+#define DEBUG_SOCKET_POLL 0x00080000 ///< Display the socket poll messages
+#define DEBUG_PORT_WORK 0x00040000 ///< Display the port work messages
+#define DEBUG_SERVER_TIMER 0x00020000 ///< Display the socket poll messages
+#define DEBUG_HTTP_PORT 0x00010000 ///< Display HTTP port related messages
+#define DEBUG_REQUEST 0x00008000 ///< Display the HTTP request messages
+
+#define HTTP_PORT_POLL_DELAY ( 2 * 1000 ) ///< Delay in milliseconds for attempts to open the HTTP port
+#define CLIENT_POLL_DELAY 50 ///< Delay in milliseconds between client polls
+
+#define TPL_WEB_SERVER TPL_CALLBACK ///< TPL for routine synchronization
+
+/**
+ Verify new TPL value
+
+ This macro which is enabled when debug is enabled verifies that
+ the new TPL value is >= the current TPL value.
+**/
+#ifdef VERIFY_TPL
+#undef VERIFY_TPL
+#endif // VERIFY_TPL
+
+#if !defined(MDEPKG_NDEBUG)
+
+#define VERIFY_TPL(tpl) \
+{ \
+ EFI_TPL PreviousTpl; \
+ \
+ PreviousTpl = gBS->RaiseTPL ( TPL_HIGH_LEVEL ); \
+ gBS->RestoreTPL ( PreviousTpl ); \
+ if ( PreviousTpl > tpl ) { \
+ DEBUG (( DEBUG_ERROR, "Current TPL: %d, New TPL: %d\r\n", PreviousTpl, tpl )); \
+ ASSERT ( PreviousTpl <= tpl ); \
+ } \
+}
+
+#else // MDEPKG_NDEBUG
+
+#define VERIFY_TPL(tpl)
+
+#endif // MDEPKG_NDEBUG
+
+#define WEB_SERVER_SIGNATURE SIGNATURE_32('W','e','b','S') ///< DT_WEB_SERVER memory signature
+
+#define SPACES_ADDRESS_TO_DATA 2
+#define BYTES_ON_A_LINE 16
+#define SPACES_BETWEEN_BYTES 1
+#define SPACES_DATA_TO_ASCII 2
+
+
+//------------------------------------------------------------------------------
+// Protocol Declarations
+//------------------------------------------------------------------------------
+
+extern EFI_COMPONENT_NAME_PROTOCOL gComponentName; ///< Component name protocol declaration
+extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2; ///< Component name 2 protocol declaration
+extern EFI_DRIVER_BINDING_PROTOCOL gDriverBinding; ///< Driver binding protocol declaration
+
+//------------------------------------------------------------------------------
+// Data Types
+//------------------------------------------------------------------------------
+
+/**
+ Port control structure
+**/
+typedef struct {
+ //
+ // Buffer management
+ //
+ size_t RequestLength; ///< Request length in bytes
+ size_t TxBytes; ///< Bytes in the TX buffer
+ UINT8 Request [ 65536 ]; ///< Page request
+ UINT8 RxBuffer [ 65536 ]; ///< Receive buffer
+ UINT8 TxBuffer [ 65536 ]; ///< Transmit buffer
+} WSDT_PORT;
+
+/**
+ Web server control structure
+**/
+typedef struct {
+ UINTN Signature; ///< Structure identification
+
+ //
+ // Image attributes
+ //
+ EFI_HANDLE ImageHandle; ///< Image handle
+
+ //
+ // HTTP port management
+ //
+ BOOLEAN bTimerRunning; ///< Port creation timer status
+ EFI_EVENT TimerEvent; ///< Timer to open HTTP port
+ int HttpListenPort; ///< File descriptor for the HTTP listen port
+
+ //
+ // Client port management
+ //
+ nfds_t MaxEntries; ///< Maximum entries in the PortList array
+ nfds_t Entries; ///< The current number of entries in the PortList array
+ struct pollfd * pFdList; ///< List of socket file descriptors
+ WSDT_PORT ** ppPortList; ///< List of port management structures
+} DT_WEB_SERVER;
+
+//#define SERVER_FROM_SERVICE(a) CR(a, DT_WEB_SERVER, ServiceBinding, WEB_SERVER_SIGNATURE) ///< Locate DT_LAYER from service binding
+
+extern DT_WEB_SERVER mWebServer;
+
+/**
+ Process an HTTP request
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+typedef
+EFI_STATUS
+(* PFN_RESPONSE) (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN BOOLEAN * pbDone
+ );
+
+/**
+ Data structure to delcare page support routines
+**/
+typedef struct {
+ UINT16 * pPageName; ///< Name of the page
+ PFN_RESPONSE pfnResponse; ///< Routine to generate the response
+ UINT16 * pDescription; ///< Description of the page
+} DT_PAGE;
+
+extern CONST DT_PAGE mPageList []; ///< List of pages
+extern CONST UINTN mPageCount; ///< Number of pages
+
+//------------------------------------------------------------------------------
+// Web Pages
+//------------------------------------------------------------------------------
+
+/**
+ Respond with the ACPI DSDT table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+AcpiDsdtPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the ACPI FADT table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+AcpiFadtPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the ACPI RSDP 1.0b table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+AcpiRsdp10Page (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the ACPI RSDP 3.0 table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+AcpiRsdp30Page (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the ACPI RSDT table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+AcpiRsdtPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the boot services table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+BootServicesTablePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the configuration tables
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+ConfigurationTablePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the DHCP options
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+DhcpOptionsPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the DXE services table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+DxeServicesTablePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the firmware status
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+FirmwarePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the handles in the system
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HandlePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the Hello World page
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HelloPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the list of known pages
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+IndexPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Page to reboot the system
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RebootPage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the runtime services table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RuntimeSservicesTablePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+/**
+ Respond with the system table
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+SystemTablePage (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN * pbDone
+ );
+
+//------------------------------------------------------------------------------
+// Support routines
+//------------------------------------------------------------------------------
+
+/**
+ Display the EFI Table Header
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pHeader Address of the EFI_TABLE_HEADER structure
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+EfiTableHeader (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN EFI_TABLE_HEADER * pHeader
+ );
+
+/**
+ Buffer the HTTP page header
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pTitle A zero terminated Unicode title string
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpPageHeader (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR16 * pTitle
+ );
+
+/**
+ Buffer and send the HTTP page trailer
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpPageTrailer (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN BOOLEAN * pbDone
+ );
+
+/**
+ Process an HTTP request
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpRequest (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN BOOLEAN * pbDone
+ );
+
+/**
+ Buffer data for sending
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] LengthInBytes Length of valid data in the buffer
+ @param [in] pBuffer Buffer of data to send
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSend (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN size_t LengthInBytes,
+ IN CONST UINT8 * pBuffer
+ );
+
+/**
+ Send an ANSI string
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pString A zero terminated Unicode string
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendAnsiString (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST char * pString
+ );
+
+/**
+ Buffer a single byte
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] Data The data byte to send
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendByte (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN UINT8 Data
+ );
+
+/**
+ Display a character
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] Character Character to display
+ @param [in] pReplacement Replacement character string
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendCharacter (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CHAR8 Character,
+ IN CHAR8 * pReplacement
+ );
+
+/**
+ Send a buffer dump
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] ByteCount The number of bytes to display
+ @param [in] pData Address of the byte array
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendDump (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN UINTN ByteCount,
+ IN CONST UINT8 * pData
+ );
+
+/**
+ Display a row containing a GUID value
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pGuid Address of the GUID to display
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendGuid (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST EFI_GUID * pGuid
+ );
+
+/**
+ Output a hex value to the HTML page
+
+ @param [in] SocketFD Socket file descriptor
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] Bits Number of bits to display
+ @param [in] Value Value to display
+
+ @retval EFI_SUCCESS Successfully displayed the address
+**/
+EFI_STATUS
+HttpSendHexBits (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN INT32 Bits,
+ IN UINT64 Value
+ );
+
+/**
+ Output a hex value to the HTML page
+
+ @param [in] SocketFD Socket file descriptor
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] Value Value to display
+
+ @retval EFI_SUCCESS Successfully displayed the address
+**/
+EFI_STATUS
+HttpSendHexValue (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN UINT64 Value
+ );
+
+/**
+ Output an IP address to the HTML page
+
+ @param [in] SocketFD Socket file descriptor
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pAddress Address of the socket address
+
+ @retval EFI_SUCCESS Successfully displayed the address
+**/
+EFI_STATUS
+HttpSendIpAddress (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN struct sockaddr_in * pAddress
+ );
+
+/**
+ Send a Unicode string
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pString A zero terminated Unicode string
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+HttpSendUnicodeString (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST UINT16 * pString
+ );
+
+/**
+ Output a value to the HTML page
+
+ @param [in] SocketFD Socket file descriptor
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] Value Value to display
+
+ @retval EFI_SUCCESS Successfully displayed the address
+**/
+EFI_STATUS
+HttpSendValue (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN UINT64 Value
+ );
+
+/**
+ Display a row containing a decimal value
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] Value The value to display
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowDecimalValue (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN UINT64 Value
+ );
+
+/**
+ Display a row containing a GUID value
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] pGuid Address of the GUID to display
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowGuid (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN CONST EFI_GUID * pGuid
+ );
+
+/**
+ Display a row containing a hex value
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] Value The value to display
+ @param [in] pWebPage Address of a zero terminated web page name
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowHexValue (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN UINT64 Value,
+ IN CONST CHAR16 * pWebPage
+ );
+
+/**
+ Display a row containing a pointer
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] pAddress The address to display
+ @param [in] pWebPage Address of a zero terminated web page name
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowPointer (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN CONST VOID * pAddress,
+ IN CONST CHAR16 * pWebPage
+ );
+
+/**
+ Display a row containing a revision
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] Revision The revision to display
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowRevision (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN UINT32 Revision
+ );
+
+/**
+ Display a row containing a unicode string
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] pString Address of a zero terminated unicode string
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+RowUnicodeString (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR8 * pName,
+ IN CONST CHAR16 * pString
+ );
+
+/**
+ Start the table page
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [in] pName Address of a zero terminated name string
+ @param [in] pTable Address of the table
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+TableHeader (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ IN CONST CHAR16 * pName,
+ IN CONST VOID * pTable
+ );
+
+/**
+ End the table page
+
+ @param [in] SocketFD The socket's file descriptor to add to the list.
+ @param [in] pPort The WSDT_PORT structure address
+ @param [out] pbDone Address to receive the request completion status
+
+ @retval EFI_SUCCESS The request was successfully processed
+
+**/
+EFI_STATUS
+TableTrailer (
+ IN int SocketFD,
+ IN WSDT_PORT * pPort,
+ OUT BOOLEAN *pbDone
+ );
+
+/**
+ HTTP port creation timer routine
+
+ This routine polls the socket layer waiting for the initial network connection
+ which will enable the creation of the HTTP port. The socket layer will manage
+ the coming and going of the network connections after that until the last network
+ connection is broken.
+
+ @param [in] pWebServer The web server control structure address.
+
+**/
+VOID
+WebServerTimer (
+ IN DT_WEB_SERVER * pWebServer
+ );
+
+/**
+ Start the web server port creation timer
+
+ @param [in] pWebServer The web server control structure address.
+
+ @retval EFI_SUCCESS The timer was successfully started.
+ @retval EFI_ALREADY_STARTED The timer is already running.
+ @retval Other The timer failed to start.
+
+**/
+EFI_STATUS
+WebServerTimerStart (
+ IN DT_WEB_SERVER * pWebServer
+ );
+
+/**
+ Stop the web server port creation timer
+
+ @param [in] pWebServer The web server control structure address.
+
+ @retval EFI_SUCCESS The HTTP port timer is stopped
+ @retval Other Failed to stop the HTTP port timer
+
+**/
+EFI_STATUS
+WebServerTimerStop (
+ IN DT_WEB_SERVER * pWebServer
+ );
+
+//------------------------------------------------------------------------------
+// Driver Binding Protocol Support
+//------------------------------------------------------------------------------
+
+/**
+ Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
+ closing the DevicePath and PciIo protocols on Controller.
+
+ @param [in] pThis Protocol instance pointer.
+ @param [in] Controller Handle of device to stop driver on.
+ @param [in] NumberOfChildren How many children need to be stopped.
+ @param [in] pChildHandleBuffer Not used.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * pThis,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * pChildHandleBuffer
+ );
+
+//------------------------------------------------------------------------------
+// EFI Component Name Protocol Support
+//------------------------------------------------------------------------------
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param [in] pLanguage A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 3066 or ISO 639-2 language code format.
+ @param [out] ppDriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL * pThis,
+ IN CHAR8 * pLanguage,
+ OUT CHAR16 ** ppDriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param [in] pThis A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param [in] ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param [in] ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param [in] pLanguage A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 3066 or ISO 639-2 language code format.
+ @param [out] ppControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+GetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL * pThis,
+ IN EFI_HANDLE ControllerHandle,
+ IN OPTIONAL EFI_HANDLE ChildHandle,
+ IN CHAR8 * pLanguage,
+ OUT CHAR16 ** ppControllerName
+ );
+
+//------------------------------------------------------------------------------
+
+#endif // _WEB_SERVER_H_
diff --git a/AppPkg/Applications/Sockets/WebServer/WebServer.inf b/AppPkg/Applications/Sockets/WebServer/WebServer.inf new file mode 100644 index 0000000000..308e4bfff2 --- /dev/null +++ b/AppPkg/Applications/Sockets/WebServer/WebServer.inf @@ -0,0 +1,97 @@ +#/** @file
+# Web Server Application
+#
+# This file contains an 'Intel Peripheral Driver' and is
+# licensed for Intel CPUs and chipsets under the terms of your
+# license agreement with Intel or your vendor. This file may
+# be modified by the user, subject to additional terms of the
+# license agreement
+#
+#
+# Copyright (c) 20011 Intel Corporation. All rights reserved
+# This software and associated documentation (if any) is furnished
+# under a license and may only be used or copied in accordance
+# with the terms of the license. Except as permitted by such
+# license, no part of this software or documentation may be
+# reproduced, stored in a retrieval system, or transmitted in any
+# form or by any means without the express written consent of
+# Intel Corporation.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = WebServer
+ FILE_GUID = 99E87DCF-6162-40c5-9FA1-32111F5197F7
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ ACPI.c
+ BootServicesTable.c
+ ConfigurationTable.c
+ DhcpOptions.c
+ DxeServicesTable.c
+ Firmware.c
+ Handles.c
+ Hello.c
+ HTTP.c
+ Index.c
+ PageList.c
+ Reboot.c
+ RuntimeServicesTable.c
+ SystemTable.c
+ WebServer.c
+
+
+[Pcd]
+ gStdLibTokenSpaceGuid.WebServer_HttpPort
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ShellPkg/ShellPkg.dec
+ StdLib/StdLib.dec
+
+
+[LibraryClasses]
+ BaseMemoryLib
+ BsdSocketLib
+ DebugLib
+ DevShell
+# EfiSocketLib
+ LibC
+ ShellLib
+ ShellCEntryLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiRuntimeServicesTableLib
+ UseSocketDxe
+
+[Guids]
+ gEfiAcpi10TableGuid
+ gEfiAcpiTableGuid
+ gEfiDebugImageInfoTableGuid
+ gEfiDxeServicesTableGuid
+ gEfiHobListGuid
+ gEfiMemoryTypeInformationGuid
+ gLoadFixedAddressConfigurationTableGuid
+
+[Protocols]
+ gEfiDhcp4ServiceBindingProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDhcp4ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[BuildOptions]
+ INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
+ MSFT:*_*_*_CC_FLAGS = /Od
+ GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable
+
|