diff options
Diffstat (limited to 'efi')
-rw-r--r-- | efi/efi.h | 5 | ||||
-rw-r--r-- | efi/tcp.c | 22 | ||||
-rw-r--r-- | efi/udp.c | 85 |
3 files changed, 81 insertions, 31 deletions
@@ -24,6 +24,11 @@ #include <efilib.h> #include <efistdarg.h> +/* Delay for 100 ms */ +#define EFI_NOMAP_PRINT_DELAY 100 +/* We should keep EFI_NOMAP_PRINT_COUNT at 10 to limit flooding the console */ +#define EFI_NOMAP_PRINT_COUNT 10 + struct efi_disk_private { EFI_HANDLE dev_handle; EFI_BLOCK_IO *bio; @@ -56,19 +56,35 @@ int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port) EFI_STATUS status; EFI_TCP4 *tcp = (EFI_TCP4 *)b->this; int rv = -1; + int unmapped = 1; + jiffies_t start, last, cur; memset(&tdata, 0, sizeof(tdata)); ap = &tdata.AccessPoint; - memcpy(&ap->StationAddress, &IPInfo.myip, sizeof(IPInfo.myip)); - memcpy(&ap->SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask)); + ap->UseDefaultAddress = TRUE; memcpy(&ap->RemoteAddress, &ip, sizeof(ip)); ap->RemotePort = port; ap->ActiveFlag = TRUE; /* Initiate active open */ tdata.TimeToLive = 64; - status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata); + last = start = jiffies(); + while (unmapped){ + status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata); + if (status != EFI_NO_MAPPING) + unmapped = 0; + else { + cur = jiffies(); + if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) { + last = cur; + Print(L"core_tcp_connect: stalling on configure with no mapping\n"); + } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) { + Print(L"core_tcp_connect: aborting on no mapping\n"); + unmapped = 0; + } + } + } if (status != EFI_SUCCESS) return -1; @@ -18,6 +18,42 @@ extern EFI_GUID Udp4ServiceBindingProtocol, Udp4Protocol; */ static struct efi_binding *udp_reader; +/** + * Try to configure this UDP socket + * + * @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. + * + * @out: status as EFI_STATUS + */ + +EFI_STATUS core_udp_configure(EFI_UDP4 *udp, EFI_UDP4_CONFIG_DATA *udata, + 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; +} + /** * Open a socket * @@ -45,15 +81,25 @@ int core_udp_open(struct pxe_pvt_inode *socket) udp = (EFI_UDP4 *)udp_reader->this; memset(&udata, 0, sizeof(udata)); - udata.AcceptPromiscuous = TRUE; - udata.AcceptAnyPort = TRUE; - status = uefi_call_wrapper(udp->Configure, 2, udp, &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; + return 0; bail: @@ -104,33 +150,17 @@ void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, /* 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)); + udata.UseDefaultAddress = TRUE; memcpy(&udata.RemoteAddress, &ip, sizeof(ip)); udata.RemotePort = port; udata.AcceptPromiscuous = TRUE; udata.TimeToLive = 64; - status = uefi_call_wrapper(udp->Configure, 2, udp, &udata); + status = core_udp_configure(udp, &udata, L"core_udp_connect"); 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; - } } /** @@ -192,6 +222,7 @@ int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, 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); @@ -273,8 +304,6 @@ void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len) if (status != EFI_SUCCESS) goto bail; - txdata->UdpSessionData = NULL; - txdata->GatewayAddress = NULL; txdata->DataLength = len; txdata->FragmentCount = 1; frag = &txdata->FragmentTable[0]; @@ -340,14 +369,16 @@ void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data, memset(&udata, 0, sizeof(udata)); - memcpy(&udata.StationAddress, &IPInfo.myip, sizeof(IPInfo.myip)); - memcpy(&udata.SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask)); + /* 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 = uefi_call_wrapper(udp->Configure, 2, udp, &udata); + status = core_udp_configure(udp, &udata, L"core_udp_sendto"); if (status != EFI_SUCCESS) goto bail; @@ -356,8 +387,6 @@ void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data, if (status != EFI_SUCCESS) goto bail; - txdata->UdpSessionData = NULL; - txdata->GatewayAddress = NULL; txdata->DataLength = len; txdata->FragmentCount = 1; frag = &txdata->FragmentTable[0]; |