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