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
;
189 udp
= (EFI_UDP4
*)b
->this;
191 status
= efi_setup_event(&token
.Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
193 if (status
!= EFI_SUCCESS
)
196 status
= uefi_call_wrapper(udp
->Receive
, 2, udp
, &token
);
197 if (status
!= EFI_SUCCESS
)
200 while (cb_status
== -1)
201 uefi_call_wrapper(udp
->Poll
, 1, udp
);
209 rxdata
= token
.Packet
.RxData
;
210 frag
= &rxdata
->FragmentTable
[0];
212 size
= min(frag
->FragmentLength
, *buf_len
);
213 memcpy(buf
, frag
->FragmentBuffer
, size
);
216 memcpy(src_port
, &rxdata
->UdpSession
.SourcePort
, sizeof(*src_port
));
217 memcpy(src_ip
, &rxdata
->UdpSession
.SourceAddress
, sizeof(*src_ip
));
219 uefi_call_wrapper(BS
->SignalEvent
, 1, rxdata
->RecycleSignal
);
222 uefi_call_wrapper(BS
->CloseEvent
, 1, token
.Event
);
229 * @param:socket, the open socket
230 * @param:data, data buffer to send
231 * @param:len, size of data bufer
233 void core_udp_send(struct pxe_pvt_inode
*socket
, const void *data
, size_t len
)
235 EFI_UDP4_COMPLETION_TOKEN
*token
;
236 EFI_UDP4_TRANSMIT_DATA
*txdata
;
237 EFI_UDP4_FRAGMENT_DATA
*frag
;
238 struct efi_binding
*b
= socket
->net
.efi
.binding
;
240 EFI_UDP4
*udp
= (EFI_UDP4
*)b
->this;
242 token
= zalloc(sizeof(*token
));
246 txdata
= zalloc(sizeof(*txdata
));
252 status
= efi_setup_event(&token
->Event
, (EFI_EVENT_NOTIFY
)udp4_cb
,
254 if (status
!= EFI_SUCCESS
)
257 txdata
->UdpSessionData
= NULL
;
258 txdata
->GatewayAddress
= NULL
;
259 txdata
->DataLength
= len
;
260 txdata
->FragmentCount
= 1;
261 frag
= &txdata
->FragmentTable
[0];
263 frag
->FragmentLength
= len
;
264 frag
->FragmentBuffer
= (void *)data
;
266 token
->Packet
.TxData
= txdata
;
268 status
= uefi_call_wrapper(udp
->Transmit
, 2, udp
, token
);
269 if (status
!= EFI_SUCCESS
)
272 while (cb_status
== -1)
273 uefi_call_wrapper(udp
->Poll
, 1, udp
);
279 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);