1
2
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;
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
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
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
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