UEFI (10) Network

Source: Internet
Author: User

Before you start programming, you must configure the development environment. In two cases, Nt32 is used to simulate the environment, and UEFI is used to simulate the environment.
For more information about Nt32 Network settings, see UEFI Network Stack for EDK Getting Started Guide:
1. Download and install Winpcap
2. Download SnpNt32Io and compile
C: \> cd c: \ SnpNt32Io
C: \ SnpNt32Io> nmake TARGET = RELEASE
C: \ SnpNt32Io> copy/y SnpNt32Io. dll c: \ edk2 \ build \ Nt32Pkg \ vs2008 \ IA32 \
3. Start the Nt32 Simulator
4. Load network protocol
Shell> fsnt0:
Fsnt0: \> load SnpNt32.efi Mnp. efi Arp. efi Ip4.efi Ip4Config. efi Udp4.efi Dhcp4.efi Mtftp4.efi Tcp4.efi

5. Configure the NIC

Fsnt0: \> ifconfig-s eth0 Dhcp
Fsnt0: \> ifconfig-s eth0 static 192.168.0.125 255.255.255.0 192.168.0.1


To use a real UEFI environment, first load the NIC driver, then load the network protocol Snp. efi Mnp. efi Arp. efi Ip4.efi Ip4Config. efi Udp4.efi Dhcp4.efi Mtftp4.efi Tcp4.efi, and configure the NIC.
Network Protocol Stack


Snp (EFI_SIMPLE_NETWORK_PROTOCOL) is used to initialize and disable network interfaces, send and receive packets,
Mnp (EFI_MANAGED_NETWORK_PROTOCOL) provides Asynchronous Network Packet I/O operations
Arp (EFI_ARP_PROTOCOL) is used to convert an IP address to a physical address www.2cto.com
We are familiar with IP, TCP, and UDP protocols.
Next we will introduce the usage of TCP Protocol (EFI_TCP4_PROTOCOL. If you have used a Socket to write a program, you can easily understand the usage of EFI_TCP4_PROTOCOL. We know that the Socket Client requires the following steps:
1. Create Socket
2. Connect
3. Send/Recv
4. Close

Similar to EFI_TCP4_PROTOCOL, the client needs to take the following steps:
1. Create EFI_TCP4_PROTOCOL object
2. Configure
3. Connect
4. Transmit (send)/Receive (Recv)
5. Close
In fact, we can take Configure and Connect into one step.
We can encapsulate EFI_TCP4_PROTOCOL into a Socket class.
# Define SocketWait (e )\{
UINTN index ;\
Status = gBS-> WaitForEvent (1, & (e), & index );\
}
Typedef EFI_STAUTS SOCKET_STATUS;
Class Socket
{
Public:
Socket (EFI_HANDLE ImageHandle );
~ Socket ();
SOCKET_STATUS Config (UINT32 Ip32, UINT16 Port );
SOCKET_STATUS Connect ();

SOCKET_STATUS Connect (UINT32 Ip32, UINT16 Port) {Config (Ip32, Port); reuturn Connect ();};
SOCKET_STATUS Close ();
SOCKET_STATUS Send (CHAR8 * Data, UINTN Lenth );
SOCKET_STATUS Recv (CHAR8 * Buffer, UINTN Lenth );
BOOL Ready () {return (m_pServiceBinding! = NULL );}
Private:
SOCKET Initialize ();

EFI_HANDLE m_SocketHandle;
EFI_TCP4_PROTOCOL * m_pTcp4Protocol;

EFI_SERVICE_BINDING_PROTOCOL * m_pServiceBinding;


EFI_TCP4_CONFIG_DATA * m_pTcp4ConfigData;

EFI_TCP4_TRANSMIT_DATA * m_TransData;
EFI_TCP4_RECEIVE_DATA * m_RecvData;


EFI_TCP4_CONNECTION_TOKEN ConnectToken;
EFI_TCP4_CLOSE_TOKEN CloseToken;
EFI_TCP4_IO_TOKEN SendToken, RecvToken;
}; Next step by step
1. generate an EFI_TCP4_PROTOCOL object.

EFI_TCP4_SERVICE_BINDING_PROTOCOL.CreateChild. The Code is as follows:

Socket: Socket (EFI_HANDLE ImageHandle)
{
EFI_STATUS Status;
Memset (void *) this, 0, sizeof (Socket ));
M_SocketHandle = NULL;
Status = gBS-> LocateProtocol (& gEfiTcp4ServiceBindingProtocolGuid,
NULL,
(VOID **) & m_pServiceBinding );

If (EFI_ERROR (Status ))
Return Status;

Status = m_pServiceBinding-> CreateChild (m_pServiceBinding,
& M_SocketHandle );

If (EFI_ERROR (Status ))
Return Status;

Status = gBS-> OpenProtocol (m_SocketHandle,
& GEfiTcp4ProtocolGuid,
(VOID **) & m_pTcp4Protocol,
ImageHandle,
M_SocketHandle,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );
If (EFI_ERROR (Status ))
Return Status;
This-> Init ();
}
2. Step 2: Configure the server IP address and port, and the local IP address and port. Note that After configuring, the connection has not been established.
SOCKET_STATUS Socket: Config (UINT32 Ip32, UINT16 Port)
{
EFI_STATUS Status = EFI_NOT_FOUND;
If (m_pTcp4ConfigData = NULL) return Status;
M_pTcp4ConfigData-> TypeOfService = 0;
M_pTcp4ConfigData-> TimeToLive = 0;
* (UINT *) (m_pTcp4ConfigData-> AccessPoint. RemoteAddress. Addr) = Ip32;
M_pTcp4ConfigData-> AccessPoint. RemotePort = Port;
* (UINT32 *) (m_pTcp4ConfigData-> AccessPoint. SubnetMask. Addr) = (255 | 255 <8 | 255 <16 | 0 <24 );

M_pTcp4ConfigData-> AccessPoint. UseDefaultAddress = TRUE;
/// If UseDefaultAddress is FALSE, set StationAddress
// * (UINT32 *) (m_pTcp4ConfigData-> AccessPoint. StationAddress. Addr) = LocalIp;
M_pTcp4ConfigData-> AccessPoint. StationPort = 61558;
M_pTcp4ConfigData-> AccessPoint. ActiveFlag = TRUE;
M_pTcp4ConfigData-> ControlOption = NULL;
Status = m_pTcp4Protocol-> Configure (m_pTcp4Protocol, m_pTcp4ConfigData );
Return Status;
}

EFI_TCP4_CONFIG_DATA * m_pTcp4ConfigData is defined as follows
//
**************************************** ***********************
// EFI_TCP4_CONFIG_DATA
//
**************************************** ***********************
Typedef struct {
// Processing ing Filters
// I/O parameters
UINT8 TypeOfService;
UINT8 TimeToLive;
// Access Point
EFI_TCP4_ACCESS_POINT AccessPoint;
// TCP Control Options
EFI_TCP4_OPTION * ControlOption;
} EFI_TCP4_CONFIG_DATA; typedef struct {
BOOLEAN UseDefaultAddress; // True indicates that the local default IP address is used. If the value is False, StationAddress must be specified.
// Local IP address and port
EFI_IPv4_ADDRESS StationAddress;
Efi_00004_address SubnetMask;
UINT16 StationPort;
// Server IP address and port
Efi_00004_address RemoteAddress;
UINT16 RemotePort;
BOOLEAN ActiveFlag; // TRUE: Active Open; False: Passive Open (Server side)
} EFI_TCP4_ACCESS_POINT
Step 3: establish a connection

EFI_STAUS Socket: Connect ()
{
EFI_STATUS Status = EFI_NOT_FOUND;
If (m_pTcp4Protocol = NULL) return Status;
Status = m_pTcp4Protocol-> Connect (m_pTcp4Protocol, & ConnectToken );
If (EFI_ERROR (Status ))
Return Status;
SocketWait (ConnectToken. CompletionToken. Event );
Return Status;
} View function prototype
Typedef
EFI_STATUS
(EFIAPI * EFI_TCP4_CONNECT )(
IN EFI_TCP4_PROTOCOL * This,
IN EFI_TCP4_CONNECTION_TOKEN * ConnectionToken,
); Typedef struct {
EFI_EVENT Event;
EFI_STATUS Status;
} EFI_TCP4_COMPLETION_TOKEN;
Typedef struct {
EFI_TCP4_COMPLETION_TOKEN CompletionToken;
} EFI_TCP4_CONNECTION_TOKEN;

Connect is a non-blocking function, which is returned immediately after being called. After the connection is completed (successful or failed), the system sets the events and status in ConnectionToken. Therefore, we need to query or wait for the event at the appropriate time. The following functions also adopt a similar mechanism.
3. Now we can send or receive data.
Let's take a look at sending data first.
Typedef
EFI_STATUS
(EFIAPI * EFI_TCP4_TRANSMIT )(
IN EFI_TCP4_PROTOCOL * This,
IN EFI_TCP4_IO_TOKEN * Token
);
EFI_TCP4_IO_TOKEN is much more complex than EFI_TCP4_CONNECTION_TOKEN. To send data, you must pass the EFI_TCP4_IO_TOKEN to EFI_TCP4_PROTOCOL.
//************************************** *************************
// EFI_TCP4_IO_TOKEN
//************************************** *************************
Typedef struct {
EFI_TCP4_COMPLETION_TOKEN CompletionToken;
Union {
EFI_TCP4_RECEIVE_DATA * RxData;
EFI_TCP4_TRANSMIT_DATA * TxData;
} Packet;
} EFI_TCP4_IO_TOKEN; //************************************** ************************
// EFI_TCP4_TRANSMIT_DATA
//************************************** ************************
Typedef struct {
BOOLEAN Push;
BOOLEAN Urgent;
UINT32 DataLength;
UINT32 FragmentCount;
EFI_TCP4_FRAGMENT_DATA FragmentTable [1];
} EFI_TCP4_TRANSMIT_DATA; //************************************** *************************
// EFI_TCP4_FRAGMENT_DATA
//************************************** *************************
Typedef struct {
UINT32 FragmentLength;
VOID * FragmentBuffer;
} EFI_TCP4_FRAGMENT_DATA;
The data to be sent may be in several discontinuous buffers. We can place these buffer pointers in the FragmentTable array. Each element in the array represents a buffer zone. DataLength is the total length of data (the sum of the buffer lengths), and FragmentCount is the number of buffers.
The following code uses only one buffer zone. Like Connect, after Transmit is called, WaitForEvent is used to wait for the sending to complete.

SOCKET_STAUS Socket: Send (CHAR8 * Data, UINTN Lenth)
{
EFI_STATUS Status = EFI_NOT_FOUND;
If (m_pTcp4Protocol = NULL) return Status;
M_TransData-> Push = TRUE;
M_TransData-> Urgent = TRUE;
M_TransData-> DataLength = (UINT32) Lenth;
M_TransData-> FragmentCount = 1;
M_TransData-> FragmentTable [0]. FragmentLength = m_TransData-> DataLength;
M_TransData-> FragmentTable [0]. FragmentBuffer = Data;
SendToken. Packet. TxData = m_TransData;
Status = m_pTcp4Protocol-> Transmit (m_pTcp4Protocol, & SendToken );
If (EFI_ERROR (Status ))
Return Status;
SocketWait (SendToken. CompletionToken. Event );
Return SendToken. CompletionToken. Status;
}
Receive data

Similar to sending and receiving
Typedef
EFI_STATUS
(EFIAPI * EFI_TCP4_RECEIVE )(
IN EFI_TCP4_PROTOCOL * This,
IN EFI_TCP4_IO_TOKEN * Token
);
//************************************** *************************
// EFI_TCP4_RECEIVE_DATA
//************************************** *************************
Typedef struct {
BOOLEAN UrgentFlag;
UINT32 DataLength;
UINT32 FragmentCount;
EFI_TCP4_FRAGMENT_DATA FragmentTable [1];
} EFI_TCP4_RECEIVE_DATA; the user is responsible for allocating and releasing the buffer. DataLength is the total length of the buffer. When the receiving is complete, the events in the Token are set, and DataLength is also set to the length of the received data.

SOCKET Socket: Recv (CHAR8 * Buffer, UINTN Lenth)
{
EFI_STATUS Status = EFI_NOT_FOUND;
If (m_pTcp4Protocol = NULL) return Status;

M_RecvData-> UrgentFlag = TRUE;
M_RecvData-> DataLength = (UINT32) Lenth;
M_RecvData-> FragmentCount = 1;
M_RecvData-> FragmentTable [0]. FragmentLength = m_RecvData-> DataLength;
M_RecvData-> FragmentTable [0]. FragmentBuffer = (void *) Buffer;
RecvToken. Packet. RxData = m_RecvData;
Status = m_pTcp4Protocol-> Receive (m_pTcp4Protocol, & RecvToken );
If (EFI_ERROR (Status ))
Return Status;
SocketWait (RecvToken. CompletionToken. Event );
Return RecvToken. CompletionToken. Status;
}
Let's look back at how to create the Token, m_RecvData, and other auxiliary data.

SOCKET_STATUS Socket: Initialize ()
{
EFI_STATUS Status;
// Create Configure Data
M_pTcp4ConfigData = new EFI_TCP4_CONFIG_DATA [1];
// Create Connect Data
ConnectToken. CompletionToken. Status = EFI_ABORTED;
Status = gBS-> CreateEvent (evt_policy_signal, TPL_CALLBACK, (EFI_EVENT_NOTIFY) NopNoify, (VOID *) & ConnectToken, & ConnectToken. CompletionToken. Event );
If (EFI_STATUS (Stauts) return Status;
// Create Transmit Data
Status = gBS-> CreateEvent (evt_policy_signal, TPL_CALLBACK, (EFI_EVENT_NOTIFY) NopNoify, (VOID *) & SendToken, & SendToken. CompletionToken. Event );
If (EFI_STATUS (Stauts) return Status;
SendToken. CompletionToken. Status = EFI_ABORTED;
M_TransData = new EFI_TCP4_TRANSMIT_DATA [1];
// Create Recv Data
Status = gBS-> CreateEvent (evt_policy_signal, TPL_CALLBACK, (EFI_EVENT_NOTIFY) NopNoify, (VOID *) & RecvToken, & RecvToken. CompletionToken. Event );
RecvToken. CompletionToken. Status = EFI_ABORTED;
M_RecvData = new EFI_TCP4_RECEIVE_DATA [1];
If (EFI_STATUS (Stauts) return Status;
// Create Close Data
CloseToken. CompletionToken. Status = EFI_ABORTED;
Status = gBS-> CreateEvent (evt_policy_signal, TPL_CALLBACK, (EFI_EVENT_NOTIFY) NopNoify, (VOID *) & CloseToken, & CloseToken. CompletionToken. Event );
Return Status;
}

// Empty Function

VOID NopNoify (IN EFI_EVENT Event, in void * Context)
{
} 5. Disable EFI_TCP4_PROTOCOL and destroy m_SocketHandle.
_ Inline Socket ::~ Socket ()
{
EFI_STATUS Status;
If (m_SocketHandle)
Status = m_pServiceBinding-> DestroyChild (m_pServiceBinding,
M_SocketHandle );
If (ConnectToken. CompletionToken. Event)
GBS-> CloseEvent (ConnectToken. CompletionToken. Event );
If (SendToken. CompletionToken. Event)
GBS-> CloseEvent (SendToken. CompletionToken. Event );
If (RecvToken. CompletionToken. Event)
GBS-> CloseEvent (RecvToken. CompletionToken. Event );
If (SendToken. Packet. TxData ){
Delete SendToken. Packet. TxData;

SendToken. Packet. TxData = NULL;
}
If (RecvToken. Packet. RxData ){
Delete RecvToken. Packet. RxData;

RecvToken. Packet. RxData = NULL;
}
}
The following is a test of our Socket class:
EFI_STATUS
TestSocket (IN EFI_HANDLE ImageHandle)
{
EFI_STATUS Status = 0;
CHAR8 RequestData [] = "GET/HTTP/1.1 \ nHost: localhost \ nAccept: */* \ nConnection: Keep-Alive \ n ";
CHAR8 * RecvBuffer = new CHAR8 [1024 + 1];
Socket WebSocket (ImageHandle );
If (WebSocket. Ready () = TRUE ){
WebSocket. Connect (192 | 168 <8 | 137 <16 | 1 <24, 80 );
WebSocket. Send (RequestData, AsciiStrLen (RequestData) + 2 );//! Must be + 2
Status = WebSocket. Recv (RecvBuffer, 1024 );
WebSocket. Close ();
}
Delete RecvBuffer;
Return Status;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.