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
)
79 if ( (cur
- last
) >= EFI_NOMAP_PRINT_DELAY
) {
81 Print(L
"core_tcp_connect: stalling on configure with no mapping\n");
82 } else if ( (cur
- start
) > EFI_NOMAP_PRINT_DELAY
* EFI_NOMAP_PRINT_COUNT
) {
83 Print(L
"core_tcp_connect: aborting on no mapping\n");
88 if (status
!= EFI_SUCCESS
)
91 status
= efi_setup_event(&token
.CompletionToken
.Event
,
92 (EFI_EVENT_NOTIFY
)tcp_cb
, &token
.CompletionToken
);
93 if (status
!= EFI_SUCCESS
)
96 status
= uefi_call_wrapper(tcp
->Connect
, 2, tcp
, &token
);
97 if (status
!= EFI_SUCCESS
) {
98 Print(L
"Failed to connect: %d\n", status
);
102 while (cb_status
== -1)
103 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
112 uefi_call_wrapper(BS
->CloseEvent
, 1, token
.CompletionToken
.Event
);
116 bool core_tcp_is_connected(struct pxe_pvt_inode
*socket
)
118 if (socket
->net
.efi
.binding
)
124 int core_tcp_write(struct pxe_pvt_inode
*socket
, const void *data
,
125 size_t len
, bool copy
)
127 EFI_TCP4_TRANSMIT_DATA txdata
;
128 EFI_TCP4_FRAGMENT_DATA
*frag
;
129 struct efi_binding
*b
= socket
->net
.efi
.binding
;
130 EFI_TCP4_IO_TOKEN iotoken
;
132 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
137 memset(&iotoken
, 0, sizeof(iotoken
));
138 memset(&txdata
, 0, sizeof(txdata
));
140 txdata
.DataLength
= len
;
141 txdata
.FragmentCount
= 1;
143 frag
= &txdata
.FragmentTable
[0];
144 frag
->FragmentLength
= len
;
145 frag
->FragmentBuffer
= (void *)data
;
147 iotoken
.Packet
.TxData
= &txdata
;
149 status
= efi_setup_event(&iotoken
.CompletionToken
.Event
,
150 (EFI_EVENT_NOTIFY
)tcp_cb
, &iotoken
.CompletionToken
);
151 if (status
!= EFI_SUCCESS
)
154 status
= uefi_call_wrapper(tcp
->Transmit
, 2, tcp
, &iotoken
);
155 if (status
!= EFI_SUCCESS
) {
156 Print(L
"tcp transmit failed, %d\n", status
);
160 while (cb_status
== -1)
161 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
170 uefi_call_wrapper(BS
->CloseEvent
, 1, iotoken
.CompletionToken
.Event
);
174 void core_tcp_close_file(struct inode
*inode
)
176 struct pxe_pvt_inode
*socket
= PVT(inode
);
177 struct efi_binding
*b
= socket
->net
.efi
.binding
;
178 EFI_TCP4_CLOSE_TOKEN token
;
180 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
182 if (!socket
->tftp_goteof
) {
183 memset(&token
, 0, sizeof(token
));
185 status
= efi_setup_event(&token
.CompletionToken
.Event
,
186 (EFI_EVENT_NOTIFY
)null_cb
,
187 &token
.CompletionToken
);
188 if (status
!= EFI_SUCCESS
)
191 status
= uefi_call_wrapper(tcp
->Close
, 2, tcp
, &token
);
192 if (status
!= EFI_SUCCESS
)
193 Print(L
"tcp close failed: %d\n", status
);
196 efi_destroy_binding(b
, &Tcp4ServiceBindingProtocol
);
197 socket
->net
.efi
.binding
= NULL
;
200 static char databuf
[8192];
202 void core_tcp_fill_buffer(struct inode
*inode
)
204 struct pxe_pvt_inode
*socket
= PVT(inode
);
205 struct efi_binding
*b
= socket
->net
.efi
.binding
;
206 EFI_TCP4_IO_TOKEN iotoken
;
207 EFI_TCP4_RECEIVE_DATA rxdata
;
208 EFI_TCP4_FRAGMENT_DATA
*frag
;
210 EFI_TCP4
*tcp
= (EFI_TCP4
*)b
->this;
214 memset(&iotoken
, 0, sizeof(iotoken
));
215 memset(&rxdata
, 0, sizeof(rxdata
));
217 status
= efi_setup_event(&iotoken
.CompletionToken
.Event
,
218 (EFI_EVENT_NOTIFY
)tcp_cb
, &iotoken
.CompletionToken
);
219 if (status
!= EFI_SUCCESS
)
222 iotoken
.Packet
.RxData
= &rxdata
;
223 rxdata
.FragmentCount
= 1;
224 rxdata
.DataLength
= sizeof(databuf
);
225 frag
= &rxdata
.FragmentTable
[0];
226 frag
->FragmentBuffer
= databuf
;
227 frag
->FragmentLength
= sizeof(databuf
);
229 status
= uefi_call_wrapper(tcp
->Receive
, 2, tcp
, &iotoken
);
230 if (status
== EFI_CONNECTION_FIN
) {
231 socket
->tftp_goteof
= 1;
232 if (inode
->size
== (uint64_t)-1)
233 inode
->size
= socket
->tftp_filepos
;
234 socket
->ops
->close(inode
);
238 while (cb_status
== -1)
239 uefi_call_wrapper(tcp
->Poll
, 1, tcp
);
244 len
= frag
->FragmentLength
;
245 memcpy(databuf
, frag
->FragmentBuffer
, len
);
248 socket
->tftp_dataptr
= data
;
249 socket
->tftp_filepos
+= len
;
250 socket
->tftp_bytesleft
= len
;
253 uefi_call_wrapper(BS
->CloseEvent
, 1, iotoken
.CompletionToken
.Event
);