Adding upstream version 6.02~pre8+dfsg.
[syslinux-debian/hramrach.git] / efi / tcp.c
blobf041b677c35ea7cd71305a2a4298c1d4002b7377
1 #include "efi.h"
2 #include "net.h"
3 #include "fs/pxe/pxe.h"
5 extern EFI_GUID Tcp4ServiceBindingProtocol;
6 extern EFI_GUID Tcp4Protocol;
9 extern struct efi_binding *efi_create_binding(EFI_GUID *, EFI_GUID *);
10 extern void efi_destroy_binding(struct efi_binding *, EFI_GUID *);
11 int core_tcp_open(struct pxe_pvt_inode *socket)
13 struct efi_binding *b;
15 b = efi_create_binding(&Tcp4ServiceBindingProtocol, &Tcp4Protocol);
16 if (!b)
17 return -1;
19 socket->net.efi.binding = b;
21 return 0;
24 static EFIAPI void null_cb(EFI_EVENT ev, void *context)
26 EFI_TCP4_COMPLETION_TOKEN *token = context;
28 (void)ev;
30 uefi_call_wrapper(BS->CloseEvent, 1, token->Event);
33 static int volatile cb_status = -1;
34 static EFIAPI void tcp_cb(EFI_EVENT ev, void *context)
36 EFI_TCP4_COMPLETION_TOKEN *token = context;
38 (void)ev;
40 if (token->Status == EFI_SUCCESS)
41 cb_status = 0;
42 else
43 cb_status = 1;
46 int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port)
48 EFI_TCP4_CONNECTION_TOKEN token;
49 EFI_TCP4_ACCESS_POINT *ap;
50 EFI_TCP4_CONFIG_DATA tdata;
51 struct efi_binding *b = socket->net.efi.binding;
52 EFI_STATUS status;
53 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
54 int rv = -1;
56 memset(&tdata, 0, sizeof(tdata));
58 ap = &tdata.AccessPoint;
59 memcpy(&ap->StationAddress, &IPInfo.myip, sizeof(IPInfo.myip));
60 memcpy(&ap->SubnetMask, &IPInfo.netmask, sizeof(IPInfo.netmask));
61 memcpy(&ap->RemoteAddress, &ip, sizeof(ip));
62 ap->RemotePort = port;
63 ap->ActiveFlag = TRUE; /* Initiate active open */
65 tdata.TimeToLive = 64;
67 status = uefi_call_wrapper(tcp->Configure, 2, tcp, &tdata);
68 if (status != EFI_SUCCESS)
69 return -1;
71 status = efi_setup_event(&token.CompletionToken.Event,
72 (EFI_EVENT_NOTIFY)tcp_cb, &token.CompletionToken);
73 if (status != EFI_SUCCESS)
74 return -1;
76 status = uefi_call_wrapper(tcp->Connect, 2, tcp, &token);
77 if (status != EFI_SUCCESS) {
78 Print(L"Failed to connect: %d\n", status);
79 goto out;
82 while (cb_status == -1)
83 uefi_call_wrapper(tcp->Poll, 1, tcp);
85 if (cb_status == 0)
86 rv = 0;
88 /* Reset */
89 cb_status = -1;
91 out:
92 uefi_call_wrapper(BS->CloseEvent, 1, token.CompletionToken.Event);
93 return rv;
96 bool core_tcp_is_connected(struct pxe_pvt_inode *socket)
98 if (socket->net.efi.binding)
99 return true;
101 return false;
104 int core_tcp_write(struct pxe_pvt_inode *socket, const void *data,
105 size_t len, bool copy)
107 EFI_TCP4_TRANSMIT_DATA txdata;
108 EFI_TCP4_FRAGMENT_DATA *frag;
109 struct efi_binding *b = socket->net.efi.binding;
110 EFI_TCP4_IO_TOKEN iotoken;
111 EFI_STATUS status;
112 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
113 int rv = -1;
115 (void)copy;
117 memset(&iotoken, 0, sizeof(iotoken));
118 memset(&txdata, 0, sizeof(txdata));
120 txdata.DataLength = len;
121 txdata.FragmentCount = 1;
123 frag = &txdata.FragmentTable[0];
124 frag->FragmentLength = len;
125 frag->FragmentBuffer = (void *)data;
127 iotoken.Packet.TxData = &txdata;
129 status = efi_setup_event(&iotoken.CompletionToken.Event,
130 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
131 if (status != EFI_SUCCESS)
132 return -1;
134 status = uefi_call_wrapper(tcp->Transmit, 2, tcp, &iotoken);
135 if (status != EFI_SUCCESS) {
136 Print(L"tcp transmit failed, %d\n", status);
137 goto out;
140 while (cb_status == -1)
141 uefi_call_wrapper(tcp->Poll, 1, tcp);
143 if (cb_status == 0)
144 rv = 0;
146 /* Reset */
147 cb_status = -1;
149 out:
150 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);
151 return rv;
154 void core_tcp_close_file(struct inode *inode)
156 struct pxe_pvt_inode *socket = PVT(inode);
157 struct efi_binding *b = socket->net.efi.binding;
158 EFI_TCP4_CLOSE_TOKEN token;
159 EFI_STATUS status;
160 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
162 if (!socket->tftp_goteof) {
163 memset(&token, 0, sizeof(token));
165 status = efi_setup_event(&token.CompletionToken.Event,
166 (EFI_EVENT_NOTIFY)null_cb,
167 &token.CompletionToken);
168 if (status != EFI_SUCCESS)
169 return;
171 status = uefi_call_wrapper(tcp->Close, 2, tcp, &token);
172 if (status != EFI_SUCCESS)
173 Print(L"tcp close failed: %d\n", status);
176 efi_destroy_binding(b, &Tcp4ServiceBindingProtocol);
177 socket->net.efi.binding = NULL;
180 static char databuf[8192];
182 void core_tcp_fill_buffer(struct inode *inode)
184 struct pxe_pvt_inode *socket = PVT(inode);
185 struct efi_binding *b = socket->net.efi.binding;
186 EFI_TCP4_IO_TOKEN iotoken;
187 EFI_TCP4_RECEIVE_DATA rxdata;
188 EFI_TCP4_FRAGMENT_DATA *frag;
189 EFI_STATUS status;
190 EFI_TCP4 *tcp = (EFI_TCP4 *)b->this;
191 void *data;
192 size_t len;
194 memset(&iotoken, 0, sizeof(iotoken));
195 memset(&rxdata, 0, sizeof(rxdata));
197 status = efi_setup_event(&iotoken.CompletionToken.Event,
198 (EFI_EVENT_NOTIFY)tcp_cb, &iotoken.CompletionToken);
199 if (status != EFI_SUCCESS)
200 return;
202 iotoken.Packet.RxData = &rxdata;
203 rxdata.FragmentCount = 1;
204 rxdata.DataLength = sizeof(databuf);
205 frag = &rxdata.FragmentTable[0];
206 frag->FragmentBuffer = databuf;
207 frag->FragmentLength = sizeof(databuf);
209 status = uefi_call_wrapper(tcp->Receive, 2, tcp, &iotoken);
210 if (status == EFI_CONNECTION_FIN) {
211 socket->tftp_goteof = 1;
212 if (inode->size == (uint64_t)-1)
213 inode->size = socket->tftp_filepos;
214 socket->ops->close(inode);
215 goto out;
218 while (cb_status == -1)
219 uefi_call_wrapper(tcp->Poll, 1, tcp);
221 /* Reset */
222 cb_status = -1;
224 len = frag->FragmentLength;
225 memcpy(databuf, frag->FragmentBuffer, len);
226 data = databuf;
228 socket->tftp_dataptr = data;
229 socket->tftp_filepos += len;
230 socket->tftp_bytesleft = len;
232 out:
233 uefi_call_wrapper(BS->CloseEvent, 1, iotoken.CompletionToken.Event);