1 /*
2  * Copyright 2013-2014 Intel Corporation - All Rights Reserved
3  */
4 
5 #include <string.h>
6 #include <minmax.h>
7 #include "efi.h"
8 #include "net.h"
9 #include "fs/pxe/pxe.h"
10 
11 extern EFI_GUID Udp4ServiceBindingProtocol, Udp4Protocol;
12 
13 /*
14  * This UDP binding is configured to operate in promiscuous mode. It is
15  * only used for reading packets. It has no associated state unlike
16  * socket->net.efi.binding, which has a remote IP address and port
17  * number.
18  */
19 static struct efi_binding *udp_reader;
20 
21 /**
22  * Try to configure this UDP socket
23  *
24  * @param:udp, the EFI_UDP4 socket to configure
25  * @param:udata, the EFI_UDP4_CONFIG_DATA to use
26  * @param:f, the name of the function as a wide string.
27  *
28  * @out: status as EFI_STATUS
29  */
30 
core_udp_configure(EFI_UDP4 * udp,EFI_UDP4_CONFIG_DATA * udata,short unsigned int * f)31 EFI_STATUS core_udp_configure(EFI_UDP4 *udp, EFI_UDP4_CONFIG_DATA *udata,
32 	short unsigned int *f)
33 {
34     EFI_STATUS status;
35     int unmapped = 1;
36     jiffies_t start, last, cur;
37 
38     last = start = jiffies();
39     while (unmapped){
40 	status = uefi_call_wrapper(udp->Configure, 2, udp, udata);
41 	if (status != EFI_NO_MAPPING)
42 		unmapped = 0;
43 	else {
44 	    cur = jiffies();
45 	    if ( (cur - last) >= EFI_NOMAP_PRINT_DELAY ) {
46 		last = cur;
47 		Print(L"%s: stalling on configure with no mapping\n", f);
48 	    } else if ( (cur - start) > EFI_NOMAP_PRINT_DELAY * EFI_NOMAP_PRINT_COUNT) {
49 		Print(L"%s: aborting on no mapping\n", f);
50 		unmapped = 0;
51 	    }
52 	}
53     }
54     return status;
55 }
56 
57 /**
58  * Open a socket
59  *
60  * @param:socket, the socket to open
61  *
62  * @out: error code, 0 on success, -1 on failure
63  */
core_udp_open(struct pxe_pvt_inode * socket)64 int core_udp_open(struct pxe_pvt_inode *socket)
65 {
66     EFI_UDP4_CONFIG_DATA udata;
67     struct efi_binding *b;
68     EFI_STATUS status;
69     EFI_UDP4 *udp;
70 
71     (void)socket;
72 
73     udp_reader = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
74     if (!udp_reader)
75 	return -1;
76 
77     b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
78     if (!b)
79 	goto bail;
80 
81     udp = (EFI_UDP4 *)udp_reader->this;
82 
83     memset(&udata, 0, sizeof(udata));
84 
85     status = core_udp_configure(udp, &udata, L"core_udp_open");
86     if (status != EFI_SUCCESS)
87 	goto bail;
88 
89     socket->net.efi.binding = b;
90 
91     /*
92      * Save the random local port number that the UDPv4 Protocol
93      * Driver picked for us. The TFTP protocol uses the local port
94      * number as the TID.
95      */
96     status = uefi_call_wrapper(udp->GetModeData, 5, udp,
97 			       &udata, NULL, NULL, NULL);
98     if (status != EFI_SUCCESS)
99 	Print(L"Failed to get UDP mode data: %d\n", status);
100     else
101 	socket->net.efi.localport = udata.StationPort;
102 
103     return 0;
104 
105 bail:
106     if (b)
107 	efi_destroy_binding(b, &Udp4ServiceBindingProtocol);
108 
109     efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol);
110     udp_reader = NULL;
111 
112     return -1;
113 }
114 
115 /**
116  * Close a socket
117  *
118  * @param:socket, the socket to open
119  */
core_udp_close(struct pxe_pvt_inode * socket)120 void core_udp_close(struct pxe_pvt_inode *socket)
121 {
122     efi_destroy_binding(udp_reader, &Udp4ServiceBindingProtocol);
123     udp_reader = NULL;
124 
125     if (!socket->net.efi.binding)
126 	return;
127 
128     efi_destroy_binding(socket->net.efi.binding, &Udp4ServiceBindingProtocol);
129     socket->net.efi.binding = NULL;
130 }
131 
132 /**
133  * Establish a connection on an open socket
134  *
135  * @param:socket, the open socket
136  * @param:ip, the ip address
137  * @param:port, the port number, host-byte order
138  */
core_udp_connect(struct pxe_pvt_inode * socket,uint32_t ip,uint16_t port)139 void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip,
140 		      uint16_t port)
141 {
142     EFI_UDP4_CONFIG_DATA udata;
143     EFI_STATUS status;
144     EFI_UDP4 *udp;
145 
146     udp = (EFI_UDP4 *)socket->net.efi.binding->this;
147 
148     memset(&udata, 0, sizeof(udata));
149 
150     /* Re-use the existing local port number */
151     udata.StationPort = socket->net.efi.localport;
152 
153     udata.UseDefaultAddress = TRUE;
154     memcpy(&udata.RemoteAddress, &ip, sizeof(ip));
155     udata.RemotePort = port;
156     udata.AcceptPromiscuous = TRUE;
157     udata.TimeToLive = 64;
158 
159     status = core_udp_configure(udp, &udata, L"core_udp_connect");
160     if (status != EFI_SUCCESS) {
161 	Print(L"Failed to configure UDP: %d\n", status);
162 	return;
163     }
164 }
165 
166 /**
167  * Tear down a connection on an open socket
168  *
169  * @param:socket, the open socket
170  */
core_udp_disconnect(struct pxe_pvt_inode * socket)171 void core_udp_disconnect(struct pxe_pvt_inode *socket)
172 {
173     EFI_STATUS status;
174     EFI_UDP4 *udp;
175 
176     udp = (EFI_UDP4 *)socket->net.efi.binding->this;
177 
178     /* Reset */
179     status = uefi_call_wrapper(udp->Configure, 2, udp, NULL);
180     if (status != EFI_SUCCESS)
181 	Print(L"Failed to reset UDP: %d\n", status);
182 
183 }
184 
185 static int volatile cb_status = -1;
udp4_cb(EFI_EVENT event,void * context)186 static EFIAPI void udp4_cb(EFI_EVENT event, void *context)
187 {
188     (void)event;
189 
190     EFI_UDP4_COMPLETION_TOKEN *token = context;
191 
192     if (token->Status == EFI_SUCCESS)
193 	cb_status = 0;
194     else
195 	cb_status = 1;
196 }
197 
198 /**
199  * Read data from the network stack
200  *
201  * @param:socket, the open socket
202  * @param:buf, location of buffer to store data
203  * @param:buf_len, size of buffer
204 
205  * @out: src_ip, ip address of the data source
206  * @out: src_port, port number of the data source, host-byte order
207  */
core_udp_recv(struct pxe_pvt_inode * socket,void * buf,uint16_t * buf_len,uint32_t * src_ip,uint16_t * src_port)208 int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
209 		  uint32_t *src_ip, uint16_t *src_port)
210 {
211     EFI_UDP4_COMPLETION_TOKEN token;
212     EFI_UDP4_FRAGMENT_DATA *frag;
213     EFI_UDP4_RECEIVE_DATA *rxdata;
214     struct efi_binding *b;
215     EFI_STATUS status;
216     EFI_UDP4 *udp;
217     size_t size;
218     int rv = -1;
219     jiffies_t start;
220 
221     (void)socket;
222 
223     b = udp_reader;
224     udp = (EFI_UDP4 *)b->this;
225     memset(&token, 0, sizeof(token));
226 
227     status = efi_setup_event(&token.Event, (EFI_EVENT_NOTIFY)udp4_cb,
228 			     &token);
229     if (status != EFI_SUCCESS)
230 	return -1;
231 
232     status = uefi_call_wrapper(udp->Receive, 2, udp, &token);
233     if (status != EFI_SUCCESS)
234 	goto bail;
235 
236     start = jiffies();
237     while (cb_status == -1) {
238 	/* 15ms receive timeout... */
239 	if (jiffies() - start >= 15) {
240 	    if (jiffies() - start >= 30)
241 		dprintf("Failed to cancel UDP\n");
242 
243 	    uefi_call_wrapper(udp->Cancel, 2, udp, &token);
244 	    dprintf("core_udp_recv: timed out\n");
245 	}
246 
247 	uefi_call_wrapper(udp->Poll, 1, udp);
248     }
249 
250     if (cb_status == 0)
251 	rv = 0;
252 
253     /* Reset */
254     cb_status = -1;
255 
256     if (rv)
257 	goto bail;
258 
259     rxdata = token.Packet.RxData;
260     frag = &rxdata->FragmentTable[0];
261 
262     size = min(frag->FragmentLength, *buf_len);
263     memcpy(buf, frag->FragmentBuffer, size);
264     *buf_len = size;
265 
266     memcpy(src_port, &rxdata->UdpSession.SourcePort, sizeof(*src_port));
267     memcpy(src_ip, &rxdata->UdpSession.SourceAddress, sizeof(*src_ip));
268 
269     uefi_call_wrapper(BS->SignalEvent, 1, rxdata->RecycleSignal);
270 
271 bail:
272     uefi_call_wrapper(BS->CloseEvent, 1, token.Event);
273     return rv;
274 }
275 
276 /**
277  * Send a UDP packet.
278  *
279  * @param:socket, the open socket
280  * @param:data, data buffer to send
281  * @param:len, size of data bufer
282  */
core_udp_send(struct pxe_pvt_inode * socket,const void * data,size_t len)283 void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
284 {
285     EFI_UDP4_COMPLETION_TOKEN *token;
286     EFI_UDP4_TRANSMIT_DATA *txdata;
287     EFI_UDP4_FRAGMENT_DATA *frag;
288     struct efi_binding *b = socket->net.efi.binding;
289     EFI_STATUS status;
290     EFI_UDP4 *udp = (EFI_UDP4 *)b->this;
291 
292     token = zalloc(sizeof(*token));
293     if (!token)
294 	return;
295 
296     txdata = zalloc(sizeof(*txdata));
297     if (!txdata) {
298 	free(token);
299 	return;
300     }
301 
302     status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)udp4_cb,
303 			     token);
304     if (status != EFI_SUCCESS)
305 	goto bail;
306 
307     txdata->DataLength = len;
308     txdata->FragmentCount = 1;
309     frag = &txdata->FragmentTable[0];
310 
311     frag->FragmentLength = len;
312     frag->FragmentBuffer = (void *)data;
313 
314     token->Packet.TxData = txdata;
315 
316     status = uefi_call_wrapper(udp->Transmit, 2, udp, token);
317     if (status != EFI_SUCCESS)
318 	goto close;
319 
320     while (cb_status == -1)
321 	uefi_call_wrapper(udp->Poll, 1, udp);
322 
323     /* Reset */
324     cb_status = -1;
325 
326 close:
327     uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
328 
329 bail:
330     free(txdata);
331     free(token);
332 }
333 
334 /**
335  * Send a UDP packet to a destination
336  *
337  * @param:socket, the open socket
338  * @param:data, data buffer to send
339  * @param:len, size of data bufer
340  * @param:ip, the ip address
341  * @param:port, the port number, host-byte order
342  */
core_udp_sendto(struct pxe_pvt_inode * socket,const void * data,size_t len,uint32_t ip,uint16_t port)343 void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data,
344 		     size_t len, uint32_t ip, uint16_t port)
345 {
346     EFI_UDP4_COMPLETION_TOKEN *token;
347     EFI_UDP4_TRANSMIT_DATA *txdata;
348     EFI_UDP4_FRAGMENT_DATA *frag;
349     EFI_UDP4_CONFIG_DATA udata;
350     EFI_STATUS status;
351     struct efi_binding *b;
352     EFI_UDP4 *udp;
353 
354     (void)socket;
355 
356     b = efi_create_binding(&Udp4ServiceBindingProtocol, &Udp4Protocol);
357     if (!b)
358 	return;
359 
360     udp = (EFI_UDP4 *)b->this;
361 
362     token = zalloc(sizeof(*token));
363     if (!token)
364 	goto out;
365 
366     txdata = zalloc(sizeof(*txdata));
367     if (!txdata)
368 	goto bail;
369 
370     memset(&udata, 0, sizeof(udata));
371 
372     /* Re-use the existing local port number */
373     udata.StationPort = socket->net.efi.localport;
374 
375     udata.UseDefaultAddress = TRUE;
376     memcpy(&udata.RemoteAddress, &ip, sizeof(ip));
377     udata.RemotePort = port;
378     udata.AcceptPromiscuous = TRUE;
379     udata.TimeToLive = 64;
380 
381     status = core_udp_configure(udp, &udata, L"core_udp_sendto");
382     if (status != EFI_SUCCESS)
383 	goto bail;
384 
385     status = efi_setup_event(&token->Event, (EFI_EVENT_NOTIFY)udp4_cb,
386 			     token);
387     if (status != EFI_SUCCESS)
388 	goto bail;
389 
390     txdata->DataLength = len;
391     txdata->FragmentCount = 1;
392     frag = &txdata->FragmentTable[0];
393 
394     frag->FragmentLength = len;
395     frag->FragmentBuffer = (void *)data;
396 
397     token->Packet.TxData = txdata;
398 
399     status = uefi_call_wrapper(udp->Transmit, 2, udp, token);
400     if (status != EFI_SUCCESS)
401 	goto close;
402 
403     while (cb_status == -1)
404 	uefi_call_wrapper(udp->Poll, 1, udp);
405 
406     /* Reset */
407     cb_status = -1;
408 
409 close:
410     uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
411 
412 bail:
413     free(txdata);
414     free(token);
415 out:
416     efi_destroy_binding(b, &Udp4ServiceBindingProtocol);
417 }
418