Adding upstream version 6.03~pre2+dfsg.
[syslinux-debian/hramrach.git] / efi / tcp.c
blobb90efaf368b703b74aff838afd3b39bb9374cf0a
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 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;
88 if (status != EFI_SUCCESS)
89 return -1;
91 status = efi_setup_event(&token.CompletionToken.Event,
92 (EFI_EVENT_NOTIFY)tcp_cb, &token.CompletionToken);
93 if (status != EFI_SUCCESS)
94 return -1;
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;
102 while (cb_status == -1)
103 uefi_call_wrapper(tcp->Poll, 1, tcp);
105 if (cb_status == 0)
106 rv = 0;
108 /* Reset */
109 cb_status = -1;
111 out:
112 uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
113 return rv;
116 bool core_tcp_is_connected(struct pxe_pvt_inode *socket)
118 if (socket->net.efi.binding)
119 return true;
121 return false;
124 int core_tcp_write(struct pxe_pvt_inode *socket, const void *data,
125 size_t len, bool copy)
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;
135 (void)copy;
137 memset(&iotoken, 0, sizeof(iotoken));
138 memset(&txdata, 0, sizeof(txdata));
140 txdata.DataLength = len;
141 txdata.FragmentCount = 1;
143 frag = &txdata.FragmentTable[0];
144 frag->FragmentLength = len;
145 frag->FragmentBuffer = (void *)data;
147 iotoken.Packet.TxData = &txdata;
149 status = efi_setup_event(&iotoken.CompletionToken.Event,
150 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
151 if (status != EFI_SUCCESS)
152 return -1;
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;
160 while (cb_status == -1)
161 uefi_call_wrapper(tcp->Poll, 1, tcp);
163 if (cb_status == 0)
164 rv = 0;
166 /* Reset */
167 cb_status = -1;
169 out:
170 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
171 return rv;
174 void core_tcp_close_file(struct inode *inode)
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;
182 if (!socket->tftp_goteof) {
183 memset(&token, 0, sizeof(token));
185 status = efi_setup_event(&token.CompletionToken.Event,
186 (EFI_EVENT_NOTIFY)null_cb,
187 &token.CompletionToken);
188 if (status != EFI_SUCCESS)
189 return;
191 status = uefi_call_wrapper(tcp->Close, 2, tcp, &token);
192 if (status != EFI_SUCCESS)
193 Print(L"tcp close failed: %d\n", status);
196 efi_destroy_binding(b, &Tcp4ServiceBindingProtocol);
197 socket->net.efi.binding = NULL;
200 static char databuf[8192];
202 void core_tcp_fill_buffer(struct inode *inode)
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;
214 memset(&iotoken, 0, sizeof(iotoken));
215 memset(&rxdata, 0, sizeof(rxdata));
217 status = efi_setup_event(&iotoken.CompletionToken.Event,
218 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
219 if (status != EFI_SUCCESS)
220 return;
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);
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;
238 while (cb_status == -1)
239 uefi_call_wrapper(tcp->Poll, 1, tcp);
241 /* Reset */
242 cb_status = -1;
244 len = frag->FragmentLength;
245 memcpy(databuf, frag->FragmentBuffer, len);
246 data = databuf;
248 socket->tftp_dataptr = data;
249 socket->tftp_filepos += len;
250 socket->tftp_bytesleft = len;
252 out:
253 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);