extlinux/main.c: space change
[syslinux.git] / efi / tcp.c
blob0e9140e4e4b1ce03324fa0dddc4f59ada1ec2ac1
1 /*
2 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
3 */
5 #include "efi.h"
6 #include "net.h"
7 #include "fs/pxe/pxe.h"
9 extern EFI_GUID Tcp4ServiceBindingProtocol;
10 extern EFI_GUID Tcp4Protocol;
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)
17 struct efi_binding *b;
19 b = efi_create_binding(&Tcp4ServiceBindingProtocol, &Tcp4Protocol);
20 if (!b)
21 return -1;
23 socket->net.efi.binding = b;
25 return 0;
28 static EFIAPI void null_cb(EFI_EVENT ev, void *context)
30 EFI_TCP4_COMPLETION_TOKEN *token = context;
32 (void)ev;
34 uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
37 static int volatile cb_status = -1;
38 static EFIAPI void tcp_cb(EFI_EVENT ev, void *context)
40 EFI_TCP4_COMPLETION_TOKEN *token = context;
42 (void)ev;
44 if (token->Status == EFI_SUCCESS)
45 cb_status = 0;
46 else
47 cb_status = 1;
50 int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port)
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;
62 memset(&tdata, 0, sizeof(tdata));
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 */
70 tdata.TimeToLive = 64;
72 last = start = jiffies();
73 while (unmapped){
74 status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata);
75 if (status == EFI_NO_MAPPING) {
76 cur = jiffies();
77 if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) {
78 last = cur;
79 Print(L"core_tcp_connect: stalling on configure with no mapping\n");
80 } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) {
81 Print(L"core_tcp_connect: aborting on no mapping\n");
82 unmapped = 0;
84 } else {
85 if (status != EFI_SUCCESS)
86 Print(L"core_tcp_connect: tcp->Configure() unsuccessful (%d)", status);
87 unmapped = 0;
90 if (status != EFI_SUCCESS)
91 return -1;
93 status = efi_setup_event(&token.CompletionToken.Event,
94 (EFI_EVENT_NOTIFY)tcp_cb, &token.CompletionToken);
95 if (status != EFI_SUCCESS)
96 return -1;
98 status = uefi_call_wrapper(tcp->Connect, 2, tcp, &token);
99 if (status != EFI_SUCCESS) {
100 Print(L"Failed to connect: %d\n", status);
101 goto out;
104 while (cb_status == -1)
105 uefi_call_wrapper(tcp->Poll, 1, tcp);
107 if (cb_status == 0)
108 rv = 0;
110 /* Reset */
111 cb_status = -1;
113 out:
114 uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
115 return rv;
118 bool core_tcp_is_connected(struct pxe_pvt_inode *socket)
120 if (socket->net.efi.binding)
121 return true;
123 return false;
126 int core_tcp_write(struct pxe_pvt_inode *socket, const void *data,
127 size_t len, bool copy)
129 EFI_TCP4_TRANSMIT_DATA txdata;
130 EFI_TCP4_FRAGMENT_DATA *frag;
131 struct efi_binding *b = socket->net.efi.binding;
132 EFI_TCP4_IO_TOKEN iotoken;
133 EFI_STATUS status;
134 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
135 int rv = -1;
137 (void)copy;
139 memset(&iotoken, 0, sizeof(iotoken));
140 memset(&txdata, 0, sizeof(txdata));
142 txdata.DataLength = len;
143 txdata.FragmentCount = 1;
145 frag = &txdata.FragmentTable[0];
146 frag->FragmentLength = len;
147 frag->FragmentBuffer = (void *)data;
149 iotoken.Packet.TxData = &txdata;
151 status = efi_setup_event(&iotoken.CompletionToken.Event,
152 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
153 if (status != EFI_SUCCESS)
154 return -1;
156 status = uefi_call_wrapper(tcp->Transmit, 2, tcp, &iotoken);
157 if (status != EFI_SUCCESS) {
158 Print(L"tcp transmit failed, %d\n", status);
159 goto out;
162 while (cb_status == -1)
163 uefi_call_wrapper(tcp->Poll, 1, tcp);
165 if (cb_status == 0)
166 rv = 0;
168 /* Reset */
169 cb_status = -1;
171 out:
172 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
173 return rv;
176 void core_tcp_close_file(struct inode *inode)
178 struct pxe_pvt_inode *socket = PVT(inode);
179 struct efi_binding *b = socket->net.efi.binding;
180 EFI_TCP4_CLOSE_TOKEN token;
181 EFI_STATUS status;
182 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
184 if (!socket->tftp_goteof) {
185 memset(&token, 0, sizeof(token));
187 status = efi_setup_event(&token.CompletionToken.Event,
188 (EFI_EVENT_NOTIFY)null_cb,
189 &token.CompletionToken);
190 if (status != EFI_SUCCESS)
191 return;
193 status = uefi_call_wrapper(tcp->Close, 2, tcp, &token);
194 if (status != EFI_SUCCESS)
195 Print(L"tcp close failed: %d\n", status);
198 efi_destroy_binding(b, &Tcp4ServiceBindingProtocol);
199 socket->net.efi.binding = NULL;
202 static char databuf[8192];
204 void core_tcp_fill_buffer(struct inode *inode)
206 struct pxe_pvt_inode *socket = PVT(inode);
207 struct efi_binding *b = socket->net.efi.binding;
208 EFI_TCP4_IO_TOKEN iotoken;
209 EFI_TCP4_RECEIVE_DATA rxdata;
210 EFI_TCP4_FRAGMENT_DATA *frag;
211 EFI_STATUS status;
212 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
213 void *data;
214 size_t len;
216 memset(&iotoken, 0, sizeof(iotoken));
217 memset(&rxdata, 0, sizeof(rxdata));
219 status = efi_setup_event(&iotoken.CompletionToken.Event,
220 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
221 if (status != EFI_SUCCESS)
222 return;
224 iotoken.Packet.RxData = &rxdata;
225 rxdata.FragmentCount = 1;
226 rxdata.DataLength = sizeof(databuf);
227 frag = &rxdata.FragmentTable[0];
228 frag->FragmentBuffer = databuf;
229 frag->FragmentLength = sizeof(databuf);
231 status = uefi_call_wrapper(tcp->Receive, 2, tcp, &iotoken);
232 if (status == EFI_CONNECTION_FIN) {
233 socket->tftp_goteof = 1;
234 if (inode->size == (uint64_t)-1)
235 inode->size = socket->tftp_filepos;
236 socket->ops->close(inode);
237 goto out;
240 while (cb_status == -1)
241 uefi_call_wrapper(tcp->Poll, 1, tcp);
243 /* Reset */
244 cb_status = -1;
246 len = frag->FragmentLength;
247 memcpy(databuf, frag->FragmentBuffer, len);
248 data = databuf;
250 socket->tftp_dataptr = data;
251 socket->tftp_filepos += len;
252 socket->tftp_bytesleft = len;
254 out:
255 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);