syslinux/efi/tcp.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
   3 */
   4
   5#include "efi.h"
   6#include "net.h"
   7#include "fs/pxe/pxe.h"
   8
   9extern EFI_GUID Tcp4ServiceBindingProtocol;
  10extern EFI_GUID Tcp4Protocol;
  11
  12
  13extern struct efi_binding *efi_create_binding(EFI_GUID *, EFI_GUID *);
  14extern void efi_destroy_binding(struct efi_binding *, EFI_GUID *);
  15int core_tcp_open(struct pxe_pvt_inode *socket)
  16{
  17    struct efi_binding *b;
  18
  19    b = efi_create_binding(&Tcp4ServiceBindingProtocol, &Tcp4Protocol);
  20    if (!b)
  21        return -1;
  22
  23    socket->net.efi.binding = b;
  24
  25    return 0;
  26}
  27
  28static EFIAPI void null_cb(EFI_EVENT ev, void *context)
  29{
  30    EFI_TCP4_COMPLETION_TOKEN *token = context;
  31
  32    (void)ev;
  33
  34    uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
  35}
  36
  37static int volatile cb_status = -1;
  38static EFIAPI void tcp_cb(EFI_EVENT ev, void *context)
  39{
  40    EFI_TCP4_COMPLETION_TOKEN *token = context;
  41
  42    (void)ev;
  43
  44    if (token->Status == EFI_SUCCESS)
  45        cb_status = 0;
  46    else
  47        cb_status = 1;
  48}
  49
  50int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port)
  51{
  52    EFI_TCP4_CONNECTION_TOKEN token;
  53    EFI_TCP4_ACCESS_POINT *ap;
  54    EFI_TCP4_CONFIG_DATA tdata;
  55    struct efi_binding *b = socket->net.efi.binding;
  56    EFI_STATUS status;
  57    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
  58    int rv = -1;
  59    int unmapped = 1;
  60    jiffies_t start, last, cur;
  61
  62    memset(&tdata, 0, sizeof(tdata));
  63
  64    ap = &tdata.AccessPoint;
  65    ap->UseDefaultAddress = TRUE;
  66    memcpy(&ap->RemoteAddress, &ip, sizeof(ip));
  67    ap->RemotePort = port;
  68    ap->ActiveFlag = TRUE; /* Initiate active open */
  69
  70    tdata.TimeToLive = 64;
  71
  72    last = start = jiffies();
  73    while (unmapped){
  74        status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata);
  75        if (status != EFI_NO_MAPPING)
  76                unmapped = 0;
  77        else {
  78            cur = jiffies();
  79            if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) {
  80                last = cur;
  81                Print(L"core_tcp_connect: stalling on configure with no mapping\n");
  82            } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) {
  83                Print(L"core_tcp_connect: aborting on no mapping\n");
  84                unmapped = 0;
  85            }
  86        }
  87    }
  88    if (status != EFI_SUCCESS)
  89        return -1;
  90
  91    status = efi_setup_event(&token.CompletionToken.Event,
  92                            (EFI_EVENT_NOTIFY)tcp_cb, &token.CompletionToken);
  93    if (status != EFI_SUCCESS)
  94        return -1;
  95
  96    status = uefi_call_wrapper(tcp->Connect, 2, tcp, &token);
  97    if (status != EFI_SUCCESS) {
  98        Print(L"Failed to connect: %d\n", status);
  99        goto out;
 100    }
 101
 102    while (cb_status == -1)
 103        uefi_call_wrapper(tcp->Poll, 1, tcp);
 104
 105    if (cb_status == 0)
 106        rv = 0;
 107
 108    /* Reset */
 109    cb_status = -1;
 110
 111out:
 112    uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
 113    return rv;
 114}
 115
 116bool core_tcp_is_connected(struct pxe_pvt_inode *socket)
 117{
 118    if (socket->net.efi.binding)
 119        return true;
 120
 121    return false;
 122}
 123
 124int core_tcp_write(struct pxe_pvt_inode *socket, const void *data,
 125                   size_t len, bool copy)
 126{
 127    EFI_TCP4_TRANSMIT_DATA txdata;
 128    EFI_TCP4_FRAGMENT_DATA *frag;
 129    struct efi_binding *b = socket->net.efi.binding;
 130    EFI_TCP4_IO_TOKEN iotoken;
 131    EFI_STATUS status;
 132    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
 133    int rv = -1;
 134
 135    (void)copy;
 136
 137    memset(&iotoken, 0, sizeof(iotoken));
 138    memset(&txdata, 0, sizeof(txdata));
 139
 140    txdata.DataLength = len;
 141    txdata.FragmentCount = 1;
 142
 143    frag = &txdata.FragmentTable[0];
 144    frag->FragmentLength = len;
 145    frag->FragmentBuffer = (void *)data;
 146
 147    iotoken.Packet.TxData = &txdata;
 148
 149    status = efi_setup_event(&iotoken.CompletionToken.Event,
 150                             (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
 151    if (status != EFI_SUCCESS)
 152        return -1;
 153
 154    status = uefi_call_wrapper(tcp->Transmit, 2, tcp, &iotoken);
 155    if (status != EFI_SUCCESS) {
 156        Print(L"tcp transmit failed, %d\n", status);
 157        goto out;
 158    }
 159
 160    while (cb_status == -1)
 161        uefi_call_wrapper(tcp->Poll, 1, tcp);
 162
 163    if (cb_status == 0)
 164        rv = 0;
 165
 166    /* Reset */
 167    cb_status = -1;
 168
 169out:
 170    uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
 171    return rv;
 172}
 173
 174void core_tcp_close_file(struct inode *inode)
 175{
 176    struct pxe_pvt_inode *socket = PVT(inode);
 177    struct efi_binding *b = socket->net.efi.binding;
 178    EFI_TCP4_CLOSE_TOKEN token;
 179    EFI_STATUS status;
 180    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
 181
 182  if (!socket->tftp_goteof) {
 183        memset(&token, 0, sizeof(token));
 184
 185        status = efi_setup_event(&token.CompletionToken.Event,
 186                                 (EFI_EVENT_NOTIFY)null_cb,
 187                                 &token.CompletionToken);
 188        if (status != EFI_SUCCESS)
 189            return;
 190
 191        status = uefi_call_wrapper(tcp->Close, 2, tcp, &token);
 192        if (status != EFI_SUCCESS)
 193            Print(L"tcp close failed: %d\n", status);
 194    }
 195
 196    efi_destroy_binding(b, &Tcp4ServiceBindingProtocol);
 197    socket->net.efi.binding = NULL;
 198}
 199
 200static char databuf[8192];
 201
 202void core_tcp_fill_buffer(struct inode *inode)
 203{
 204    struct pxe_pvt_inode *socket = PVT(inode);
 205    struct efi_binding *b = socket->net.efi.binding;
 206    EFI_TCP4_IO_TOKEN iotoken;
 207    EFI_TCP4_RECEIVE_DATA rxdata;
 208    EFI_TCP4_FRAGMENT_DATA *frag;
 209    EFI_STATUS status;
 210    EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
 211    void *data;
 212    size_t len;
 213
 214    memset(&iotoken, 0, sizeof(iotoken));
 215    memset(&rxdata, 0, sizeof(rxdata));
 216
 217    status = efi_setup_event(&iotoken.CompletionToken.Event,
 218                      (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
 219    if (status != EFI_SUCCESS)
 220        return;
 221
 222    iotoken.Packet.RxData = &rxdata;
 223    rxdata.FragmentCount = 1;
 224    rxdata.DataLength = sizeof(databuf);
 225    frag = &rxdata.FragmentTable[0];
 226    frag->FragmentBuffer = databuf;
 227    frag->FragmentLength = sizeof(databuf);
 228
 229    status = uefi_call_wrapper(tcp->Receive, 2, tcp, &iotoken);
 230    if (status == EFI_CONNECTION_FIN) {
 231        socket->tftp_goteof = 1;
 232        if (inode->size == (uint64_t)-1)
 233            inode->size = socket->tftp_filepos;
 234        socket->ops->close(inode);
 235        goto out;
 236    }
 237
 238    while (cb_status == -1)
 239        uefi_call_wrapper(tcp->Poll, 1, tcp);
 240
 241    /* Reset */
 242    cb_status = -1;
 243
 244    len = frag->FragmentLength;
 245    memcpy(databuf, frag->FragmentBuffer, len);
 246    data = databuf;
 247
 248    socket->tftp_dataptr = data;
 249    socket->tftp_filepos += len;
 250    socket->tftp_bytesleft = len;
 251
 252out:
 253    uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
 254}
 255