/[gxemul]/upstream/0.4.4/src/net/net_ip.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.4/src/net/net_ip.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 35 - (show annotations)
Mon Oct 8 16:21:26 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 44463 byte(s)
0.4.4
1 /*
2 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: net_ip.c,v 1.5 2006/12/30 13:31:02 debug Exp $
29 *
30 * Internet Protocol related networking stuff.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <errno.h>
41 #include <fcntl.h>
42
43 #include "misc.h"
44 #include "net.h"
45
46
47 /* #define debug fatal */
48
49
50 /*
51 * net_ip_checksum():
52 *
53 * Fill in an IP header checksum. (This works for ICMP too.)
54 * chksumoffset should be 10 for IP headers, and len = 20.
55 * For ICMP packets, chksumoffset = 2 and len = length of the ICMP packet.
56 */
57 void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len)
58 {
59 int i;
60 uint32_t sum = 0;
61
62 for (i=0; i<len; i+=2)
63 if (i != chksumoffset) {
64 uint16_t w = (ip_header[i] << 8) + ip_header[i+1];
65 sum += w;
66 while (sum > 65535) {
67 int to_add = sum >> 16;
68 sum = (sum & 0xffff) + to_add;
69 }
70 }
71
72 sum ^= 0xffff;
73 ip_header[chksumoffset + 0] = sum >> 8;
74 ip_header[chksumoffset + 1] = sum & 0xff;
75 }
76
77
78 /*
79 * net_ip_tcp_checksum():
80 *
81 * Fill in a TCP header checksum. This differs slightly from the IP
82 * checksum. The checksum is calculated on a pseudo header, the actual
83 * TCP header, and the data. This is what the pseudo header looks like:
84 *
85 * uint32_t srcaddr;
86 * uint32_t dstaddr;
87 * uint16_t protocol; (= 6 for tcp)
88 * uint16_t tcp_len;
89 *
90 * tcp_len is length of header PLUS data. The psedo header is created
91 * internally here, and does not need to be supplied by the caller.
92 */
93 void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset,
94 int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr,
95 int udpflag)
96 {
97 int i, pad = 0;
98 unsigned char pseudoh[12];
99 uint32_t sum = 0;
100
101 memcpy(pseudoh + 0, srcaddr, 4);
102 memcpy(pseudoh + 4, dstaddr, 4);
103 pseudoh[8] = 0x00;
104 pseudoh[9] = udpflag? 17 : 6;
105 pseudoh[10] = tcp_len >> 8;
106 pseudoh[11] = tcp_len & 255;
107
108 for (i=0; i<12; i+=2) {
109 uint16_t w = (pseudoh[i] << 8) + pseudoh[i+1];
110 sum += w;
111 while (sum > 65535) {
112 int to_add = sum >> 16;
113 sum = (sum & 0xffff) + to_add;
114 }
115 }
116
117 if (tcp_len & 1) {
118 tcp_len ++;
119 pad = 1;
120 }
121
122 for (i=0; i<tcp_len; i+=2)
123 if (i != chksumoffset) {
124 uint16_t w;
125 if (!pad || i < tcp_len-2)
126 w = (tcp_header[i] << 8) + tcp_header[i+1];
127 else
128 w = (tcp_header[i] << 8) + 0x00;
129 sum += w;
130 while (sum > 65535) {
131 int to_add = sum >> 16;
132 sum = (sum & 0xffff) + to_add;
133 }
134 }
135
136 sum ^= 0xffff;
137 tcp_header[chksumoffset + 0] = sum >> 8;
138 tcp_header[chksumoffset + 1] = sum & 0xff;
139 }
140
141
142 /*
143 * net_ip_icmp():
144 *
145 * Handle an ICMP packet.
146 *
147 * The IP header (at offset 14) could look something like
148 *
149 * ver=45 tos=00 len=0054 id=001a ofs=0000 ttl=ff p=01 sum=a87e
150 * src=0a000005 dst=03050607
151 *
152 * and the ICMP specific data (beginning at offset 34):
153 *
154 * type=08 code=00 chksum=b8bf
155 * 000c0008d5cee94089190c0008090a0b
156 * 0c0d0e0f101112131415161718191a1b
157 * 1c1d1e1f202122232425262728292a2b
158 * 2c2d2e2f3031323334353637
159 */
160 static void net_ip_icmp(struct net *net, void *extra,
161 unsigned char *packet, int len)
162 {
163 int type;
164 struct ethernet_packet_link *lp;
165
166 type = packet[34];
167
168 switch (type) {
169 case 8: /* ECHO request */
170 debug("[ ICMP echo ]\n");
171 lp = net_allocate_ethernet_packet_link(net, extra, len);
172
173 /* Copy the old packet first: */
174 memcpy(lp->data + 12, packet + 12, len - 12);
175
176 /* Switch to and from ethernet addresses: */
177 memcpy(lp->data + 0, packet + 6, 6);
178 memcpy(lp->data + 6, packet + 0, 6);
179
180 /* Switch to and from IP addresses: */
181 memcpy(lp->data + 26, packet + 30, 4);
182 memcpy(lp->data + 30, packet + 26, 4);
183
184 /* Change from echo REQUEST to echo REPLY: */
185 lp->data[34] = 0x00;
186
187 /* Decrease the TTL to a low value: */
188 lp->data[22] = 2;
189
190 /* Recalculate ICMP checksum: */
191 net_ip_checksum(lp->data + 34, 2, len - 34);
192
193 /* Recalculate IP header checksum: */
194 net_ip_checksum(lp->data + 14, 10, 20);
195
196 break;
197 default:
198 fatal("[ net: ICMP type %i not yet implemented ]\n", type);
199 }
200 }
201
202
203 /*
204 * tcp_closeconnection():
205 *
206 * Helper function which closes down a TCP connection completely.
207 */
208 static void tcp_closeconnection(struct net *net, int con_id)
209 {
210 close(net->tcp_connections[con_id].socket);
211 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED;
212 net->tcp_connections[con_id].in_use = 0;
213 net->tcp_connections[con_id].incoming_buf_len = 0;
214 }
215
216
217 /*
218 * net_ip_tcp_connectionreply():
219 *
220 * When changing from state _TRYINGTOCONNECT to _CONNECTED, then this
221 * function should be called with connecting set to 1.
222 *
223 * To send a generic ack reply, set connecting to 0.
224 *
225 * To send data (PSH), set data to non-NULL and datalen to the length.
226 *
227 * This creates an ethernet packet for the guest OS with an ACK to the
228 * initial SYN packet.
229 */
230 void net_ip_tcp_connectionreply(struct net *net, void *extra,
231 int con_id, int connecting, unsigned char *data, int datalen, int rst)
232 {
233 struct ethernet_packet_link *lp;
234 int tcp_length, ip_len, option_len = 20;
235
236 if (connecting)
237 net->tcp_connections[con_id].outside_acknr =
238 net->tcp_connections[con_id].inside_seqnr + 1;
239
240 net->tcp_connections[con_id].tcp_id ++;
241 tcp_length = 20 + option_len + datalen;
242 ip_len = 20 + tcp_length;
243 lp = net_allocate_ethernet_packet_link(net, extra, 14 + ip_len);
244
245 /* Ethernet header: */
246 memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6);
247 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
248 lp->data[12] = 0x08; /* IP = 0x0800 */
249 lp->data[13] = 0x00;
250
251 /* IP header: */
252 lp->data[14] = 0x45; /* ver */
253 lp->data[15] = 0x10; /* tos */
254 lp->data[16] = ip_len >> 8;
255 lp->data[17] = ip_len & 0xff;
256 lp->data[18] = net->tcp_connections[con_id].tcp_id >> 8;
257 lp->data[19] = net->tcp_connections[con_id].tcp_id & 0xff;
258 lp->data[20] = 0x40; /* don't fragment */
259 lp->data[21] = 0x00;
260 lp->data[22] = 0x40; /* ttl */
261 lp->data[23] = 6; /* p = TCP */
262 memcpy(lp->data + 26, net->tcp_connections[con_id].
263 outside_ip_address, 4);
264 memcpy(lp->data + 30, net->tcp_connections[con_id].
265 inside_ip_address, 4);
266 net_ip_checksum(lp->data + 14, 10, 20);
267
268 /* TCP header and options at offset 34: */
269 lp->data[34] = net->tcp_connections[con_id].outside_tcp_port >> 8;
270 lp->data[35] = net->tcp_connections[con_id].outside_tcp_port & 0xff;
271 lp->data[36] = net->tcp_connections[con_id].inside_tcp_port >> 8;
272 lp->data[37] = net->tcp_connections[con_id].inside_tcp_port & 0xff;
273 lp->data[38] = (net->tcp_connections[con_id].
274 outside_seqnr >> 24) & 0xff;
275 lp->data[39] = (net->tcp_connections[con_id].
276 outside_seqnr >> 16) & 0xff;
277 lp->data[40] = (net->tcp_connections[con_id].
278 outside_seqnr >> 8) & 0xff;
279 lp->data[41] = net->tcp_connections[con_id].
280 outside_seqnr & 0xff;
281 lp->data[42] = (net->tcp_connections[con_id].
282 outside_acknr >> 24) & 0xff;
283 lp->data[43] = (net->tcp_connections[con_id].
284 outside_acknr >> 16) & 0xff;
285 lp->data[44] = (net->tcp_connections[con_id].
286 outside_acknr >> 8) & 0xff;
287 lp->data[45] = net->tcp_connections[con_id].outside_acknr & 0xff;
288
289 /* Control */
290 lp->data[46] = (option_len + 20) / 4 * 0x10;
291 lp->data[47] = 0x10; /* ACK */
292 if (connecting)
293 lp->data[47] |= 0x02; /* SYN */
294 if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED)
295 lp->data[47] |= 0x08; /* PSH */
296 if (rst)
297 lp->data[47] |= 0x04; /* RST */
298 if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED)
299 lp->data[47] |= 0x01; /* FIN */
300
301 /* Window */
302 lp->data[48] = 0x10;
303 lp->data[49] = 0x00;
304
305 /* no urgent ptr */
306
307 /* options */
308 /* TODO: HAHA, this is ugly */
309 lp->data[54] = 0x02;
310 lp->data[55] = 0x04;
311 lp->data[56] = 0x05;
312 lp->data[57] = 0xb4;
313 lp->data[58] = 0x01;
314 lp->data[59] = 0x03;
315 lp->data[60] = 0x03;
316 lp->data[61] = 0x00;
317 lp->data[62] = 0x01;
318 lp->data[63] = 0x01;
319 lp->data[64] = 0x08;
320 lp->data[65] = 0x0a;
321 lp->data[66] = (net->timestamp >> 24) & 0xff;
322 lp->data[67] = (net->timestamp >> 16) & 0xff;
323 lp->data[68] = (net->timestamp >> 8) & 0xff;
324 lp->data[69] = net->timestamp & 0xff;
325 lp->data[70] = (net->tcp_connections[con_id].
326 inside_timestamp >> 24) & 0xff;
327 lp->data[71] = (net->tcp_connections[con_id].
328 inside_timestamp >> 16) & 0xff;
329 lp->data[72] = (net->tcp_connections[con_id].
330 inside_timestamp >> 8) & 0xff;
331 lp->data[73] = net->tcp_connections[con_id].
332 inside_timestamp & 0xff;
333
334 /* data: */
335 if (data != NULL) {
336 memcpy(lp->data + 74, data, datalen);
337 net->tcp_connections[con_id].outside_seqnr += datalen;
338 }
339
340 /* Checksum: */
341 net_ip_tcp_checksum(lp->data + 34, 16, tcp_length,
342 lp->data + 26, lp->data + 30, 0);
343
344 #if 0
345 {
346 int i;
347 fatal("[ net_ip_tcp_connectionreply(%i): ", connecting);
348 for (i=0; i<ip_len+14; i++)
349 fatal("%02x", lp->data[i]);
350 fatal(" ]\n");
351 }
352 #endif
353
354 if (connecting)
355 net->tcp_connections[con_id].outside_seqnr ++;
356 }
357
358
359 /*
360 * net_ip_tcp():
361 *
362 * Handle a TCP packet comming from the emulated OS.
363 *
364 * The IP header (at offset 14) could look something like
365 *
366 * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798
367 * src=0a000001 dst=c1abcdef
368 *
369 * TCP header, at offset 34:
370 *
371 * srcport=fffe dstport=0015 seqnr=af419a1d acknr=00000000
372 * control=a002 window=4000 checksum=fe58 urgent=0000
373 * and then "options and padding" and then data.
374 * (020405b4010303000101080a0000000000000000)
375 *
376 * See the following URLs for good descriptions of TCP:
377 *
378 * http://www.networksorcery.com/enp/protocol/tcp.htm
379 * http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm
380 */
381 static void net_ip_tcp(struct net *net, void *extra,
382 unsigned char *packet, int len)
383 {
384 int con_id, free_con_id, i, res;
385 int srcport, dstport, data_offset, window, checksum, urgptr;
386 int syn, ack, psh, rst, urg, fin;
387 uint32_t seqnr, acknr;
388 struct sockaddr_in remote_ip;
389 fd_set rfds;
390 struct timeval tv;
391 int send_ofs;
392
393 #if 0
394 fatal("[ net: TCP: ");
395 for (i=0; i<26; i++)
396 fatal("%02x", packet[i]);
397 fatal(" ");
398 #endif
399
400 srcport = (packet[34] << 8) + packet[35];
401 dstport = (packet[36] << 8) + packet[37];
402
403 seqnr = (packet[38] << 24) + (packet[39] << 16)
404 + (packet[40] << 8) + packet[41];
405 acknr = (packet[42] << 24) + (packet[43] << 16)
406 + (packet[44] << 8) + packet[45];
407
408 #if 0
409 fatal("%i.%i.%i.%i:%i -> %i.%i.%i.%i:%i, seqnr=%lli acknr=%lli ",
410 packet[26], packet[27], packet[28], packet[29], srcport,
411 packet[30], packet[31], packet[32], packet[33], dstport,
412 (long long)seqnr, (long long)acknr);
413 #endif
414
415 data_offset = (packet[46] >> 4) * 4 + 34;
416 /* data_offset is now data offset within packet :-) */
417
418 urg = packet[47] & 32;
419 ack = packet[47] & 16;
420 psh = packet[47] & 8;
421 rst = packet[47] & 4;
422 syn = packet[47] & 2;
423 fin = packet[47] & 1;
424 window = (packet[48] << 8) + packet[49];
425 checksum = (packet[50] << 8) + packet[51];
426 urgptr = (packet[52] << 8) + packet[53];
427
428 #if 0
429 fatal(urg? "URG " : "");
430 fatal(ack? "ACK " : "");
431 fatal(psh? "PSH " : "");
432 fatal(rst? "RST " : "");
433 fatal(syn? "SYN " : "");
434 fatal(fin? "FIN " : "");
435
436 fatal("window=0x%04x checksum=0x%04x urgptr=0x%04x ",
437 window, checksum, urgptr);
438
439 fatal("options=");
440 for (i=34+20; i<data_offset; i++)
441 fatal("%02x", packet[i]);
442
443 fatal(" data=");
444 for (i=data_offset; i<len; i++)
445 fatal("%02x", packet[i]);
446
447 fatal(" ]\n");
448 #endif
449
450 net_ip_tcp_checksum(packet + 34, 16, len - 34,
451 packet + 26, packet + 30, 0);
452 if (packet[50] * 256 + packet[51] != checksum) {
453 debug("TCP: dropping packet because of checksum mismatch "
454 "(0x%04x != 0x%04x)\n", packet[50] * 256 + packet[51],
455 checksum);
456
457 return;
458 }
459
460 /* Does this packet belong to a current connection? */
461 con_id = free_con_id = -1;
462 for (i=0; i<MAX_TCP_CONNECTIONS; i++) {
463 if (!net->tcp_connections[i].in_use)
464 free_con_id = i;
465 if (net->tcp_connections[i].in_use &&
466 net->tcp_connections[i].inside_tcp_port == srcport &&
467 net->tcp_connections[i].outside_tcp_port == dstport &&
468 memcmp(net->tcp_connections[i].inside_ip_address,
469 packet + 26, 4) == 0 &&
470 memcmp(net->tcp_connections[i].outside_ip_address,
471 packet + 30, 4) == 0) {
472 con_id = i;
473 break;
474 }
475 }
476
477 /*
478 * Unknown connection, and not SYN? Then drop the packet.
479 * TODO: Send back RST?
480 */
481 if (con_id < 0 && !syn) {
482 debug("[ net: TCP: dropping packet from unknown connection,"
483 " %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i %s%s%s%s%s]\n",
484 packet[26], packet[27], packet[28], packet[29], srcport,
485 packet[30], packet[31], packet[32], packet[33], dstport,
486 fin? "FIN ": "", syn? "SYN ": "", ack? "ACK ": "",
487 psh? "PSH ": "", rst? "RST ": "");
488 return;
489 }
490
491 /* Known connection, and SYN? Then ignore the packet. */
492 if (con_id >= 0 && syn) {
493 debug("[ net: TCP: ignoring redundant SYN packet from known"
494 " connection, %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i ]\n",
495 packet[26], packet[27], packet[28], packet[29], srcport,
496 packet[30], packet[31], packet[32], packet[33], dstport);
497 return;
498 }
499
500 /*
501 * A new outgoing connection?
502 */
503 if (con_id < 0 && syn) {
504 debug("[ net: TCP: new outgoing connection, %i.%i.%i.%i:%i"
505 " -> %i.%i.%i.%i:%i ]\n",
506 packet[26], packet[27], packet[28], packet[29], srcport,
507 packet[30], packet[31], packet[32], packet[33], dstport);
508
509 /* Find a free connection id to use: */
510 if (free_con_id < 0) {
511 #if 1
512 /*
513 * TODO: Reuse the oldest one currently in use, or
514 * just drop the new connection attempt? Drop for now.
515 */
516 fatal("[ TOO MANY TCP CONNECTIONS IN USE! "
517 "Increase MAX_TCP_CONNECTIONS! ]\n");
518 return;
519 #else
520 int i;
521 int64_t oldest = net->
522 tcp_connections[0].last_used_timestamp;
523 free_con_id = 0;
524
525 fatal("[ NO FREE TCP SLOTS, REUSING OLDEST ONE ]\n");
526 for (i=0; i<MAX_TCP_CONNECTIONS; i++)
527 if (net->tcp_connections[i].
528 last_used_timestamp < oldest) {
529 oldest = net->tcp_connections[i].
530 last_used_timestamp;
531 free_con_id = i;
532 }
533 tcp_closeconnection(net, free_con_id);
534 #endif
535 }
536
537 con_id = free_con_id;
538 memset(&net->tcp_connections[con_id], 0,
539 sizeof(struct tcp_connection));
540
541 memcpy(net->tcp_connections[con_id].ethernet_address,
542 packet + 6, 6);
543 memcpy(net->tcp_connections[con_id].inside_ip_address,
544 packet + 26, 4);
545 net->tcp_connections[con_id].inside_tcp_port = srcport;
546 memcpy(net->tcp_connections[con_id].outside_ip_address,
547 packet + 30, 4);
548 net->tcp_connections[con_id].outside_tcp_port = dstport;
549
550 net->tcp_connections[con_id].socket =
551 socket(AF_INET, SOCK_STREAM, 0);
552 if (net->tcp_connections[con_id].socket < 0) {
553 fatal("[ net: TCP: socket() returned %i ]\n",
554 net->tcp_connections[con_id].socket);
555 return;
556 }
557
558 debug("[ new tcp outgoing socket=%i ]\n",
559 net->tcp_connections[con_id].socket);
560
561 net->tcp_connections[con_id].in_use = 1;
562
563 /* Set the socket to non-blocking: */
564 res = fcntl(net->tcp_connections[con_id].socket, F_GETFL);
565 fcntl(net->tcp_connections[con_id].socket, F_SETFL,
566 res | O_NONBLOCK);
567
568 remote_ip.sin_family = AF_INET;
569 memcpy((unsigned char *)&remote_ip.sin_addr,
570 net->tcp_connections[con_id].outside_ip_address, 4);
571 remote_ip.sin_port = htons(
572 net->tcp_connections[con_id].outside_tcp_port);
573
574 res = connect(net->tcp_connections[con_id].socket,
575 (struct sockaddr *)&remote_ip, sizeof(remote_ip));
576
577 /* connect can return -1, and errno = EINPROGRESS
578 as we might not have connected right away. */
579
580 net->tcp_connections[con_id].state =
581 TCP_OUTSIDE_TRYINGTOCONNECT;
582
583 net->tcp_connections[con_id].outside_acknr = 0;
584 net->tcp_connections[con_id].outside_seqnr =
585 ((random() & 0xffff) << 16) + (random() & 0xffff);
586 }
587
588 if (rst) {
589 debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id);
590 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
591 tcp_closeconnection(net, con_id);
592 return;
593 }
594
595 if (ack && net->tcp_connections[con_id].state
596 == TCP_OUTSIDE_DISCONNECTED2) {
597 debug("[ 'ack': guestOS's final termination of TCP "
598 "connection %i ]\n", con_id);
599
600 /* Send an RST? (TODO, this is wrong...) */
601 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
602
603 /* ... and forget about this connection: */
604 tcp_closeconnection(net, con_id);
605 return;
606 }
607
608 if (fin && net->tcp_connections[con_id].state
609 == TCP_OUTSIDE_DISCONNECTED) {
610 debug("[ 'fin': response to outside's disconnection of "
611 "TCP connection %i ]\n", con_id);
612
613 /* Send an ACK: */
614 net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED;
615 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
616 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
617 return;
618 }
619
620 if (fin) {
621 debug("[ 'fin': guestOS disconnecting TCP connection %i ]\n",
622 con_id);
623
624 /* Send ACK: */
625 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
626 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
627
628 /* Return and send FIN: */
629 goto ret;
630 }
631
632 if (ack) {
633 debug("ACK %i bytes, inside_acknr=%u outside_seqnr=%u\n",
634 net->tcp_connections[con_id].incoming_buf_len,
635 net->tcp_connections[con_id].inside_acknr,
636 net->tcp_connections[con_id].outside_seqnr);
637 net->tcp_connections[con_id].inside_acknr = acknr;
638 if (net->tcp_connections[con_id].inside_acknr ==
639 net->tcp_connections[con_id].outside_seqnr &&
640 net->tcp_connections[con_id].incoming_buf_len != 0) {
641 debug(" all acked\n");
642 net->tcp_connections[con_id].incoming_buf_len = 0;
643 }
644 }
645
646 net->tcp_connections[con_id].inside_seqnr = seqnr;
647
648 /* TODO: This is hardcoded for a specific NetBSD packet: */
649 if (packet[34 + 30] == 0x08 && packet[34 + 31] == 0x0a)
650 net->tcp_connections[con_id].inside_timestamp =
651 (packet[34 + 32 + 0] << 24) +
652 (packet[34 + 32 + 1] << 16) +
653 (packet[34 + 32 + 2] << 8) +
654 (packet[34 + 32 + 3] << 0);
655
656
657 net->timestamp ++;
658 net->tcp_connections[con_id].last_used_timestamp = net->timestamp;
659
660
661 if (net->tcp_connections[con_id].state != TCP_OUTSIDE_CONNECTED) {
662 debug("[ not connected to outside ]\n");
663 return;
664 }
665
666
667 if (data_offset >= len)
668 return;
669
670
671 /*
672 * We are here if this is a known connection, and data is to be
673 * transmitted to the outside world.
674 */
675
676 send_ofs = data_offset;
677 send_ofs += ((int32_t)net->tcp_connections[con_id].outside_acknr
678 - (int32_t)seqnr);
679 #if 1
680 debug("[ %i bytes of tcp data to be sent, beginning at seqnr %u, ",
681 len - data_offset, seqnr);
682 debug("outside is at acknr %u ==> %i actual bytes to be sent ]\n",
683 net->tcp_connections[con_id].outside_acknr, len - send_ofs);
684 #endif
685
686 /* Drop outgoing packet if the guest OS' seqnr is not
687 the same as we have acked. (We have missed something, perhaps.) */
688 if (seqnr != net->tcp_connections[con_id].outside_acknr) {
689 debug("!! outgoing TCP packet dropped (seqnr = %u, "
690 "outside_acknr = %u)\n", seqnr,
691 net->tcp_connections[con_id].outside_acknr);
692 goto ret;
693 }
694
695 if (len - send_ofs > 0) {
696 /* Is the socket available for output? */
697 FD_ZERO(&rfds); /* write */
698 FD_SET(net->tcp_connections[con_id].socket, &rfds);
699 tv.tv_sec = tv.tv_usec = 0;
700 errno = 0;
701 res = select(net->tcp_connections[con_id].socket+1,
702 NULL, &rfds, NULL, &tv);
703 if (res < 1) {
704 net->tcp_connections[con_id].state =
705 TCP_OUTSIDE_DISCONNECTED;
706 debug("[ TCP: disconnect on select for writing ]\n");
707 goto ret;
708 }
709
710 res = write(net->tcp_connections[con_id].socket,
711 packet + send_ofs, len - send_ofs);
712
713 if (res > 0) {
714 net->tcp_connections[con_id].outside_acknr += res;
715 } else if (errno == EAGAIN) {
716 /* Just ignore this attempt. */
717 return;
718 } else {
719 debug("[ error writing %i bytes to TCP connection %i:"
720 " errno = %i ]\n", len - send_ofs, con_id, errno);
721 net->tcp_connections[con_id].state =
722 TCP_OUTSIDE_DISCONNECTED;
723 debug("[ TCP: disconnect on write() ]\n");
724 goto ret;
725 }
726 }
727
728 ret:
729 /* Send an ACK (or FIN) to the guest OS: */
730 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
731 }
732
733
734 /*
735 * net_ip_udp():
736 *
737 * Handle a UDP packet.
738 *
739 * (See http://www.networksorcery.com/enp/protocol/udp.htm.)
740 *
741 * The IP header (at offset 14) could look something like
742 *
743 * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798
744 * src=0a000001 dst=c1abcdef
745 *
746 * and the UDP data (beginning at offset 34):
747 *
748 * srcport=fffc dstport=0035 length=0028 chksum=76b6
749 * 43e20100000100000000000003667470066e6574627364036f726700001c0001
750 */
751 static void net_ip_udp(struct net *net, void *extra,
752 unsigned char *packet, int len)
753 {
754 int con_id, free_con_id, i, srcport, dstport, udp_len;
755 ssize_t res;
756 struct sockaddr_in remote_ip;
757
758 if ((packet[20] & 0x3f) != 0) {
759 fatal("[ net_ip_udp(): WARNING! fragmented UDP "
760 "packet, TODO ]\n");
761 return;
762 }
763
764 srcport = (packet[34] << 8) + packet[35];
765 dstport = (packet[36] << 8) + packet[37];
766 udp_len = (packet[38] << 8) + packet[39];
767 /* chksum at offset 40 and 41 */
768
769 debug("[ net: UDP: ");
770 debug("srcport=%i dstport=%i len=%i ", srcport, dstport, udp_len);
771 for (i=42; i<len; i++) {
772 if (packet[i] >= ' ' && packet[i] < 127)
773 debug("%c", packet[i]);
774 else
775 debug("[%02x]", packet[i]);
776 }
777 debug(" ]\n");
778
779 /* Is this "connection" new, or a currently ongoing one? */
780 con_id = free_con_id = -1;
781 for (i=0; i<MAX_UDP_CONNECTIONS; i++) {
782 if (!net->udp_connections[i].in_use)
783 free_con_id = i;
784 if (net->udp_connections[i].in_use &&
785 net->udp_connections[i].inside_udp_port == srcport &&
786 net->udp_connections[i].outside_udp_port == dstport &&
787 memcmp(net->udp_connections[i].inside_ip_address,
788 packet + 26, 4) == 0 &&
789 memcmp(net->udp_connections[i].outside_ip_address,
790 packet + 30, 4) == 0) {
791 con_id = i;
792 break;
793 }
794 }
795
796 debug("&& UDP connection is ");
797 if (con_id >= 0)
798 debug("ONGOING");
799 else {
800 debug("NEW");
801 if (free_con_id < 0) {
802 int i;
803 int64_t oldest = net->
804 udp_connections[0].last_used_timestamp;
805 free_con_id = 0;
806
807 debug(", NO FREE SLOTS, REUSING OLDEST ONE");
808 for (i=0; i<MAX_UDP_CONNECTIONS; i++)
809 if (net->udp_connections[i].
810 last_used_timestamp < oldest) {
811 oldest = net->udp_connections[i].
812 last_used_timestamp;
813 free_con_id = i;
814 }
815 close(net->udp_connections[free_con_id].socket);
816 }
817 con_id = free_con_id;
818 memset(&net->udp_connections[con_id], 0,
819 sizeof(struct udp_connection));
820
821 memcpy(net->udp_connections[con_id].ethernet_address,
822 packet + 6, 6);
823 memcpy(net->udp_connections[con_id].inside_ip_address,
824 packet + 26, 4);
825 net->udp_connections[con_id].inside_udp_port = srcport;
826 memcpy(net->udp_connections[con_id].outside_ip_address,
827 packet + 30, 4);
828 net->udp_connections[con_id].outside_udp_port = dstport;
829
830 net->udp_connections[con_id].socket = socket(AF_INET,
831 SOCK_DGRAM, 0);
832 if (net->udp_connections[con_id].socket < 0) {
833 fatal("[ net: UDP: socket() returned %i ]\n",
834 net->udp_connections[con_id].socket);
835 return;
836 }
837
838 debug(" {socket=%i}", net->udp_connections[con_id].socket);
839
840 net->udp_connections[con_id].in_use = 1;
841
842 /* Set the socket to non-blocking: */
843 res = fcntl(net->udp_connections[con_id].socket, F_GETFL);
844 fcntl(net->udp_connections[con_id].socket, F_SETFL,
845 res | O_NONBLOCK);
846 }
847
848 debug(", connection id %i\n", con_id);
849
850 net->timestamp ++;
851 net->udp_connections[con_id].last_used_timestamp = net->timestamp;
852
853 remote_ip.sin_family = AF_INET;
854 memcpy((unsigned char *)&remote_ip.sin_addr,
855 net->udp_connections[con_id].outside_ip_address, 4);
856
857 /*
858 * Special case for the nameserver: If a UDP packet is sent to
859 * the gateway, it will be forwarded to the nameserver, if it is
860 * known.
861 */
862 if (net->nameserver_known &&
863 memcmp(net->udp_connections[con_id].outside_ip_address,
864 &net->gateway_ipv4_addr[0], 4) == 0) {
865 memcpy((unsigned char *)&remote_ip.sin_addr,
866 &net->nameserver_ipv4, 4);
867 net->udp_connections[con_id].fake_ns = 1;
868 }
869
870 remote_ip.sin_port = htons(
871 net->udp_connections[con_id].outside_udp_port);
872
873 res = sendto(net->udp_connections[con_id].socket, packet + 42,
874 len - 42, 0, (const struct sockaddr *)&remote_ip,
875 sizeof(remote_ip));
876
877 if (res != len-42)
878 debug("[ net: UDP: unable to send %i bytes ]\n", len-42);
879 else
880 debug("[ net: UDP: OK!!! ]\n");
881 }
882
883
884 /*
885 * net_ip():
886 *
887 * Handle an IP packet, coming from the emulated NIC.
888 */
889 void net_ip(struct net *net, void *extra, unsigned char *packet, int len)
890 {
891 #if 1
892 int i;
893
894 debug("[ net: IP: ");
895 debug("ver=%02x ", packet[14]);
896 debug("tos=%02x ", packet[15]);
897 debug("len=%02x%02x ", packet[16], packet[17]);
898 debug("id=%02x%02x ", packet[18], packet[19]);
899 debug("ofs=%02x%02x ", packet[20], packet[21]);
900 debug("ttl=%02x ", packet[22]);
901 debug("p=%02x ", packet[23]);
902 debug("sum=%02x%02x ", packet[24], packet[25]);
903 debug("src=%02x%02x%02x%02x ",
904 packet[26], packet[27], packet[28], packet[29]);
905 debug("dst=%02x%02x%02x%02x ",
906 packet[30], packet[31], packet[32], packet[33]);
907 for (i=34; i<len; i++)
908 debug("%02x", packet[i]);
909 debug(" ]\n");
910 #endif
911
912 /* Cut off overflowing tail data: */
913 if (len > 14 + packet[16]*256 + packet[17])
914 len = 14 + packet[16]*256 + packet[17];
915
916 if (packet[14] == 0x45) {
917 /* IPv4: */
918 switch (packet[23]) {
919 case 1: /* ICMP */
920 net_ip_icmp(net, extra, packet, len);
921 break;
922 case 6: /* TCP */
923 net_ip_tcp(net, extra, packet, len);
924 break;
925 case 17:/* UDP */
926 net_ip_udp(net, extra, packet, len);
927 break;
928 default:
929 fatal("[ net: IP: UNIMPLEMENTED protocol %i ]\n",
930 packet[23]);
931 }
932 } else
933 fatal("[ net: IP: UNIMPLEMENTED ip, first byte = 0x%02x ]\n",
934 packet[14]);
935 }
936
937
938 /*
939 * net_ip_broadcast_dhcp():
940 *
941 * Handle an IPv4 DHCP broadcast packet, coming from the emulated NIC.
942 *
943 * Read http://www.ietf.org/rfc/rfc2131.txt for details on DHCP.
944 * (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.)
945 */
946 static void net_ip_broadcast_dhcp(struct net *net, void *extra,
947 unsigned char *packet, int len)
948 {
949 /*
950 * TODO
951 */
952 #if 1
953 struct ethernet_packet_link *lp;
954 int i;
955
956 fatal("[ net: IPv4 DHCP: ");
957 #if 1
958 fatal("ver=%02x ", packet[14]);
959 fatal("tos=%02x ", packet[15]);
960 fatal("len=%02x%02x ", packet[16], packet[17]);
961 fatal("id=%02x%02x ", packet[18], packet[19]);
962 fatal("ofs=%02x%02x ", packet[20], packet[21]);
963 fatal("ttl=%02x ", packet[22]);
964 fatal("p=%02x ", packet[23]);
965 fatal("sum=%02x%02x ", packet[24], packet[25]);
966 #endif
967 fatal("src=%02x%02x%02x%02x ",
968 packet[26], packet[27], packet[28], packet[29]);
969 fatal("dst=%02x%02x%02x%02x ",
970 packet[30], packet[31], packet[32], packet[33]);
971 #if 0
972 for (i=34; i<len; i++)
973 fatal("%02x", packet[i]);
974 #endif
975
976 if (len < 34 + 8 + 236) {
977 fatal("[ DHCP packet too short? Len=%i ]\n", len);
978 return;
979 }
980
981 /*
982 * UDP data (at offset 34):
983 *
984 * srcport=0044 dstport=0043 length=0134 chksum=a973
985 * data = 01010600d116d276000000000000000000000000000000
986 * 0000000000102030405060...0000...638253633501...000
987 */
988
989 fatal("op=%02x ", packet[42]);
990 fatal("htype=%02x ", packet[43]);
991 fatal("hlen=%02x ", packet[44]);
992 fatal("hops=%02x ", packet[45]);
993 fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47],
994 packet[48], packet[49]);
995 fatal("secs=%02x%02x ", packet[50], packet[51]);
996 fatal("flags=%02x%02x ", packet[52], packet[53]);
997 fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55],
998 packet[56], packet[57]);
999 fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59],
1000 packet[60], packet[61]);
1001 fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63],
1002 packet[64], packet[65]);
1003 fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67],
1004 packet[68], packet[69]);
1005 fatal("chaddr=");
1006 for (i=70; i<70+16; i++)
1007 fatal("%02x", packet[i]);
1008 /*
1009 | sname (64) |
1010 | file (128) |
1011 */
1012 fatal(" ]\n");
1013
1014 lp = net_allocate_ethernet_packet_link(net, extra, len);
1015
1016 /* Copy the old packet first: */
1017 memcpy(lp->data, packet, len);
1018
1019 /* We are sending to the client, from the gateway: */
1020 memcpy(lp->data + 0, packet + 6, 6);
1021 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1022
1023 memcpy(lp->data + 26, &net->gateway_ipv4_addr[0], 4);
1024 lp->data[30] = 0xff;
1025 lp->data[31] = 0xff;
1026 lp->data[32] = 0xff;
1027 lp->data[33] = 0xff;
1028
1029 /* Switch src and dst ports: */
1030 memcpy(lp->data + 34, packet + 36, 2);
1031 memcpy(lp->data + 36, packet + 34, 2);
1032
1033 /* Client's (yiaddr) IPv4 address: */
1034 lp->data[58] = 10;
1035 lp->data[59] = 0;
1036 lp->data[60] = 0;
1037 lp->data[61] = 1;
1038
1039 /* Server's IPv4 address: (giaddr) */
1040 memcpy(lp->data + 66, &net->gateway_ipv4_addr[0], 4);
1041
1042 /* This is a Reply: */
1043 lp->data[42] = 0x02;
1044
1045 snprintf((char *)lp->data + 70+16+64, 8, "gxemul");
1046
1047 /* Recalculate IP header checksum: */
1048 net_ip_checksum(lp->data + 14, 10, 20);
1049
1050 /* ... and the UDP checksum: */
1051 net_ip_tcp_checksum(lp->data + 34, 6, len - 34 - 8,
1052 lp->data + 26, lp->data + 30, 1);
1053
1054
1055 /* Debug dump: */
1056 packet = lp->data;
1057 fatal("[ net: IPv4 DHCP REPLY: ");
1058 for (i=0; i<14; i++)
1059 fatal("%02x", packet[i]);
1060 fatal("ver=%02x ", packet[14]);
1061 fatal("tos=%02x ", packet[15]);
1062 fatal("len=%02x%02x ", packet[16], packet[17]);
1063 fatal("id=%02x%02x ", packet[18], packet[19]);
1064 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1065 fatal("ttl=%02x ", packet[22]);
1066 fatal("p=%02x ", packet[23]);
1067 fatal("sum=%02x%02x ", packet[24], packet[25]);
1068 fatal("src=%02x%02x%02x%02x ",
1069 packet[26], packet[27], packet[28], packet[29]);
1070 fatal("dst=%02x%02x%02x%02x ",
1071 packet[30], packet[31], packet[32], packet[33]);
1072 fatal("op=%02x ", packet[42]);
1073 fatal("htype=%02x ", packet[43]);
1074 fatal("hlen=%02x ", packet[44]);
1075 fatal("hops=%02x ", packet[45]);
1076 fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47],
1077 packet[48], packet[49]);
1078 fatal("secs=%02x%02x ", packet[50], packet[51]);
1079 fatal("flags=%02x%02x ", packet[52], packet[53]);
1080 fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55],
1081 packet[56], packet[57]);
1082 fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59],
1083 packet[60], packet[61]);
1084 fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63],
1085 packet[64], packet[65]);
1086 fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67],
1087 packet[68], packet[69]);
1088 fatal("chaddr=");
1089 for (i=70; i<70+16; i++)
1090 fatal("%02x", packet[i]);
1091 fatal(" ]\n");
1092
1093 #endif
1094 }
1095
1096
1097 /*
1098 * net_ip_broadcast():
1099 *
1100 * Handle an IP broadcast packet, coming from the emulated NIC.
1101 * (This is usually a DHCP request, or similar.)
1102 */
1103 void net_ip_broadcast(struct net *net, void *extra,
1104 unsigned char *packet, int len)
1105 {
1106 unsigned char *p = (void *) &net->netmask_ipv4;
1107 uint32_t x, y;
1108 int i, xl, warning = 0, match = 0;
1109
1110 #if 0
1111 fatal("[ net: IP BROADCAST: ");
1112 fatal("ver=%02x ", packet[14]);
1113 fatal("tos=%02x ", packet[15]);
1114 fatal("len=%02x%02x ", packet[16], packet[17]);
1115 fatal("id=%02x%02x ", packet[18], packet[19]);
1116 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1117 fatal("ttl=%02x ", packet[22]);
1118 fatal("p=%02x ", packet[23]);
1119 fatal("sum=%02x%02x ", packet[24], packet[25]);
1120 fatal("src=%02x%02x%02x%02x ",
1121 packet[26], packet[27], packet[28], packet[29]);
1122 fatal("dst=%02x%02x%02x%02x ",
1123 packet[30], packet[31], packet[32], packet[33]);
1124 for (i=34; i<len; i++)
1125 fatal("%02x", packet[i]);
1126 fatal(" ]\n");
1127 #endif
1128
1129 /* Check for 10.0.0.255 first, maybe some guest OSes think that
1130 it's a /24 network, regardless of what it actually is. */
1131 y = (packet[30] << 24) + (packet[31] << 16) +
1132 (packet[32] << 8) + packet[33];
1133
1134 x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
1135 /* Example: x = 10.0.0.0 */
1136 x |= 255;
1137
1138 if (x == y) {
1139 warning = 1;
1140 match = 1;
1141 }
1142
1143 xl = 32 - net->netmask_ipv4_len;
1144 x |= (1 << xl) - 1;
1145 /* x = 10.255.255.255 */
1146
1147 if (x == y)
1148 match = 1;
1149 if (y == 0xffffffff)
1150 match = 1;
1151
1152 if (warning)
1153 fatal("[ net_ip_broadcast(): warning: broadcast to "
1154 "0x%08x, expecting broadcast to 0x%08x or "
1155 "0xffffffff ]\n", y, x);
1156
1157 /* Cut off overflowing tail data: */
1158 if (len > 14 + packet[16]*256 + packet[17])
1159 len = 14 + packet[16]*256 + packet[17];
1160
1161 /* Check for known packets: */
1162 if (packet[14] == 0x45 && /* IPv4 */
1163 packet[23] == 0x11 && /* UDP */
1164 packet[34] == 0 && packet[35] == 68 && /* DHCP client */
1165 packet[36] == 0 && packet[37] == 67) { /* DHCP server */
1166 net_ip_broadcast_dhcp(net, extra, packet, len);
1167 return;
1168 }
1169
1170 /* Unknown packet: */
1171 fatal("[ net: UNIMPLEMENTED IP BROADCAST: ");
1172 fatal("ver=%02x ", packet[14]);
1173 fatal("tos=%02x ", packet[15]);
1174 fatal("len=%02x%02x ", packet[16], packet[17]);
1175 fatal("id=%02x%02x ", packet[18], packet[19]);
1176 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1177 fatal("ttl=%02x ", packet[22]);
1178 fatal("p=%02x ", packet[23]);
1179 fatal("sum=%02x%02x ", packet[24], packet[25]);
1180 fatal("src=%02x%02x%02x%02x ",
1181 packet[26], packet[27], packet[28], packet[29]);
1182 fatal("dst=%02x%02x%02x%02x ",
1183 packet[30], packet[31], packet[32], packet[33]);
1184 for (i=34; i<len; i++)
1185 fatal("%02x", packet[i]);
1186 fatal(" ]\n");
1187 }
1188
1189
1190 /*
1191 * net_udp_rx_avail():
1192 *
1193 * Receive any available UDP packets (from the outside world).
1194 */
1195 void net_udp_rx_avail(struct net *net, void *extra)
1196 {
1197 int received_packets_this_tick = 0;
1198 int max_packets_this_tick = 200;
1199 int con_id;
1200
1201 for (con_id=0; con_id<MAX_UDP_CONNECTIONS; con_id++) {
1202 ssize_t res;
1203 unsigned char buf[66000];
1204 unsigned char udp_data[66008];
1205 struct sockaddr_in from;
1206 socklen_t from_len = sizeof(from);
1207 int ip_len, udp_len;
1208 struct ethernet_packet_link *lp;
1209 int max_per_packet;
1210 int bytes_converted = 0;
1211 int this_packets_data_length;
1212 int fragment_ofs = 0;
1213
1214 if (received_packets_this_tick > max_packets_this_tick)
1215 break;
1216
1217 if (!net->udp_connections[con_id].in_use)
1218 continue;
1219
1220 if (net->udp_connections[con_id].socket < 0) {
1221 fatal("INTERNAL ERROR in net.c, udp socket < 0 "
1222 "but in use?\n");
1223 continue;
1224 }
1225
1226 res = recvfrom(net->udp_connections[con_id].socket, buf,
1227 sizeof(buf), 0, (struct sockaddr *)&from, &from_len);
1228
1229 /* No more incoming UDP on this connection? */
1230 if (res < 0)
1231 continue;
1232
1233 net->timestamp ++;
1234 net->udp_connections[con_id].last_used_timestamp =
1235 net->timestamp;
1236
1237 net->udp_connections[con_id].udp_id ++;
1238
1239 /*
1240 * Special case for the nameserver: If a UDP packet is
1241 * received from the nameserver (if the nameserver's IP is
1242 * known), fake it so that it comes from the gateway instead.
1243 */
1244 if (net->udp_connections[con_id].fake_ns)
1245 memcpy(((unsigned char *)(&from))+4,
1246 &net->gateway_ipv4_addr[0], 4);
1247
1248 /*
1249 * We now have a UDP packet of size 'res' which we need
1250 * turn into one or more ethernet packets for the emulated
1251 * operating system. Ethernet packets are at most 1518
1252 * bytes long. With some margin, that means we can have
1253 * about 1500 bytes per packet.
1254 *
1255 * Ethernet = 14 bytes
1256 * IP = 20 bytes
1257 * (UDP = 8 bytes + data)
1258 *
1259 * So data can be at most max_per_packet - 34. For UDP
1260 * fragments, each multiple should (?) be a multiple of
1261 * 8 bytes, except the last which doesn't have any such
1262 * restriction.
1263 */
1264 max_per_packet = 1500;
1265
1266 /* UDP: */
1267 udp_len = res + 8;
1268 /* from[2..3] = outside_udp_port */
1269 udp_data[0] = ((unsigned char *)&from)[2];
1270 udp_data[1] = ((unsigned char *)&from)[3];
1271 udp_data[2] = (net->udp_connections[con_id].
1272 inside_udp_port >> 8) & 0xff;
1273 udp_data[3] = net->udp_connections[con_id].
1274 inside_udp_port & 0xff;
1275 udp_data[4] = udp_len >> 8;
1276 udp_data[5] = udp_len & 0xff;
1277 udp_data[6] = 0;
1278 udp_data[7] = 0;
1279 memcpy(udp_data + 8, buf, res);
1280 /*
1281 * TODO: UDP checksum, if necessary. At least NetBSD
1282 * and OpenBSD accept UDP packets with 0x0000 in the
1283 * checksum field anyway.
1284 */
1285
1286 while (bytes_converted < udp_len) {
1287 this_packets_data_length = udp_len - bytes_converted;
1288
1289 /* Do we need to fragment? */
1290 if (this_packets_data_length > max_per_packet-34) {
1291 this_packets_data_length =
1292 max_per_packet - 34;
1293 while (this_packets_data_length & 7)
1294 this_packets_data_length --;
1295 }
1296
1297 ip_len = 20 + this_packets_data_length;
1298
1299 lp = net_allocate_ethernet_packet_link(net, extra,
1300 14 + 20 + this_packets_data_length);
1301
1302 /* Ethernet header: */
1303 memcpy(lp->data + 0, net->udp_connections[con_id].
1304 ethernet_address, 6);
1305 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1306 lp->data[12] = 0x08; /* IP = 0x0800 */
1307 lp->data[13] = 0x00;
1308
1309 /* IP header: */
1310 lp->data[14] = 0x45; /* ver */
1311 lp->data[15] = 0x00; /* tos */
1312 lp->data[16] = ip_len >> 8;
1313 lp->data[17] = ip_len & 0xff;
1314 lp->data[18] = net->udp_connections[con_id].udp_id >> 8;
1315 lp->data[19] = net->udp_connections[con_id].udp_id
1316 & 0xff;
1317 lp->data[20] = (fragment_ofs >> 8);
1318 if (bytes_converted + this_packets_data_length
1319 < udp_len)
1320 lp->data[20] |= 0x20; /* More fragments */
1321 lp->data[21] = fragment_ofs & 0xff;
1322 lp->data[22] = 0x40; /* ttl */
1323 lp->data[23] = 17; /* p = UDP */
1324 lp->data[26] = ((unsigned char *)&from)[4];
1325 lp->data[27] = ((unsigned char *)&from)[5];
1326 lp->data[28] = ((unsigned char *)&from)[6];
1327 lp->data[29] = ((unsigned char *)&from)[7];
1328 memcpy(lp->data + 30, net->udp_connections[con_id].
1329 inside_ip_address, 4);
1330 net_ip_checksum(lp->data + 14, 10, 20);
1331
1332 memcpy(lp->data+34, udp_data + bytes_converted,
1333 this_packets_data_length);
1334
1335 bytes_converted += this_packets_data_length;
1336 fragment_ofs = bytes_converted / 8;
1337
1338 received_packets_this_tick ++;
1339 }
1340
1341 /* This makes sure we check this connection AGAIN
1342 for more incoming UDP packets, before moving to the
1343 next connection: */
1344 con_id --;
1345 }
1346 }
1347
1348
1349 /*
1350 * net_tcp_rx_avail():
1351 *
1352 * Receive any available TCP packets (from the outside world).
1353 */
1354 void net_tcp_rx_avail(struct net *net, void *extra)
1355 {
1356 int received_packets_this_tick = 0;
1357 int max_packets_this_tick = 200;
1358 int con_id;
1359
1360 for (con_id=0; con_id<MAX_TCP_CONNECTIONS; con_id++) {
1361 unsigned char buf[66000];
1362 ssize_t res, res2;
1363 fd_set rfds;
1364 struct timeval tv;
1365
1366 if (received_packets_this_tick > max_packets_this_tick)
1367 break;
1368
1369 if (!net->tcp_connections[con_id].in_use)
1370 continue;
1371
1372 if (net->tcp_connections[con_id].socket < 0) {
1373 fatal("INTERNAL ERROR in net.c, tcp socket < 0"
1374 " but in use?\n");
1375 continue;
1376 }
1377
1378 if (net->tcp_connections[con_id].incoming_buf == NULL) {
1379 net->tcp_connections[con_id].incoming_buf =
1380 malloc(TCP_INCOMING_BUF_LEN);
1381 if (net->tcp_connections[con_id].incoming_buf == NULL) {
1382 printf("out of memory allocating "
1383 "incoming_buf for con_id %i\n", con_id);
1384 exit(1);
1385 }
1386 }
1387
1388 if (net->tcp_connections[con_id].state >=
1389 TCP_OUTSIDE_DISCONNECTED)
1390 continue;
1391
1392 /* Is the socket available for output? */
1393 FD_ZERO(&rfds); /* write */
1394 FD_SET(net->tcp_connections[con_id].socket, &rfds);
1395 tv.tv_sec = tv.tv_usec = 0;
1396 errno = 0;
1397 res = select(net->tcp_connections[con_id].socket+1,
1398 NULL, &rfds, NULL, &tv);
1399
1400 if (errno == ECONNREFUSED) {
1401 fatal("[ ECONNREFUSED: TODO ]\n");
1402 net->tcp_connections[con_id].state =
1403 TCP_OUTSIDE_DISCONNECTED;
1404 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED "
1405 "(refused connection)\n");
1406 continue;
1407 }
1408
1409 if (errno == ETIMEDOUT) {
1410 fatal("[ ETIMEDOUT: TODO ]\n");
1411 /* TODO */
1412 net->tcp_connections[con_id].state =
1413 TCP_OUTSIDE_DISCONNECTED;
1414 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED "
1415 "(timeout)\n");
1416 continue;
1417 }
1418
1419 if (net->tcp_connections[con_id].state ==
1420 TCP_OUTSIDE_TRYINGTOCONNECT && res > 0) {
1421 net->tcp_connections[con_id].state =
1422 TCP_OUTSIDE_CONNECTED;
1423 debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n");
1424 net_ip_tcp_connectionreply(net, extra, con_id, 1,
1425 NULL, 0, 0);
1426 }
1427
1428 if (net->tcp_connections[con_id].state ==
1429 TCP_OUTSIDE_CONNECTED && res < 1) {
1430 continue;
1431 }
1432
1433 /*
1434 * Does this connection have unacknowledged data? Then, if
1435 * enough number of rounds have passed, try to resend it using
1436 * the old value of seqnr.
1437 */
1438 if (net->tcp_connections[con_id].incoming_buf_len != 0) {
1439 net->tcp_connections[con_id].incoming_buf_rounds ++;
1440 if (net->tcp_connections[con_id].incoming_buf_rounds >
1441 10000) {
1442 debug(" at seqnr %u but backing back to %u,"
1443 " resending %i bytes\n",
1444 net->tcp_connections[con_id].outside_seqnr,
1445 net->tcp_connections[con_id].
1446 incoming_buf_seqnr,
1447 net->tcp_connections[con_id].
1448 incoming_buf_len);
1449
1450 net->tcp_connections[con_id].
1451 incoming_buf_rounds = 0;
1452 net->tcp_connections[con_id].outside_seqnr =
1453 net->tcp_connections[con_id].
1454 incoming_buf_seqnr;
1455
1456 net_ip_tcp_connectionreply(net, extra, con_id,
1457 0, net->tcp_connections[con_id].
1458 incoming_buf,
1459 net->tcp_connections[con_id].
1460 incoming_buf_len, 0);
1461 }
1462 continue;
1463 }
1464
1465 /* Don't receive unless the guest OS is ready! */
1466 if (((int32_t)net->tcp_connections[con_id].outside_seqnr -
1467 (int32_t)net->tcp_connections[con_id].inside_acknr) > 0) {
1468 /* fatal("YOYO 1! outside_seqnr - inside_acknr = %i\n",
1469 net->tcp_connections[con_id].outside_seqnr -
1470 net->tcp_connections[con_id].inside_acknr); */
1471 continue;
1472 }
1473
1474 /* Is there incoming data available on the socket? */
1475 FD_ZERO(&rfds); /* read */
1476 FD_SET(net->tcp_connections[con_id].socket, &rfds);
1477 tv.tv_sec = tv.tv_usec = 0;
1478 res2 = select(net->tcp_connections[con_id].socket+1, &rfds,
1479 NULL, NULL, &tv);
1480
1481 /* No more incoming TCP data on this connection? */
1482 if (res2 < 1)
1483 continue;
1484
1485 res = read(net->tcp_connections[con_id].socket, buf, 1400);
1486 if (res > 0) {
1487 /* debug("\n -{- %lli -}-\n", (long long)res); */
1488 net->tcp_connections[con_id].incoming_buf_len = res;
1489 net->tcp_connections[con_id].incoming_buf_rounds = 0;
1490 net->tcp_connections[con_id].incoming_buf_seqnr =
1491 net->tcp_connections[con_id].outside_seqnr;
1492 debug(" putting %i bytes (seqnr %u) in the incoming "
1493 "buf\n", res, net->tcp_connections[con_id].
1494 incoming_buf_seqnr);
1495 memcpy(net->tcp_connections[con_id].incoming_buf,
1496 buf, res);
1497
1498 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1499 buf, res, 0);
1500 } else if (res == 0) {
1501 net->tcp_connections[con_id].state =
1502 TCP_OUTSIDE_DISCONNECTED;
1503 debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read"
1504 " res=0\n");
1505 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1506 NULL, 0, 0);
1507 } else {
1508 net->tcp_connections[con_id].state =
1509 TCP_OUTSIDE_DISCONNECTED;
1510 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, "
1511 "read res<=0, errno = %i\n", errno);
1512 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1513 NULL, 0, 0);
1514 }
1515
1516 net->timestamp ++;
1517 net->tcp_connections[con_id].last_used_timestamp =
1518 net->timestamp;
1519 }
1520 }
1521
1522

  ViewVC Help
Powered by ViewVC 1.1.26