2 * Copyright 2013-2014 Intel Corporation - All Rights Reserved
7 #include "fs/pxe/pxe.h"
9 extern EFI_GUID Tcp4ServiceBindingProtocol
;
10 extern EFI_GUID Tcp4Protocol
;
13 extern struct efi_binding
*efi_create_binding(EFI_GUID
*, EFI_GUID
*);
14 extern void efi_destroy_binding(struct efi_binding
*, EFI_GUID
*);
15 int core_tcp_open(struct pxe_pvt_inode
*socket
)
17 struct efi_binding
*b
;
19 b
= efi_create_binding(&Tcp4ServiceBindingProtocol
, &Tcp4Protocol
);
23 socket
->net
.efi
.binding
= b
;
28 static EFIAPI
void null_cb(EFI_EVENT ev
, void *context
)
30 EFI_TCP4_COMPLETION_TOKEN
*token
= context
;
34 uefi_call_wrapper(BS
->CloseEvent
, 1, token
->Event
);
37 static int volatile cb_status
= -1;
38 static EFIAPI
void tcp_cb(EFI_EVENT ev
, void *context
)
40 EFI_TCP4_COMPLETION_TOKEN
*token
= context
;
44 if (token
->Status
== EFI_SUCCESS
)
50 int core_tcp_connect(struct pxe_pvt_inode
*socket
, uint32_t ip
, uint16_t port
)
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
;
57 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
60 jiffies_t start
, last
, cur
;
62 memset(&tdata
, 0, sizeof(tdata
));
64 ap
= &tdata
.AccessPoint
;
65 ap
->UseDefaultAddress
= TRUE
;
66 memcpy(&ap
->RemoteAddress
, &ip
, sizeof(ip
));
67 ap
->RemotePort
= port
;
68 ap
->ActiveFlag
= TRUE
; /* Initiate active open */
70 tdata
.TimeToLive
= 64;
72 last
= start
= jiffies();
74 status
= uefi_call_wrapper(tcp
->Configure
, 2, tcp
, &tdata
);
75 if (status
== EFI_NO_MAPPING
) {
77 if ( (cur
- last
) >= EFI_NOMAP_PRINT_DELAY
) {
79 Print(L
"core_tcp_connect: stalling on configure with no mapping\n");
80 } else if ( (cur
- start
) > EFI_NOMAP_PRINT_DELAY
* EFI_NOMAP_PRINT_COUNT
) {
81 Print(L
"core_tcp_connect: aborting on no mapping\n");
85 if (status
!= EFI_SUCCESS
)
86 Print(L
"core_tcp_connect: tcp->Configure() unsuccessful (%i)", status
);
90 if (status
!= EFI_SUCCESS
)
93 status
= efi_setup_event(&token
.CompletionToken
.Event
,
94 (EFI_EVENT_NOTIFY
)tcp_cb
, &token
.CompletionToken
);
95 if (status
!= EFI_SUCCESS
)
98 status
= uefi_call_wrapper(tcp
->Connect
, 2, tcp
, &token
);
99 if (status
!= EFI_SUCCESS
) {
100 Print(L
"Failed to connect: %d\n", status
);
104 while (cb_status
== -1)
105 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
114 uefi_call_wrapper(BS
->CloseEvent
, 1, token
.CompletionToken
.Event
);
118 bool core_tcp_is_connected(struct pxe_pvt_inode
*socket
)
120 if (socket
->net
.efi
.binding
)
126 int core_tcp_write(struct pxe_pvt_inode
*socket
, const void *data
,
127 size_t len
, bool copy
)
129 EFI_TCP4_TRANSMIT_DATA txdata
;
130 EFI_TCP4_FRAGMENT_DATA
*frag
;
131 struct efi_binding
*b
= socket
->net
.efi
.binding
;
132 EFI_TCP4_IO_TOKEN iotoken
;
134 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
139 memset(&iotoken
, 0, sizeof(iotoken
));
140 memset(&txdata
, 0, sizeof(txdata
));
142 txdata
.DataLength
= len
;
143 txdata
.FragmentCount
= 1;
145 frag
= &txdata
.FragmentTable
[0];
146 frag
->FragmentLength
= len
;
147 frag
->FragmentBuffer
= (void *)data
;
149 iotoken
.Packet
.TxData
= &txdata
;
151 status
= efi_setup_event(&iotoken
.CompletionToken
.Event
,
152 (EFI_EVENT_NOTIFY
)tcp_cb
, &iotoken
.CompletionToken
);
153 if (status
!= EFI_SUCCESS
)
156 status
= uefi_call_wrapper(tcp
->Transmit
, 2, tcp
, &iotoken
);
157 if (status
!= EFI_SUCCESS
) {
158 Print(L
"tcp transmit failed, %d\n", status
);
162 while (cb_status
== -1)
163 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
172 uefi_call_wrapper(BS
->CloseEvent
, 1, iotoken
.CompletionToken
.Event
);
176 void core_tcp_close_file(struct inode
*inode
)
178 struct pxe_pvt_inode
*socket
= PVT(inode
);
179 struct efi_binding
*b
= socket
->net
.efi
.binding
;
180 EFI_TCP4_CLOSE_TOKEN token
;
182 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
184 if (!socket
->tftp_goteof
) {
185 memset(&token
, 0, sizeof(token
));
187 status
= efi_setup_event(&token
.CompletionToken
.Event
,
188 (EFI_EVENT_NOTIFY
)null_cb
,
189 &token
.CompletionToken
);
190 if (status
!= EFI_SUCCESS
)
193 status
= uefi_call_wrapper(tcp
->Close
, 2, tcp
, &token
);
194 if (status
!= EFI_SUCCESS
)
195 Print(L
"tcp close failed: %d\n", status
);
198 efi_destroy_binding(b
, &Tcp4ServiceBindingProtocol
);
199 socket
->net
.efi
.binding
= NULL
;
202 static char databuf
[8192];
204 void core_tcp_fill_buffer(struct inode
*inode
)
206 struct pxe_pvt_inode
*socket
= PVT(inode
);
207 struct efi_binding
*b
= socket
->net
.efi
.binding
;
208 EFI_TCP4_IO_TOKEN iotoken
;
209 EFI_TCP4_RECEIVE_DATA rxdata
;
210 EFI_TCP4_FRAGMENT_DATA
*frag
;
212 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
216 memset(&iotoken
, 0, sizeof(iotoken
));
217 memset(&rxdata
, 0, sizeof(rxdata
));
219 status
= efi_setup_event(&iotoken
.CompletionToken
.Event
,
220 (EFI_EVENT_NOTIFY
)tcp_cb
, &iotoken
.CompletionToken
);
221 if (status
!= EFI_SUCCESS
)
224 iotoken
.Packet
.RxData
= &rxdata
;
225 rxdata
.FragmentCount
= 1;
226 rxdata
.DataLength
= sizeof(databuf
);
227 frag
= &rxdata
.FragmentTable
[0];
228 frag
->FragmentBuffer
= databuf
;
229 frag
->FragmentLength
= sizeof(databuf
);
231 status
= uefi_call_wrapper(tcp
->Receive
, 2, tcp
, &iotoken
);
232 if (status
== EFI_CONNECTION_FIN
) {
233 socket
->tftp_goteof
= 1;
234 if (inode
->size
== (uint64_t)-1)
235 inode
->size
= socket
->tftp_filepos
;
236 socket
->ops
->close(inode
);
240 while (cb_status
== -1)
241 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
246 len
= frag
->FragmentLength
;
247 memcpy(databuf
, frag
->FragmentBuffer
, len
);
250 socket
->tftp_dataptr
= data
;
251 socket
->tftp_filepos
+= len
;
252 socket
->tftp_bytesleft
= len
;
255 uefi_call_wrapper(BS
->CloseEvent
, 1, iotoken
.CompletionToken
.Event
);