1 #include <syslinux/pxe_api.h>
2 #include <lwip/api.h>
3 #include <lwip/tcpip.h>
4 #include <lwip/dns.h>
5 #include <core.h>
6 #include <net.h>
7 #include "pxe.h"
8
9 #include <dprintf.h>
10
11 const struct url_scheme url_schemes[] = {
12 { "tftp", tftp_open, 0 },
13 { "http", http_open, O_DIRECTORY },
14 { "ftp", ftp_open, O_DIRECTORY },
15 { NULL, NULL, 0 },
16 };
17
18 /**
19 * Open a socket
20 *
21 * @param:socket, the socket to open
22 *
23 * @out: error code, 0 on success, -1 on failure
24 */
core_udp_open(struct pxe_pvt_inode * socket)25 int core_udp_open(struct pxe_pvt_inode *socket)
26 {
27 struct net_private_lwip *priv = &socket->net.lwip;
28 int err;
29
30 priv->conn = netconn_new(NETCONN_UDP);
31 if (!priv->conn)
32 return -1;
33
34 priv->conn->recv_timeout = 15; /* A 15 ms recv timeout... */
35 err = netconn_bind(priv->conn, NULL, 0);
36 if (err) {
37 ddprintf("netconn_bind error %d\n", err);
38 return -1;
39 }
40
41 return 0;
42 }
43
44 /**
45 * Close a socket
46 *
47 * @param:socket, the socket to open
48 */
core_udp_close(struct pxe_pvt_inode * socket)49 void core_udp_close(struct pxe_pvt_inode *socket)
50 {
51 struct net_private_lwip *priv = &socket->net.lwip;
52
53 if (priv->conn) {
54 netconn_delete(priv->conn);
55 priv->conn = NULL;
56 }
57 }
58
59 /**
60 * Establish a connection on an open socket
61 *
62 * @param:socket, the open socket
63 * @param:ip, the ip address
64 * @param:port, the port number, host-byte order
65 */
core_udp_connect(struct pxe_pvt_inode * socket,uint32_t ip,uint16_t port)66 void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip,
67 uint16_t port)
68 {
69 struct net_private_lwip *priv = &socket->net.lwip;
70 struct ip_addr addr;
71
72 dprintf("net_core_connect: %08X %04X\n", ntohl(ip), port);
73 addr.addr = ip;
74 netconn_connect(priv->conn, &addr, port);
75 }
76
77 /**
78 * Tear down a connection on an open socket
79 *
80 * @param:socket, the open socket
81 */
core_udp_disconnect(struct pxe_pvt_inode * socket)82 void core_udp_disconnect(struct pxe_pvt_inode *socket)
83 {
84 struct net_private_lwip *priv = &socket->net.lwip;
85 netconn_disconnect(priv->conn);
86 }
87
88 /**
89 * Read data from the network stack
90 *
91 * @param:socket, the open socket
92 * @param:buf, location of buffer to store data
93 * @param:buf_len, size of buffer
94
95 * @out: src_ip, ip address of the data source
96 * @out: src_port, port number of the data source, host-byte order
97 */
core_udp_recv(struct pxe_pvt_inode * socket,void * buf,uint16_t * buf_len,uint32_t * src_ip,uint16_t * src_port)98 int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len,
99 uint32_t *src_ip, uint16_t *src_port)
100 {
101 struct net_private_lwip *priv = &socket->net.lwip;
102 struct netbuf *nbuf;
103 u16_t nbuf_len;
104 int err;
105
106 err = netconn_recv(priv->conn, &nbuf);
107 if (err)
108 return err;
109
110 if (!nbuf)
111 return -1;
112
113 *src_ip = netbuf_fromaddr(nbuf)->addr;
114 *src_port = netbuf_fromport(nbuf);
115
116 netbuf_first(nbuf); /* XXX needed? */
117 nbuf_len = netbuf_len(nbuf);
118 if (nbuf_len <= *buf_len)
119 netbuf_copy(nbuf, buf, nbuf_len);
120 else
121 nbuf_len = 0; /* impossible mtu < PKTBUF_SIZE */
122 netbuf_delete(nbuf);
123
124 *buf_len = nbuf_len;
125 return 0;
126 }
127
128 /**
129 * Send a UDP packet.
130 *
131 * @param:socket, the open socket
132 * @param:data, data buffer to send
133 * @param:len, size of data bufer
134 */
core_udp_send(struct pxe_pvt_inode * socket,const void * data,size_t len)135 void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len)
136 {
137 struct netconn *conn = socket->net.lwip.conn;
138 struct netbuf *nbuf;
139 void *pbuf;
140 int err;
141
142 nbuf = netbuf_new();
143 if (!nbuf) {
144 ddprintf("netbuf allocation error\n");
145 return;
146 }
147
148 pbuf = netbuf_alloc(nbuf, len);
149 if (!pbuf) {
150 ddprintf("pbuf allocation error\n");
151 goto out;
152 }
153
154 memcpy(pbuf, data, len);
155
156 err = netconn_send(conn, nbuf);
157 if (err) {
158 ddprintf("netconn_send error %d\n", err);
159 goto out;
160 }
161
162 out:
163 netbuf_delete(nbuf);
164 }
165
166 /**
167 * Send a UDP packet to a destination
168 *
169 * @param:socket, the open socket
170 * @param:data, data buffer to send
171 * @param:len, size of data bufer
172 * @param:ip, the ip address
173 * @param:port, the port number, host-byte order
174 */
core_udp_sendto(struct pxe_pvt_inode * socket,const void * data,size_t len,uint32_t ip,uint16_t port)175 void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data,
176 size_t len, uint32_t ip, uint16_t port)
177 {
178 struct netconn *conn = socket->net.lwip.conn;
179 struct ip_addr addr;
180 struct netbuf *nbuf;
181 void *pbuf;
182 int err;
183
184 nbuf = netbuf_new();
185 if (!nbuf) {
186 ddprintf("netbuf allocation error\n");
187 return;
188 }
189
190 pbuf = netbuf_alloc(nbuf, len);
191 if (!pbuf) {
192 ddprintf("pbuf allocation error\n");
193 goto out;
194 }
195
196 memcpy(pbuf, data, len);
197
198 dprintf("core_udp_sendto: %08X %04X\n", ntohl(ip), port);
199 addr.addr = ip;
200
201 err = netconn_sendto(conn, nbuf, &addr, port);
202 if (err) {
203 ddprintf("netconn_sendto error %d\n", err);
204 goto out;
205 }
206
207 out:
208 netbuf_delete(nbuf);
209 }
210
211 /**
212 * Network stack-specific initialization
213 */
net_core_init(void)214 void net_core_init(void)
215 {
216 int err;
217 int i;
218
219 http_bake_cookies();
220
221 /* Initialize lwip */
222 tcpip_init(NULL, NULL);
223
224 /* Start up the undi driver for lwip */
225 err = undiif_start(IPInfo.myip, IPInfo.netmask, IPInfo.gateway);
226 if (err) {
227 ddprintf("undiif driver failed to start: %d\n", err);
228 kaboom();
229 }
230
231 for (i = 0; i < DNS_MAX_SERVERS; i++) {
232 /* Transfer the DNS information to lwip */
233 dns_setserver(i, (struct ip_addr *)&dns_server[i]);
234 }
235 }
236
probe_undi(void)237 void probe_undi(void)
238 {
239 /* Probe UNDI information */
240 pxe_call(PXENV_UNDI_GET_INFORMATION, &pxe_undi_info);
241 pxe_call(PXENV_UNDI_GET_IFACE_INFO, &pxe_undi_iface);
242
243 ddprintf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n",
244 pxe_undi_info.BaseIo, pxe_undi_info.IntNumber,
245 pxe_undi_info.MaxTranUnit, pxe_undi_info.HwType,
246 pxe_undi_iface.IfaceType, pxe_undi_iface.ServiceFlags);
247 }
248
core_tcp_open(struct pxe_pvt_inode * socket)249 int core_tcp_open(struct pxe_pvt_inode *socket)
250 {
251 socket->net.lwip.conn = netconn_new(NETCONN_TCP);
252 if (!socket->net.lwip.conn)
253 return -1;
254
255 return 0;
256 }
core_tcp_connect(struct pxe_pvt_inode * socket,uint32_t ip,uint16_t port)257 int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port)
258 {
259 struct ip_addr addr;
260 err_t err;
261
262 addr.addr = ip;
263 err = netconn_connect(socket->net.lwip.conn, &addr, port);
264 if (err) {
265 printf("netconn_connect error %d\n", err);
266 return -1;
267 }
268
269 return 0;
270 }
271
core_tcp_write(struct pxe_pvt_inode * socket,const void * data,size_t len,bool copy)272 int core_tcp_write(struct pxe_pvt_inode *socket, const void *data, size_t len,
273 bool copy)
274 {
275 err_t err;
276 u8_t flags = copy ? NETCONN_COPY : NETCONN_NOCOPY;
277
278 err = netconn_write(socket->net.lwip.conn, data, len, flags);
279 if (err) {
280 printf("netconn_write failed: %d\n", err);
281 return -1;
282 }
283
284 return 0;
285 }
286
core_tcp_close_file(struct inode * inode)287 void core_tcp_close_file(struct inode *inode)
288 {
289 struct pxe_pvt_inode *socket = PVT(inode);
290
291 if (socket->net.lwip.conn) {
292 netconn_delete(socket->net.lwip.conn);
293 socket->net.lwip.conn = NULL;
294 }
295 if (socket->net.lwip.buf) {
296 netbuf_delete(socket->net.lwip.buf);
297 socket->net.lwip.buf = NULL;
298 }
299 }
300
core_tcp_is_connected(struct pxe_pvt_inode * socket)301 bool core_tcp_is_connected(struct pxe_pvt_inode *socket)
302 {
303 if (socket->net.lwip.conn)
304 return true;
305
306 return false;
307 }
308
core_tcp_fill_buffer(struct inode * inode)309 void core_tcp_fill_buffer(struct inode *inode)
310 {
311 struct pxe_pvt_inode *socket = PVT(inode);
312 void *data;
313 u16_t len;
314 err_t err;
315
316 /* Clean up or advance an inuse netbuf */
317 if (socket->net.lwip.buf) {
318 if (netbuf_next(socket->net.lwip.buf) < 0) {
319 netbuf_delete(socket->net.lwip.buf);
320 socket->net.lwip.buf = NULL;
321 }
322 }
323 /* If needed get a new netbuf */
324 if (!socket->net.lwip.buf) {
325 err = netconn_recv(socket->net.lwip.conn, &(socket->net.lwip.buf));
326 if (!socket->net.lwip.buf || err) {
327 socket->tftp_goteof = 1;
328 if (inode->size == -1)
329 inode->size = socket->tftp_filepos;
330 socket->ops->close(inode);
331 return;
332 }
333 }
334 /* Report the current fragment of the netbuf */
335 err = netbuf_data(socket->net.lwip.buf, &data, &len);
336 if (err) {
337 printf("netbuf_data err: %d\n", err);
338 kaboom();
339 }
340 socket->tftp_dataptr = data;
341 socket->tftp_filepos += len;
342 socket->tftp_bytesleft = len;
343 return;
344 }
345