5 #include "fs/pxe/pxe.h"
7 extern EFI_GUID Udp4ServiceBindingProtocol
, Udp4Protocol
;
10 * This UDP binding is configured to operate in promiscuous mode. It is
11 * only used for reading packets. It has no associated state unlike
12 * socket->net.efi.binding, which has a remote IP address and port
15 static struct efi_binding
*udp_reader
;
20 * @param:socket, the socket to open
22 * @out: error code, 0 on success, -1 on failure
24 int core_udp_open(struct pxe_pvt_inode
*socket
)
26 EFI_UDP4_CONFIG_DATA udata
;
27 struct efi_binding
*b
;
33 udp_reader
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
37 b
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
41 udp
= (EFI_UDP4
*)udp_reader
->this;
43 memset(&udata
, 0, sizeof(udata
));
44 udata
.AcceptPromiscuous
= TRUE
;
45 udata
.AcceptAnyPort
= TRUE
;
47 status
= uefi_call_wrapper(udp
->Configure
, 2, udp
, &udata
);
48 if (status
!= EFI_SUCCESS
)
51 socket
->net
.efi
.binding
= b
;
57 efi_destroy_binding(b
, &Udp4ServiceBindingProtocol
);
59 efi_destroy_binding(udp_reader
, &Udp4ServiceBindingProtocol
);
68 * @param:socket, the socket to open
70 void core_udp_close(struct pxe_pvt_inode
*socket
)
72 efi_destroy_binding(udp_reader
, &Udp4ServiceBindingProtocol
);
75 if (!socket
->net
.efi
.binding
)
78 efi_destroy_binding(socket
->net
.efi
.binding
, &Udp4ServiceBindingProtocol
);
79 socket
->net
.efi
.binding
= NULL
;
83 * Establish a connection on an open socket
85 * @param:socket, the open socket
86 * @param:ip, the ip address
87 * @param:port, the port number, host-byte order
89 void core_udp_connect(struct pxe_pvt_inode
*socket
, uint32_t ip
,
92 EFI_UDP4_CONFIG_DATA udata
;
96 udp
= (EFI_UDP4
*)socket
->net
.efi
.binding
->this;
98 memset(&udata
, 0, sizeof(udata
));
100 /* Re-use the existing local port number */
101 udata
.StationPort
= socket
->net
.efi
.localport
;
103 memcpy(&udata
.StationAddress
, &IPInfo
.myip
, sizeof(IPInfo
.myip
));
104 memcpy(&udata
.SubnetMask
, &IPInfo
.netmask
, sizeof(IPInfo
.netmask
));
105 memcpy(&udata
.RemoteAddress
, &ip
, sizeof(ip
));
106 udata
.RemotePort
= port
;
107 udata
.AcceptPromiscuous
= TRUE
;
108 udata
.TimeToLive
= 64;
110 status
= uefi_call_wrapper(udp
->Configure
, 2, udp
, &udata
);
111 if (status
!= EFI_SUCCESS
) {
112 Print(L
"Failed to configure UDP: %d\n", status
);
117 * If this is the first time connecting, save the random local port
118 * number that the UDPv4 Protocol Driver picked for us. The TFTP
119 * protocol uses the local port number as the TID, and it needs to
120 * be consistent across connect()/disconnect() calls.
122 if (!socket
->net
.efi
.localport
) {
123 status
= uefi_call_wrapper(udp
->GetModeData
, 5, udp
,
124 &udata
, NULL
, NULL
, NULL
);
125 if (status
!= EFI_SUCCESS
)
126 Print(L
"Failed to get UDP mode data: %d\n", status
);
128 socket
->net
.efi
.localport
= udata
.StationPort
;
133 * Tear down a connection on an open socket
135 * @param:socket, the open socket
137 void core_udp_disconnect(struct pxe_pvt_inode
*socket
)
142 udp
= (EFI_UDP4
*)socket
->net
.efi
.binding
->this;
145 status
= uefi_call_wrapper(udp
->Configure
, 2, udp
, NULL
);
146 if (status
!= EFI_SUCCESS
)
147 Print(L
"Failed to reset UDP: %d\n", status
);
151 static int volatile cb_status
= -1;
152 static EFIAPI
void udp4_cb(EFI_EVENT event
, void *context
)
156 EFI_UDP4_COMPLETION_TOKEN
*token
= context
;
158 if (token
->Status
== EFI_SUCCESS
)
165 * Read data from the network stack
167 * @param:socket, the open socket
168 * @param:buf, location of buffer to store data
169 * @param:buf_len, size of buffer
171 * @out: src_ip, ip address of the data source
172 * @out: src_port, port number of the data source, host-byte order
174 int core_udp_recv(struct pxe_pvt_inode
*socket
, void *buf
, uint16_t *buf_len
,
175 uint32_t *src_ip
, uint16_t *src_port
)
177 EFI_UDP4_COMPLETION_TOKEN token
;
178 EFI_UDP4_FRAGMENT_DATA
*frag
;
179 EFI_UDP4_RECEIVE_DATA
*rxdata
;
180 struct efi_binding
*b
;
190 udp
= (EFI_UDP4
*)b
->this;
192 status
= efi_setup_event(&token
.Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
194 if (status
!= EFI_SUCCESS
)
197 status
= uefi_call_wrapper(udp
->Receive
, 2, udp
, &token
);
198 if (status
!= EFI_SUCCESS
)
202 while (cb_status
== -1) {
203 /* 15ms receive timeout... */
204 if (jiffies() - start
>= 15) {
205 if (jiffies() - start
>= 30)
206 dprintf("Failed to cancel UDP\n");
208 uefi_call_wrapper(udp
->Cancel
, 2, udp
, &token
);
209 dprintf("core_udp_recv: timed out\n");
212 uefi_call_wrapper(udp
->Poll
, 1, udp
);
224 rxdata
= token
.Packet
.RxData
;
225 frag
= &rxdata
->FragmentTable
[0];
227 size
= min(frag
->FragmentLength
, *buf_len
);
228 memcpy(buf
, frag
->FragmentBuffer
, size
);
231 memcpy(src_port
, &rxdata
->UdpSession
.SourcePort
, sizeof(*src_port
));
232 memcpy(src_ip
, &rxdata
->UdpSession
.SourceAddress
, sizeof(*src_ip
));
234 uefi_call_wrapper(BS
->SignalEvent
, 1, rxdata
->RecycleSignal
);
237 uefi_call_wrapper(BS
->CloseEvent
, 1, token
.Event
);
244 * @param:socket, the open socket
245 * @param:data, data buffer to send
246 * @param:len, size of data bufer
248 void core_udp_send(struct pxe_pvt_inode
*socket
, const void *data
, size_t len
)
250 EFI_UDP4_COMPLETION_TOKEN
*token
;
251 EFI_UDP4_TRANSMIT_DATA
*txdata
;
252 EFI_UDP4_FRAGMENT_DATA
*frag
;
253 struct efi_binding
*b
= socket
->net
.efi
.binding
;
255 EFI_UDP4
*udp
= (EFI_UDP4
*)b
->this;
257 token
= zalloc(sizeof(*token
));
261 txdata
= zalloc(sizeof(*txdata
));
267 status
= efi_setup_event(&token
->Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
269 if (status
!= EFI_SUCCESS
)
272 txdata
->UdpSessionData
= NULL
;
273 txdata
->GatewayAddress
= NULL
;
274 txdata
->DataLength
= len
;
275 txdata
->FragmentCount
= 1;
276 frag
= &txdata
->FragmentTable
[0];
278 frag
->FragmentLength
= len
;
279 frag
->FragmentBuffer
= (void *)data
;
281 token
->Packet
.TxData
= txdata
;
283 status
= uefi_call_wrapper(udp
->Transmit
, 2, udp
, token
);
284 if (status
!= EFI_SUCCESS
)
287 while (cb_status
== -1)
288 uefi_call_wrapper(udp
->Poll
, 1, udp
);
294 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);
302 * Send a UDP packet to a destination
304 * @param:socket, the open socket
305 * @param:data, data buffer to send
306 * @param:len, size of data bufer
307 * @param:ip, the ip address
308 * @param:port, the port number, host-byte order
310 void core_udp_sendto(struct pxe_pvt_inode
*socket
, const void *data
,
311 size_t len
, uint32_t ip
, uint16_t port
)
313 EFI_UDP4_COMPLETION_TOKEN
*token
;
314 EFI_UDP4_TRANSMIT_DATA
*txdata
;
315 EFI_UDP4_FRAGMENT_DATA
*frag
;
316 EFI_UDP4_CONFIG_DATA udata
;
318 struct efi_binding
*b
;
323 b
= efi_create_binding(&Udp4ServiceBindingProtocol
, &Udp4Protocol
);
327 udp
= (EFI_UDP4
*)b
->this;
329 token
= zalloc(sizeof(*token
));
333 txdata
= zalloc(sizeof(*txdata
));
337 memset(&udata
, 0, sizeof(udata
));
339 memcpy(&udata
.StationAddress
, &IPInfo
.myip
, sizeof(IPInfo
.myip
));
340 memcpy(&udata
.SubnetMask
, &IPInfo
.netmask
, sizeof(IPInfo
.netmask
));
341 memcpy(&udata
.RemoteAddress
, &ip
, sizeof(ip
));
342 udata
.RemotePort
= port
;
343 udata
.AcceptPromiscuous
= TRUE
;
344 udata
.TimeToLive
= 64;
346 status
= uefi_call_wrapper(udp
->Configure
, 2, udp
, &udata
);
347 if (status
!= EFI_SUCCESS
)
350 status
= efi_setup_event(&token
->Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
352 if (status
!= EFI_SUCCESS
)
355 txdata
->UdpSessionData
= NULL
;
356 txdata
->GatewayAddress
= NULL
;
357 txdata
->DataLength
= len
;
358 txdata
->FragmentCount
= 1;
359 frag
= &txdata
->FragmentTable
[0];
361 frag
->FragmentLength
= len
;
362 frag
->FragmentBuffer
= (void *)data
;
364 token
->Packet
.TxData
= txdata
;
366 status
= uefi_call_wrapper(udp
->Transmit
, 2, udp
, token
);
367 if (status
!= EFI_SUCCESS
)
370 while (cb_status
== -1)
371 uefi_call_wrapper(udp
->Poll
, 1, udp
);
377 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);
383 efi_destroy_binding(b
, &Udp4ServiceBindingProtocol
);