2 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
9 #include "fs/pxe/pxe.h"
11 extern EFI_GUID Udp4ServiceBindingProtocol
, Udp4Protocol
;
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
19 static struct efi_binding
*udp_reader
;
22 * Try to configure this UDP socket
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.
28 * @out: status as EFI_STATUS
31 EFI_STATUS
core_udp_configure(EFI_UDP4
*udp
, EFI_UDP4_CONFIG_DATA
*udata
,
32 short unsigned int *f
)
36 jiffies_t start
, last
, cur
;
38 last
= start
= jiffies();
40 status
= uefi_call_wrapper(udp
->Configure
, 2, udp
, udata
);
41 if (status
!= EFI_NO_MAPPING
)
45 if ( (cur
- last
) >= EFI_NOMAP_PRINT_DELAY
) {
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
);
60 * @param:socket, the socket to open
62 * @out: error code, 0 on success, -1 on failure
64 int core_udp_open(struct pxe_pvt_inode
*socket
)
66 EFI_UDP4_CONFIG_DATA udata
;
67 struct efi_binding
*b
;
73 udp_reader
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
77 b
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
81 udp
= (EFI_UDP4
*)udp_reader
->this;
83 memset(&udata
, 0, sizeof(udata
));
85 status
= core_udp_configure(udp
, &udata
, L
"core_udp_open");
86 if (status
!= EFI_SUCCESS
)
89 socket
->net
.efi
.binding
= b
;
92 * Save the random local port number that the UDPv4 Protocol
93 * Driver picked for us. The TFTP protocol uses the local port
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
);
101 socket
->net
.efi
.localport
= udata
.StationPort
;
107 efi_destroy_binding(b
, &Udp4ServiceBindingProtocol
);
109 efi_destroy_binding(udp_reader
, &Udp4ServiceBindingProtocol
);
118 * @param:socket, the socket to open
120 void core_udp_close(struct pxe_pvt_inode
*socket
)
122 efi_destroy_binding(udp_reader
, &Udp4ServiceBindingProtocol
);
125 if (!socket
->net
.efi
.binding
)
128 efi_destroy_binding(socket
->net
.efi
.binding
, &Udp4ServiceBindingProtocol
);
129 socket
->net
.efi
.binding
= NULL
;
133 * Establish a connection on an open socket
135 * @param:socket, the open socket
136 * @param:ip, the ip address
137 * @param:port, the port number, host-byte order
139 void core_udp_connect(struct pxe_pvt_inode
*socket
, uint32_t ip
,
142 EFI_UDP4_CONFIG_DATA udata
;
146 udp
= (EFI_UDP4
*)socket
->net
.efi
.binding
->this;
148 memset(&udata
, 0, sizeof(udata
));
150 /* Re-use the existing local port number */
151 udata
.StationPort
= socket
->net
.efi
.localport
;
153 udata
.UseDefaultAddress
= TRUE
;
154 memcpy(&udata
.RemoteAddress
, &ip
, sizeof(ip
));
155 udata
.RemotePort
= port
;
156 udata
.AcceptPromiscuous
= TRUE
;
157 udata
.TimeToLive
= 64;
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
);
167 * Tear down a connection on an open socket
169 * @param:socket, the open socket
171 void core_udp_disconnect(struct pxe_pvt_inode
*socket
)
176 udp
= (EFI_UDP4
*)socket
->net
.efi
.binding
->this;
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
);
185 static int volatile cb_status
= -1;
186 static EFIAPI
void udp4_cb(EFI_EVENT event
, void *context
)
190 EFI_UDP4_COMPLETION_TOKEN
*token
= context
;
192 if (token
->Status
== EFI_SUCCESS
)
199 * Read data from the network stack
201 * @param:socket, the open socket
202 * @param:buf, location of buffer to store data
203 * @param:buf_len, size of buffer
205 * @out: src_ip, ip address of the data source
206 * @out: src_port, port number of the data source, host-byte order
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
)
211 EFI_UDP4_COMPLETION_TOKEN token
;
212 EFI_UDP4_FRAGMENT_DATA
*frag
;
213 EFI_UDP4_RECEIVE_DATA
*rxdata
;
214 struct efi_binding
*b
;
224 udp
= (EFI_UDP4
*)b
->this;
225 memset(&token
, 0, sizeof(token
));
227 status
= efi_setup_event(&token
.Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
229 if (status
!= EFI_SUCCESS
)
232 status
= uefi_call_wrapper(udp
->Receive
, 2, udp
, &token
);
233 if (status
!= EFI_SUCCESS
)
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");
243 uefi_call_wrapper(udp
->Cancel
, 2, udp
, &token
);
244 dprintf("core_udp_recv: timed out\n");
247 uefi_call_wrapper(udp
->Poll
, 1, udp
);
259 rxdata
= token
.Packet
.RxData
;
260 frag
= &rxdata
->FragmentTable
[0];
262 size
= min(frag
->FragmentLength
, *buf_len
);
263 memcpy(buf
, frag
->FragmentBuffer
, size
);
266 memcpy(src_port
, &rxdata
->UdpSession
.SourcePort
, sizeof(*src_port
));
267 memcpy(src_ip
, &rxdata
->UdpSession
.SourceAddress
, sizeof(*src_ip
));
269 uefi_call_wrapper(BS
->SignalEvent
, 1, rxdata
->RecycleSignal
);
272 uefi_call_wrapper(BS
->CloseEvent
, 1, token
.Event
);
279 * @param:socket, the open socket
280 * @param:data, data buffer to send
281 * @param:len, size of data bufer
283 void core_udp_send(struct pxe_pvt_inode
*socket
, const void *data
, size_t len
)
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
;
290 EFI_UDP4
*udp
= (EFI_UDP4
*)b
->this;
292 token
= zalloc(sizeof(*token
));
296 txdata
= zalloc(sizeof(*txdata
));
302 status
= efi_setup_event(&token
->Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
304 if (status
!= EFI_SUCCESS
)
307 txdata
->DataLength
= len
;
308 txdata
->FragmentCount
= 1;
309 frag
= &txdata
->FragmentTable
[0];
311 frag
->FragmentLength
= len
;
312 frag
->FragmentBuffer
= (void *)data
;
314 token
->Packet
.TxData
= txdata
;
316 status
= uefi_call_wrapper(udp
->Transmit
, 2, udp
, token
);
317 if (status
!= EFI_SUCCESS
)
320 while (cb_status
== -1)
321 uefi_call_wrapper(udp
->Poll
, 1, udp
);
327 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);
335 * Send a UDP packet to a destination
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
343 void core_udp_sendto(struct pxe_pvt_inode
*socket
, const void *data
,
344 size_t len
, uint32_t ip
, uint16_t port
)
346 EFI_UDP4_COMPLETION_TOKEN
*token
;
347 EFI_UDP4_TRANSMIT_DATA
*txdata
;
348 EFI_UDP4_FRAGMENT_DATA
*frag
;
349 EFI_UDP4_CONFIG_DATA udata
;
351 struct efi_binding
*b
;
356 b
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
360 udp
= (EFI_UDP4
*)b
->this;
362 token
= zalloc(sizeof(*token
));
366 txdata
= zalloc(sizeof(*txdata
));
370 memset(&udata
, 0, sizeof(udata
));
372 /* Re-use the existing local port number */
373 udata
.StationPort
= socket
->net
.efi
.localport
;
375 udata
.UseDefaultAddress
= TRUE
;
376 memcpy(&udata
.RemoteAddress
, &ip
, sizeof(ip
));
377 udata
.RemotePort
= port
;
378 udata
.AcceptPromiscuous
= TRUE
;
379 udata
.TimeToLive
= 64;
381 status
= core_udp_configure(udp
, &udata
, L
"core_udp_sendto");
382 if (status
!= EFI_SUCCESS
)
385 status
= efi_setup_event(&token
->Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
387 if (status
!= EFI_SUCCESS
)
390 txdata
->DataLength
= len
;
391 txdata
->FragmentCount
= 1;
392 frag
= &txdata
->FragmentTable
[0];
394 frag
->FragmentLength
= len
;
395 frag
->FragmentBuffer
= (void *)data
;
397 token
->Packet
.TxData
= txdata
;
399 status
= uefi_call_wrapper(udp
->Transmit
, 2, udp
, token
);
400 if (status
!= EFI_SUCCESS
)
403 while (cb_status
== -1)
404 uefi_call_wrapper(udp
->Poll
, 1, udp
);
410 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);
416 efi_destroy_binding(b
, &Udp4ServiceBindingProtocol
);