diff options
author | Matt Fleming <matt.fleming@intel.com> | 2013-06-26 10:17:54 +0100 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2013-06-26 10:41:10 +0100 |
commit | c5c37402f45d705cf4fee3870e44d6cd14649971 (patch) | |
tree | 8608168b42aeaf095f40257be63cac2c52e454a5 /efi | |
parent | 042d0e52f7debe5bdf303254e3b8e90d24e97635 (diff) | |
download | syslinux-c5c37402f45d705cf4fee3870e44d6cd14649971.tar.gz |
efi, udp: use single local port for each connectionsyslinux-6.01-pre2
The TFTP protocol uses the local port as an idenitifer during a transfer
(TID), which means that once we've established a TFTP connection, we
must ensure we reuse the same local port number in each packet. Failure
to do so is an error, which causes the TFTP server to send an error
packet.
From RFC 1350 - THE TFTP PROTOCOL (REVISION 2), Section 4,
In the next step, and in all succeeding steps, the hosts should make
sure that the source TID matches the value that was agreed on in
steps 1 and 2. If a source TID does not match, the packet should be
discarded as erroneously sent from somewhere else. An error packet
should be sent to the source of the incorrect packet, while not
disturbing the transfer.
Once the UDPv4 protocol driver has been assigned a local port number
(which happens on the first core_udp_connect()) reuse that number until
core_udp_close() time.
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'efi')
-rw-r--r-- | efi/udp.c | 76 |
1 files changed, 54 insertions, 22 deletions
@@ -24,6 +24,7 @@ static struct efi_binding *udp_reader; int core_udp_open(struct pxe_pvt_inode *socket) { EFI_UDP4_CONFIG_DATA udata; + struct efi_binding *b; EFI_STATUS status; EFI_UDP4 *udp; @@ -33,6 +34,10 @@ int core_udp_open(struct pxe_pvt_inode *socket) 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)); @@ -40,13 +45,21 @@ int core_udp_open(struct pxe_pvt_inode *socket) udata.AcceptAnyPort = TRUE; status = uefi_call_wrapper(udp->Configure, 2, udp, &udata); - if (status != EFI_SUCCESS) { - efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol); - udp_reader = NULL; - return -1; - } + if (status != EFI_SUCCESS) + goto bail; + + socket->net.efi.binding = b; return 0; + +bail: + if (b) + efi_destroy_binding(b, &Udp4ServiceBindingProtocol); + + efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol); + udp_reader = NULL; + + return -1; } /** @@ -56,10 +69,14 @@ int core_udp_open(struct pxe_pvt_inode *socket) */ void core_udp_close(struct pxe_pvt_inode *socket) { - (void)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; } /** @@ -73,20 +90,16 @@ void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port) { EFI_UDP4_CONFIG_DATA udata; - struct efi_binding *b; EFI_STATUS status; EFI_UDP4 *udp; - b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol); - if (!b) - return; - - socket->net.efi.binding = b; - - udp = (EFI_UDP4 *)b->this; + 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; + memcpy(&udata.StationAddress, &IPInfo.myip, sizeof(IPInfo.myip)); memcpy(&udata.SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask)); memcpy(&udata.RemoteAddress, &ip, sizeof(ip)); @@ -94,8 +107,25 @@ void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, udata.AcceptPromiscuous = TRUE; status = uefi_call_wrapper(udp->Configure, 2, udp, &udata); - if (status != EFI_SUCCESS) + if (status != EFI_SUCCESS) { Print(L"Failed to configure UDP: %d\n", status); + return; + } + + /* + * If this is the first time connecting, 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, and it needs to + * be consistent across connect()/disconnect() calls. + */ + if (!socket->net.efi.localport) { + 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; + } } /** @@ -105,14 +135,16 @@ void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, */ void core_udp_disconnect(struct pxe_pvt_inode *socket) { - struct efi_binding *b; + EFI_STATUS status; + EFI_UDP4 *udp; - if (!socket->net.efi.binding) - return; + 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); - b = socket->net.efi.binding; - efi_destroy_binding(b, &Udp4ServiceBindingProtocol); - socket->net.efi.binding = NULL; } static int volatile cb_status = -1; |