176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright 2013-2014 Intel Corporation - All Rights Reserved
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "efi.h"
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "net.h"
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "fs/pxe/pxe.h"
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern EFI_GUID Tcp4ServiceBindingProtocol;
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern EFI_GUID Tcp4Protocol;
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern struct efi_binding *efi_create_binding(EFI_GUID *, EFI_GUID *);
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanextern void efi_destroy_binding(struct efi_binding *, EFI_GUID *);
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint core_tcp_open(struct pxe_pvt_inode *socket)
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct efi_binding *b;
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    b = efi_create_binding(&Tcp4ServiceBindingProtocol, &Tcp4Protocol);
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!b)
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    socket->net.efi.binding = b;
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return 0;
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic EFIAPI void null_cb(EFI_EVENT ev, void *context)
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_COMPLETION_TOKEN *token = context;
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)ev;
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int volatile cb_status = -1;
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic EFIAPI void tcp_cb(EFI_EVENT ev, void *context)
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_COMPLETION_TOKEN *token = context;
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)ev;
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (token->Status == EFI_SUCCESS)
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cb_status = 0;
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    else
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	cb_status = 1;
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port)
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_CONNECTION_TOKEN token;
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_ACCESS_POINT *ap;
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_CONFIG_DATA tdata;
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct efi_binding *b = socket->net.efi.binding;
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_STATUS status;
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rv = -1;
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int unmapped = 1;
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    jiffies_t start, last, cur;
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&tdata, 0, sizeof(tdata));
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ap = &tdata.AccessPoint;
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ap->UseDefaultAddress = TRUE;
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(&ap->RemoteAddress, &ip, sizeof(ip));
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ap->RemotePort = port;
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ap->ActiveFlag = TRUE; /* Initiate active open */
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    tdata.TimeToLive = 64;
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    last = start = jiffies();
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (unmapped){
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata);
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status != EFI_NO_MAPPING)
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		unmapped = 0;
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	else {
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    cur = jiffies();
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) {
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		last = cur;
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		Print(L"core_tcp_connect: stalling on configure with no mapping\n");
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) {
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		Print(L"core_tcp_connect: aborting on no mapping\n");
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		unmapped = 0;
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    }
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	}
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS)
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = efi_setup_event(&token.CompletionToken.Event,
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			    (EFI_EVENT_NOTIFY)tcp_cb, &token.CompletionToken);
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS)
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = uefi_call_wrapper(tcp->Connect, 2, tcp, &token);
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS) {
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Print(L"Failed to connect: %d\n", status);
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto out;
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (cb_status == -1)
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uefi_call_wrapper(tcp->Poll, 1, tcp);
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cb_status == 0)
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = 0;
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Reset */
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cb_status = -1;
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout:
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv;
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanbool core_tcp_is_connected(struct pxe_pvt_inode *socket)
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (socket->net.efi.binding)
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return true;
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return false;
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanint core_tcp_write(struct pxe_pvt_inode *socket, const void *data,
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		   size_t len, bool copy)
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_TRANSMIT_DATA txdata;
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_FRAGMENT_DATA *frag;
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct efi_binding *b = socket->net.efi.binding;
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_IO_TOKEN iotoken;
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_STATUS status;
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int rv = -1;
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (void)copy;
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&iotoken, 0, sizeof(iotoken));
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&txdata, 0, sizeof(txdata));
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txdata.DataLength = len;
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    txdata.FragmentCount = 1;
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag = &txdata.FragmentTable[0];
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag->FragmentLength = len;
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag->FragmentBuffer = (void *)data;
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    iotoken.Packet.TxData = &txdata;
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = efi_setup_event(&iotoken.CompletionToken.Event,
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman			     (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS)
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return -1;
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = uefi_call_wrapper(tcp->Transmit, 2, tcp, &iotoken);
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS) {
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	Print(L"tcp transmit failed, %d\n", status);
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto out;
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (cb_status == -1)
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uefi_call_wrapper(tcp->Poll, 1, tcp);
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (cb_status == 0)
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	rv = 0;
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Reset */
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cb_status = -1;
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout:
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return rv;
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid core_tcp_close_file(struct inode *inode)
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pxe_pvt_inode *socket = PVT(inode);
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct efi_binding *b = socket->net.efi.binding;
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_CLOSE_TOKEN token;
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_STATUS status;
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (!socket->tftp_goteof) {
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	memset(&token, 0, sizeof(token));
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = efi_setup_event(&token.CompletionToken.Event,
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 (EFI_EVENT_NOTIFY)null_cb,
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman				 &token.CompletionToken);
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status != EFI_SUCCESS)
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    return;
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	status = uefi_call_wrapper(tcp->Close, 2, tcp, &token);
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (status != EFI_SUCCESS)
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    Print(L"tcp close failed: %d\n", status);
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    efi_destroy_binding(b, &Tcp4ServiceBindingProtocol);
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    socket->net.efi.binding = NULL;
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic char databuf[8192];
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid core_tcp_fill_buffer(struct inode *inode)
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pxe_pvt_inode *socket = PVT(inode);
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct efi_binding *b = socket->net.efi.binding;
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_IO_TOKEN iotoken;
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_RECEIVE_DATA rxdata;
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4_FRAGMENT_DATA *frag;
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_STATUS status;
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    void *data;
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    size_t len;
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&iotoken, 0, sizeof(iotoken));
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memset(&rxdata, 0, sizeof(rxdata));
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = efi_setup_event(&iotoken.CompletionToken.Event,
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman		      (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status != EFI_SUCCESS)
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	return;
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    iotoken.Packet.RxData = &rxdata;
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rxdata.FragmentCount = 1;
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    rxdata.DataLength = sizeof(databuf);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag = &rxdata.FragmentTable[0];
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag->FragmentBuffer = databuf;
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    frag->FragmentLength = sizeof(databuf);
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    status = uefi_call_wrapper(tcp->Receive, 2, tcp, &iotoken);
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (status == EFI_CONNECTION_FIN) {
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	socket->tftp_goteof = 1;
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	if (inode->size == (uint64_t)-1)
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	    inode->size = socket->tftp_filepos;
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	socket->ops->close(inode);
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	goto out;
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (cb_status == -1)
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman	uefi_call_wrapper(tcp->Poll, 1, tcp);
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Reset */
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    cb_status = -1;
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    len = frag->FragmentLength;
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memcpy(databuf, frag->FragmentBuffer, len);
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    data = databuf;
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    socket->tftp_dataptr = data;
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    socket->tftp_filepos += len;
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    socket->tftp_bytesleft = len;
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout:
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
255