Home | History | Annotate | Download | only in efi
      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 
      9 extern EFI_GUID Tcp4ServiceBindingProtocol;
     10 extern EFI_GUID Tcp4Protocol;
     11 
     12 
     13 extern struct efi_binding *efi_create_binding(EFI_GUID *, EFI_GUID *);
     14 extern void efi_destroy_binding(struct efi_binding *, EFI_GUID *);
     15 int 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 
     28 static 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 
     37 static int volatile cb_status = -1;
     38 static 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 
     50 int 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 
    111 out:
    112     uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
    113     return rv;
    114 }
    115 
    116 bool 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 
    124 int 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 
    169 out:
    170     uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
    171     return rv;
    172 }
    173 
    174 void 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 
    200 static char databuf[8192];
    201 
    202 void 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 
    252 out:
    253     uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
    254 }
    255