[syslinux] [PATCH 0/1] UEFI UDP/TFTP
Patrick Masotta
masottaus at yahoo.com
Sun Feb 28 08:26:07 PST 2016
Hi guys,
I have re-implemented /efi/udp.c
The new code fixes:
1) The low and decreasing throughput on TFTP transfers.
2) The added delay between consecutive TFTP transfers.
3) The TFTP errors induced by broadcast traffic like ARP.
Initial tests on a 50MB transfer showed times going from 3 minutes
to ~12 seconds, also tested OK with nested TFTP transfers
(include command).
This new code affects/fixes the problems reported at:
a) "Problem with 90MB Initrd"
http://www.syslinux.org/archives/2015-September/024236.html
b) "UEFI: Failed to load ldlinux.e64/ldlinux.e32"
http://www.syslinux.org/archives/2015-October/024341.html
This report has led to Gene's patch:
https://github.com/geneC/syslinux/commit/9e0926bb338deb5c634ccb4ee29eb4577158cfdc
it was reported working but I think "it cannot work" if it has these lines
+ memcpy(&udata.StationAddress, &IPInfo.myip, sizeof(IPInfo.myip));
+ memcpy(&udata.StationAddress, &IPInfo.netmask, sizeof(IPInfo.netmask));
the StationAddress gets overwritten by a netmask...
There's a picture attached comparing performance between the old and new udp.c code.
Testing reports are welcome.
Best,
Patrick
Signed-off-by: Patrick Masotta <masottaus at yahoo.com>
diff -uprN a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
--- a/core/fs/pxe/pxe.h 2014-10-06 10:27:44.000000000 -0600
+++ b/core/fs/pxe/pxe.h 2016-02-28 08:44:47.127996962 -0700
@@ -130,6 +130,7 @@ union net_private {
struct net_private_efi {
struct efi_binding *binding; /* EFI binding for protocol */
uint16_t localport; /* Local port number (0=not in use) */
+ void* context; /* Holds the UDP_IO Instance (used in the new efi UDP codebase) */
} efi;
};
diff -uprN a/efi/udp.c b/efi/udp.c
--- a/efi/udp.c 2014-10-06 10:27:44.000000000 -0600
+++ b/efi/udp.c 2016-02-28 08:41:29.867226806 -0700
@@ -1,5 +1,6 @@
/*
- * Copyright 2013-2014 Intel Corporation - All Rights Reserved
+ * Serva (c) 2010-2016 Patrick Masotta - All Rights Reserved
+ *
*/
#include <string.h>
@@ -8,50 +9,189 @@
#include "net.h"
#include "fs/pxe/pxe.h"
+
+#define TICKS_PER_SECOND 10000000
+#define TICKS_PER_MS 10000
+
+#define UDP_TIME_TO_GETMAP 5 * TICKS_PER_SECOND
+#define UDP_TIME_TX_TIMEOUT 1 * TICKS_PER_SECOND + 500 * TICKS_PER_MS
+#define UDP_TIME_RX_TIMEOUT 1 * TICKS_PER_SECOND + 500 * TICKS_PER_MS
+
+
+///
+/// Type defined as RX.
+/// This data structure wraps receive udp parameters.
+///
+typedef struct {
+ void* buf;
+ uint16_t* buf_len;
+ uint32_t* src_ip;
+ uint16_t* src_port;
+}RX;
+
+///
+/// Type defined as UDP_IO.
+/// This data structure wraps the UDP instance and configuration.
+///
+typedef struct {
+ uint16_t known_TID;
+ struct efi_binding* b;
+ EFI_UDP4* Protocol_Udp4;
+ EFI_UDP4_CONFIG_DATA Config_Udp4;
+ EFI_UDP4_COMPLETION_TOKEN* Token;
+ EFI_EVENT Timeout_Timer;
+ EFI_EVENT CB_OK_Event;
+ RX rx;
+}UDP_IO;
+
+
+#define EFI_IP4_EQUAL(Ip1, Ip2) (CompareMem ((Ip1), (Ip2), sizeof (EFI_IPv4_ADDRESS)) == 0)
+EFI_IPv4_ADDRESS mZeroIp4Addr = {{0, 0, 0, 0}};
+static BOOLEAN volatile UseDefaultSetting = TRUE;
+
extern EFI_GUID Udp4ServiceBindingProtocol, Udp4Protocol;
-/*
- * This UDP binding is configured to operate in promiscuous mode. It is
- * only used for reading packets. It has no associated state unlike
- * socket->net.efi.binding, which has a remote IP address and port
- * number.
- */
-static struct efi_binding *udp_reader;
+
+
+
+/**
+ Poll the UDP to get the IP4 default address, which may be retrieved
+ by DHCP.
+
+ The default time out value is 5 seconds. If IP has retrieved the default address,
+ the UDP is reconfigured.
+
+
+ @param udp_io The UDP_IO instance
+ @param udata The UDP configure data to reconfigure the UDP_IO
+
+ @retval TRUE The default address is retrieved and UDP is reconfigured.
+ @retval FALSE Some error occured.
+
+**/
+BOOLEAN
+efi_udp_get_mapping (UDP_IO* udp_io, EFI_UDP4_CONFIG_DATA* udata)
+{
+ EFI_STATUS status;
+ EFI_UDP4* udp;
+ EFI_IP4_MODE_DATA Ip4Mode;
+
+// ASSERT (UseDefaultSetting);
+
+ udp = udp_io->Protocol_Udp4;
+
+ status = uefi_call_wrapper( BS->SetTimer, 3,
+ udp_io->Timeout_Timer,
+ TimerRelative,
+ UDP_TIME_TO_GETMAP
+ );
+
+ if (EFI_ERROR (status))
+ return FALSE;
+
+ while (EFI_ERROR ( uefi_call_wrapper(BS->CheckEvent, 1, udp_io->Timeout_Timer) ))
+ {
+ udp->Poll(udp);
+
+ if (!EFI_ERROR(udp->GetModeData(udp, NULL, &Ip4Mode, NULL, NULL)) &&
+ Ip4Mode.IsConfigured)
+ {
+ udp->Configure(udp, NULL);
+ return (BOOLEAN) (udp->Configure(udp, udata) == EFI_SUCCESS);
+ }
+ }
+
+ return FALSE;
+}
+
+
/**
- * Try to configure this UDP socket
+ * Try to configure this UDP_IO
*
- * @param:udp, the EFI_UDP4 socket to configure
- * @param:udata, the EFI_UDP4_CONFIG_DATA to use
- * @param:f, the name of the function as a wide string.
+ * @param:udp_io, The UDP_IO containing the EFI_UDP4 socket to configure
+ * and the EFI_UDP4_CONFIG_DATA to use.
+ * @param:f, The name of the invoking function as a wide string.
*
* @out: status as EFI_STATUS
*/
-
-EFI_STATUS core_udp_configure(EFI_UDP4 *udp, EFI_UDP4_CONFIG_DATA *udata,
- short unsigned int *f)
+EFI_STATUS efi_udp_configure(UDP_IO *udp_io, short unsigned int *f)
{
- EFI_STATUS status;
- int unmapped = 1;
- jiffies_t start, last, cur;
-
- last = start = jiffies();
- while (unmapped){
- status = uefi_call_wrapper(udp->Configure, 2, udp, udata);
- if (status != EFI_NO_MAPPING)
- unmapped = 0;
- else {
- cur = jiffies();
- if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) {
- last = cur;
- Print(L"%s: stalling on configure with no mapping\n", f);
- } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) {
- Print(L"%s: aborting on no mapping\n", f);
- unmapped = 0;
- }
- }
- }
- return status;
+
+ EFI_STATUS status;
+ EFI_UDP4* udp = udp_io->Protocol_Udp4;
+ EFI_UDP4_CONFIG_DATA* udata = &udp_io->Config_Udp4;
+
+
+ status = uefi_call_wrapper(udp->Configure, 2, udp, NULL);
+ if (EFI_ERROR (status))
+ {
+ return status;
+ }
+
+
+ status= uefi_call_wrapper(udp->Configure, 2, udp, udata);
+ if( status == EFI_SUCCESS )
+ {
+ EFI_STATUS status;
+
+ status = uefi_call_wrapper(udp->GetModeData, 5, udp,
+ udata, NULL, NULL, NULL);
+
+ if(status == EFI_SUCCESS )
+ return EFI_SUCCESS;
+ else
+ return -1;
+ }
+
+ else
+ if ( status == EFI_NO_MAPPING &&
+ UseDefaultSetting &&
+ efi_udp_get_mapping (udp_io, udata) &&
+ EFI_SUCCESS == uefi_call_wrapper(udp->GetModeData, 5, udp,
+ udata, NULL, NULL, NULL)
+ )
+ return EFI_SUCCESS;
+ else
+ if(
+ UseDefaultSetting &&
+ !EFI_IP4_EQUAL (&mZeroIp4Addr, &IPInfo.gateway) &&
+ !EFI_IP4_EQUAL (&mZeroIp4Addr, &IPInfo.myip) &&
+ !EFI_IP4_EQUAL (&mZeroIp4Addr, &IPInfo.netmask)
+ )
+ { // udp->Configure() and efi_udp_get_mapping() failed lets try a manual config
+ EFI_STATUS status;
+
+ UseDefaultSetting=FALSE;
+ udata->UseDefaultAddress = FALSE;
+ memcpy(&udata->StationAddress , &IPInfo.myip, sizeof(IPInfo.myip));
+ memcpy(&udata->SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask));
+
+ status = uefi_call_wrapper(udp->Routes , 5,
+ udp,
+ FALSE,
+ &mZeroIp4Addr,
+ &mZeroIp4Addr,
+ (EFI_IPv4_ADDRESS *)&IPInfo.gateway
+ );
+ if (EFI_ERROR (status))
+ {
+ uefi_call_wrapper(udp->Configure, 2, udp, NULL);
+ return -1;
+ }
+
+ if( EFI_ERROR (uefi_call_wrapper(udp->Configure, 2, udp, NULL)) ||
+ EFI_ERROR (uefi_call_wrapper(udp->Configure, 2, udp, udata))
+ )
+ return -1;
+ else
+ return EFI_SUCCESS;
+
+ }
+
+ else
+ return -1;
+
}
/**
@@ -63,55 +203,76 @@ EFI_STATUS core_udp_configure(EFI_UDP4 *
*/
int core_udp_open(struct pxe_pvt_inode *socket)
{
- EFI_UDP4_CONFIG_DATA udata;
- struct efi_binding *b;
- EFI_STATUS status;
- EFI_UDP4 *udp;
-
+ EFI_STATUS status;
+ struct efi_binding* b;
+ EFI_UDP4* udp;
+ UDP_IO* udp_io;
+
(void)socket;
- udp_reader = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
- if (!udp_reader)
- return -1;
-
- b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
- if (!b)
- goto bail;
-
- udp = (EFI_UDP4 *)udp_reader->this;
-
- memset(&udata, 0, sizeof(udata));
-
- status = core_udp_configure(udp, &udata, L"core_udp_open");
- if (status != EFI_SUCCESS)
- goto bail;
-
- socket->net.efi.binding = b;
-
- /*
- * Save the random local port number that the UDPv4 Protocol
- * Driver picked for us. The TFTP protocol uses the local port
- * number as the TID.
- */
- status = uefi_call_wrapper(udp->GetModeData, 5, udp,
- &udata, NULL, NULL, NULL);
- if (status != EFI_SUCCESS)
- Print(L"Failed to get UDP mode data: %d\n", status);
- else
- socket->net.efi.localport = udata.StationPort;
+
+ b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
+ if(!b)
+ return -1;
+
+ udp_io=zalloc(sizeof(UDP_IO));
+ if(!udp_io)
+ goto bail;
+
+ udp_io->b = b;
+
+ udp = (EFI_UDP4 *)b->this;
+ udp_io->Protocol_Udp4 = udp;
+
+ socket->net.efi.context = udp_io;
+
+ //
+ // Create the timer used to time out transmit, receive, and get map events
+ //
+ status = uefi_call_wrapper(BS->CreateEvent, 5,
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &udp_io->Timeout_Timer
+ );
+ if (EFI_ERROR (status))
+ goto bail;
+
+ //
+ // Create the event to signal when the send/receive callback function ends
+ // correctly.
+ //
+ status = uefi_call_wrapper(BS->CreateEvent, 5,
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &udp_io->CB_OK_Event
+ );
+ if (EFI_ERROR (status))
+ goto bail;
return 0;
bail:
if (b)
- efi_destroy_binding(b, &Udp4ServiceBindingProtocol);
+ efi_destroy_binding(b, &Udp4ServiceBindingProtocol);
- efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol);
- udp_reader = NULL;
+ if(udp_io && udp_io->Timeout_Timer)
+ uefi_call_wrapper(BS->CloseEvent, 1, udp_io->Timeout_Timer);
+
+ if(udp_io && udp_io->CB_OK_Event)
+ uefi_call_wrapper(BS->CloseEvent, 1, udp_io->CB_OK_Event);
+
+
+ if(udp_io)
+ free(udp_io);
return -1;
}
+
/**
* Close a socket
*
@@ -119,299 +280,394 @@ bail:
*/
void core_udp_close(struct pxe_pvt_inode *socket)
{
- efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol);
- udp_reader = NULL;
- if (!socket->net.efi.binding)
- return;
-
- efi_destroy_binding(socket->net.efi.binding, &Udp4ServiceBindingProtocol);
- socket->net.efi.binding = NULL;
+ UDP_IO* udp_io;
+ udp_io = (UDP_IO*)socket->net.efi.context;
+
+
+ if (!udp_io->b)
+ return;
+
+ efi_destroy_binding(udp_io->b, &Udp4ServiceBindingProtocol);
+ udp_io->b = NULL;
+
+ if(udp_io->Timeout_Timer)
+ uefi_call_wrapper(BS->CloseEvent, 1, udp_io->Timeout_Timer);
+
+ if(udp_io->CB_OK_Event)
+ uefi_call_wrapper(BS->CloseEvent, 1, udp_io->CB_OK_Event);
+
+ if(socket->net.efi.context)
+ free(socket->net.efi.context);
+ socket->net.efi.context=NULL;
+
+
}
/**
* Establish a connection on an open socket
*
- * @param:socket, the open socket
- * @param:ip, the ip address
- * @param:port, the port number, host-byte order
+ * @param:socket, the open socket
+ * @param:ip, the source ip address
+ * @param:port, the source port number, host-byte order
*/
-void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip,
- uint16_t port)
+void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t src_ip,
+ uint16_t src_port)
{
- EFI_UDP4_CONFIG_DATA udata;
- EFI_STATUS status;
- EFI_UDP4 *udp;
-
- udp = (EFI_UDP4 *)socket->net.efi.binding->this;
- memset(&udata, 0, sizeof(udata));
-
- /* Re-use the existing local port number */
- udata.StationPort = socket->net.efi.localport;
-
- udata.UseDefaultAddress = TRUE;
- memcpy(&udata.RemoteAddress, &ip, sizeof(ip));
- udata.RemotePort = port;
- udata.AcceptPromiscuous = TRUE;
- udata.TimeToLive = 64;
-
- status = core_udp_configure(udp, &udata, L"core_udp_connect");
- if (status != EFI_SUCCESS) {
- Print(L"Failed to configure UDP: %d\n", status);
- return;
- }
+ EFI_STATUS status;
+ UDP_IO* udp_io;
+
+ udp_io = (UDP_IO*)socket->net.efi.context;
+
+ if ( src_port != udp_io->Config_Udp4.RemotePort )
+ {
+ udp_io->Config_Udp4.RemotePort = src_port;
+
+ status = efi_udp_configure(udp_io, L"core_udp_connect");
+ if (EFI_ERROR (status))
+ {
+ Print(L"Failed to configure UDP: %d\n", status);
+ return;
+ }
+ }
+
}
/**
* Tear down a connection on an open socket
*
- * @param:socket, the open socket
+ * @param:socket, the open socket
*/
void core_udp_disconnect(struct pxe_pvt_inode *socket)
{
- EFI_STATUS status;
- EFI_UDP4 *udp;
-
- udp = (EFI_UDP4 *)socket->net.efi.binding->this;
-
- /* Reset */
- status = uefi_call_wrapper(udp->Configure, 2, udp, NULL);
- if (status != EFI_SUCCESS)
- Print(L"Failed to reset UDP: %d\n", status);
+
+ return;
+
}
-static int volatile cb_status = -1;
-static EFIAPI void udp4_cb(EFI_EVENT event, void *context)
-{
- (void)event;
-
- EFI_UDP4_COMPLETION_TOKEN *token = context;
- if (token->Status == EFI_SUCCESS)
- cb_status = 0;
- else
- cb_status = 1;
+/**
+ *
+ * Send callback function
+ *
+ */
+VOID
+EFIAPI
+UdpIoOnDgramSent (
+ IN EFI_EVENT event,
+ IN VOID* context
+ )
+{
+ UDP_IO* udp_io;
+ EFI_UDP4_COMPLETION_TOKEN* token;
+
+ udp_io = (UDP_IO*) context;
+ if( udp_io &&
+ (token = udp_io->Token) &&
+ token->Status == EFI_SUCCESS
+ )
+ uefi_call_wrapper(BS->SignalEvent, 1, udp_io->CB_OK_Event);
}
+
/**
- * Read data from the network stack
+ * Send a UDP packet (blocking call).
*
- * @param:socket, the open socket
- * @param:buf, location of buffer to store data
- * @param:buf_len, size of buffer
-
- * @out: src_ip, ip address of the data source
- * @out: src_port, port number of the data source, host-byte order
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
*/
-int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
- uint32_t *src_ip, uint16_t *src_port)
+
+void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
{
- EFI_UDP4_COMPLETION_TOKEN token;
- EFI_UDP4_FRAGMENT_DATA *frag;
- EFI_UDP4_RECEIVE_DATA *rxdata;
- struct efi_binding *b;
EFI_STATUS status;
- EFI_UDP4 *udp;
- size_t size;
- int rv = -1;
- jiffies_t start;
-
- (void)socket;
-
- b = udp_reader;
- udp = (EFI_UDP4 *)b->this;
- memset(&token, 0, sizeof(token));
-
- status = efi_setup_event(&token.Event, (EFI_EVENT_NOTIFY)udp4_cb,
- &token);
- if (status != EFI_SUCCESS)
- return -1;
-
- status = uefi_call_wrapper(udp->Receive, 2, udp, &token);
- if (status != EFI_SUCCESS)
- goto bail;
-
- start = jiffies();
- while (cb_status == -1) {
- /* 15ms receive timeout... */
- if (jiffies() - start >= 15) {
- if (jiffies() - start >= 30)
- dprintf("Failed to cancel UDP\n");
-
- uefi_call_wrapper(udp->Cancel, 2, udp, &token);
- dprintf("core_udp_recv: timed out\n");
- }
+ UDP_IO* udp_io;
+ EFI_UDP4* udp;
+ EFI_UDP4_COMPLETION_TOKEN* token=NULL;
+ EFI_UDP4_TRANSMIT_DATA* txdata=NULL;
+ EFI_UDP4_FRAGMENT_DATA* frag;
- uefi_call_wrapper(udp->Poll, 1, udp);
- }
+ udp_io = (UDP_IO*)socket->net.efi.context;
+ udp = udp_io->Protocol_Udp4;
- if (cb_status == 0)
- rv = 0;
- /* Reset */
- cb_status = -1;
-
- if (rv)
- goto bail;
-
- rxdata = token.Packet.RxData;
- frag = &rxdata->FragmentTable[0];
+ token = zalloc(sizeof(EFI_UDP4_COMPLETION_TOKEN));
+ if (!token)
+ goto bail;
- size = min(frag->FragmentLength, *buf_len);
- memcpy(buf, frag->FragmentBuffer, size);
- *buf_len = size;
+ txdata = zalloc(sizeof(EFI_UDP4_TRANSMIT_DATA));
+ if (!txdata)
+ goto bail;
- memcpy(src_port, &rxdata->UdpSession.SourcePort, sizeof(*src_port));
- memcpy(src_ip, &rxdata->UdpSession.SourceAddress, sizeof(*src_ip));
+ status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)UdpIoOnDgramSent,
+ udp_io);
+ if (EFI_ERROR (status))
+ goto bail;
- uefi_call_wrapper(BS->SignalEvent, 1, rxdata->RecycleSignal);
-bail:
- uefi_call_wrapper(BS->CloseEvent, 1, token.Event);
- return rv;
-}
+ udp_io->Token = token;
-/**
- * Send a UDP packet.
- *
- * @param:socket, the open socket
- * @param:data, data buffer to send
- * @param:len, size of data bufer
- */
-void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
-{
- EFI_UDP4_COMPLETION_TOKEN *token;
- EFI_UDP4_TRANSMIT_DATA *txdata;
- EFI_UDP4_FRAGMENT_DATA *frag;
- struct efi_binding *b = socket->net.efi.binding;
- EFI_STATUS status;
- EFI_UDP4 *udp = (EFI_UDP4 *)b->this;
-
- token = zalloc(sizeof(*token));
- if (!token)
- return;
-
- txdata = zalloc(sizeof(*txdata));
- if (!txdata) {
- free(token);
- return;
- }
-
- status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)udp4_cb,
- token);
- if (status != EFI_SUCCESS)
- goto bail;
-
- txdata->DataLength = len;
- txdata->FragmentCount = 1;
+ txdata->DataLength = len;
+ txdata->FragmentCount = 1;
+
frag = &txdata->FragmentTable[0];
-
frag->FragmentLength = len;
frag->FragmentBuffer = (void *)data;
token->Packet.TxData = txdata;
-
+
+ status = uefi_call_wrapper(BS->SetTimer, 3,
+ udp_io->Timeout_Timer,
+ TimerRelative,
+ UDP_TIME_TX_TIMEOUT
+ );
+ if (EFI_ERROR (status))
+ goto bail;
+
+ uefi_call_wrapper(BS->CheckEvent, 1, udp_io->CB_OK_Event);
status = uefi_call_wrapper(udp->Transmit, 2, udp, token);
- if (status != EFI_SUCCESS)
- goto close;
+ if (EFI_ERROR (status))
+ {
+ goto close;
+ }
- while (cb_status == -1)
- uefi_call_wrapper(udp->Poll, 1, udp);
+
+ while (1)
+ {
+ uefi_call_wrapper(udp->Poll, 1, udp);
+
+ if(!EFI_ERROR ( uefi_call_wrapper(BS->CheckEvent, 1, udp_io->CB_OK_Event) ))
+ {
+ goto close; //TX OK
+ }
+
+ if(!EFI_ERROR ( uefi_call_wrapper(BS->CheckEvent, 1, udp_io->Timeout_Timer) ))
+ {
+ dprintf("core_udp_send: timed out\n");
+ goto close; //TX timeout
+ }
+ }
- /* Reset */
- cb_status = -1;
close:
uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
bail:
- free(txdata);
- free(token);
+ if(txdata)
+ free(txdata);
+
+ if(token)
+ free(token);
+
+ udp_io->Token = NULL;
}
+
+
/**
* Send a UDP packet to a destination
*
- * @param:socket, the open socket
- * @param:data, data buffer to send
- * @param:len, size of data bufer
- * @param:ip, the ip address
- * @param:port, the port number, host-byte order
+ * @param:socket, the open socket
+ * @param:data, data buffer to send
+ * @param:len, size of data bufer
+ * @param:ip, the remote ip address
+ * @param:port, the remote port number, host-byte order
*/
void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data,
- size_t len, uint32_t ip, uint16_t port)
+ size_t len, uint32_t remote_ip, uint16_t remote_port)
{
- EFI_UDP4_COMPLETION_TOKEN *token;
- EFI_UDP4_TRANSMIT_DATA *txdata;
- EFI_UDP4_FRAGMENT_DATA *frag;
- EFI_UDP4_CONFIG_DATA udata;
- EFI_STATUS status;
- struct efi_binding *b;
- EFI_UDP4 *udp;
+ EFI_STATUS status;
+ UDP_IO* udp_io;
- (void)socket;
- b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
- if (!b)
- return;
+ udp_io = (UDP_IO*)socket->net.efi.context;
+
+ if(!udp_io->known_TID)
+ udp_io->known_TID=remote_port;
+
+ udp_io->Config_Udp4.AcceptBroadcast = FALSE;
+ udp_io->Config_Udp4.AcceptPromiscuous = FALSE;
+ udp_io->Config_Udp4.AcceptAnyPort = FALSE;
+ udp_io->Config_Udp4.AllowDuplicatePort = FALSE;
+ udp_io->Config_Udp4.TypeOfService = 0;
+ udp_io->Config_Udp4.TimeToLive = 64;
+ udp_io->Config_Udp4.DoNotFragment = FALSE;
+ udp_io->Config_Udp4.ReceiveTimeout = 0;
+ udp_io->Config_Udp4.TransmitTimeout = 0;
+
+
+ if (UseDefaultSetting)
+ {
+ udp_io->Config_Udp4.UseDefaultAddress = TRUE;
+ }
+ else
+ {
+ udp_io->Config_Udp4.UseDefaultAddress = FALSE;
+ memcpy(&udp_io->Config_Udp4.StationAddress , &IPInfo.myip, sizeof(IPInfo.myip));
+ memcpy(&udp_io->Config_Udp4.SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask));
+ }
+
+ //udp_io->Config_Udp4.StationPort = 0; //Reuse or initially assigned by FW
+
+ memcpy(&udp_io->Config_Udp4.RemoteAddress, &remote_ip, sizeof(remote_ip));
+ udp_io->Config_Udp4.RemotePort = remote_port;
+
+
+ status = efi_udp_configure(udp_io, L"core_udp_sendto");
+ if (EFI_ERROR (status))
+ return;
+
+ core_udp_send(socket, data, len);
- udp = (EFI_UDP4 *)b->this;
+}
- token = zalloc(sizeof(*token));
- if (!token)
- goto out;
+
+
+/**
+ *
+ * Receive callback function
+ *
+ */
+VOID
+EFIAPI
+UdpIoOnDgramRecvd (
+ IN EFI_EVENT event,
+ IN VOID* context
+ )
+{
+ UDP_IO* udp_io;
+ EFI_UDP4_COMPLETION_TOKEN* token;
+ EFI_UDP4_FRAGMENT_DATA* frag;
+ EFI_UDP4_RECEIVE_DATA* rxdata;
+
+ size_t size;
+
+ udp_io = (UDP_IO*) context;
+
+ if( udp_io &&
+ (token = udp_io->Token) &&
+ token->Status == EFI_SUCCESS
+ )
+ {
+ rxdata = token->Packet.RxData;
+ frag = &rxdata->FragmentTable[0];
+
+ size = min(frag->FragmentLength, *(udp_io->rx.buf_len));
+ memcpy(udp_io->rx.buf, frag->FragmentBuffer, size);
+ *(udp_io->rx.buf_len) = size;
+
+ memcpy(udp_io->rx.src_port, &rxdata->UdpSession.SourcePort, sizeof(*udp_io->rx.src_port));
+ memcpy(udp_io->rx.src_ip, &rxdata->UdpSession.SourceAddress, sizeof(*udp_io->rx.src_ip));
+
+ uefi_call_wrapper(BS->SignalEvent, 1, rxdata->RecycleSignal);
+
+ uefi_call_wrapper(BS->SignalEvent, 1, udp_io->CB_OK_Event);
+
+ }
+
+}
- txdata = zalloc(sizeof(*txdata));
- if (!txdata)
- goto bail;
-
- memset(&udata, 0, sizeof(udata));
-
- /* Re-use the existing local port number */
- udata.StationPort = socket->net.efi.localport;
-
- udata.UseDefaultAddress = TRUE;
- memcpy(&udata.RemoteAddress, &ip, sizeof(ip));
- udata.RemotePort = port;
- udata.AcceptPromiscuous = TRUE;
- udata.TimeToLive = 64;
-
- status = core_udp_configure(udp, &udata, L"core_udp_sendto");
- if (status != EFI_SUCCESS)
- goto bail;
-
- status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)udp4_cb,
- token);
- if (status != EFI_SUCCESS)
- goto bail;
- txdata->DataLength = len;
- txdata->FragmentCount = 1;
- frag = &txdata->FragmentTable[0];
+/**
+ * Read data from the network stack (blocking call)
+ *
+ * @param:socket, the open socket
+ * @param:buf, location of buffer to store data
+ * @param:buf_len, size of buffer
- frag->FragmentLength = len;
- frag->FragmentBuffer = (void *)data;
+ * @out:src_ip, ip address of the data source
+ * @out:src_port, port number of the data source, host-byte order
+ */
+
+int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
+ uint32_t *src_ip, uint16_t *src_port)
+{
+ EFI_STATUS status;
+ UDP_IO* udp_io;
+ EFI_UDP4* udp;
+ EFI_UDP4_COMPLETION_TOKEN* token;
+ int rv = -1;
- token->Packet.TxData = txdata;
- status = uefi_call_wrapper(udp->Transmit, 2, udp, token);
- if (status != EFI_SUCCESS)
- goto close;
+ udp_io = (UDP_IO*)socket->net.efi.context;
+ udp = udp_io->Protocol_Udp4;
+
+ token = zalloc(sizeof(EFI_UDP4_COMPLETION_TOKEN));
+
+ if (!token)
+ return -1;
- while (cb_status == -1)
- uefi_call_wrapper(udp->Poll, 1, udp);
- /* Reset */
- cb_status = -1;
+ status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)UdpIoOnDgramRecvd,
+ udp_io);
+ if (EFI_ERROR (status))
+ goto bail;
+
+
+ udp_io->Token = token;
+
+ udp_io->rx.buf = buf;
+ udp_io->rx.buf_len = buf_len;
+ udp_io->rx.src_ip = src_ip;
+ udp_io->rx.src_port = src_port;
+
+ status = uefi_call_wrapper( BS->SetTimer, 3,
+ udp_io->Timeout_Timer,
+ TimerRelative,
+ UDP_TIME_RX_TIMEOUT
+ );
+ if (EFI_ERROR (status))
+ goto bail;
+
+ if( udp_io->Config_Udp4.RemotePort == udp_io->known_TID )
+ {
+ udp_io->Config_Udp4.RemotePort=0;
+ status = efi_udp_configure(udp_io, L"core_udp_recv");
+ if (EFI_ERROR (status))
+ goto bail;
+ }
+
+ uefi_call_wrapper(BS->CheckEvent, 1, udp_io->CB_OK_Event);
+
+ status = uefi_call_wrapper(udp->Receive, 2, udp, token);
+ if (EFI_ERROR (status))
+ goto bail;
+
+ while (1)
+ {
+ uefi_call_wrapper(udp->Poll, 1, udp);
+
+
+ if(!EFI_ERROR ( uefi_call_wrapper(BS->CheckEvent, 1, udp_io->CB_OK_Event) ))
+ {
+ rv = 0;
+ goto close; //RX OK
+ }
+
+ if( ( EFI_SUCCESS == uefi_call_wrapper(BS->CheckEvent, 1, udp_io->Timeout_Timer)) )
+ {
+ uefi_call_wrapper(udp->Cancel, 2, udp, token);
+ dprintf("core_udp_recv: timed out\n");
+ rv = -1;
+ goto bail; //RX timeout
+ }
+
+ }
-close:
- uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
+close:
+
bail:
- free(txdata);
- free(token);
-out:
- efi_destroy_binding(b, &Udp4ServiceBindingProtocol);
+ uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
+
+ if(token)
+ free(token);
+
+ udp_io->Token=NULL;
+
+ return rv;
}
+
+
-------------- next part --------------
A non-text attachment was scrubbed...
Name: UEFI UDP compare-.png
Type: image/png
Size: 70861 bytes
Desc: not available
URL: <http://www.zytor.com/pipermail/syslinux/attachments/20160228/a7d90d8d/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: efi_udp.patch
Type: application/octet-stream
Size: 24996 bytes
Desc: not available
URL: <http://www.zytor.com/pipermail/syslinux/attachments/20160228/a7d90d8d/attachment-0001.obj>
More information about the Syslinux
mailing list