/[gxemul]/upstream/0.3.6.1/src/net.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.3.6.1/src/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (show annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 67342 byte(s)
0.3.6.1
1 /*
2 * Copyright (C) 2004-2005 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.c,v 1.80 2005/08/12 05:49:46 debug Exp $
29 *
30 * Emulated (ethernet / internet) network support.
31 *
32 *
33 * NOTE: This is just an ugly hack, and just barely enough to get some
34 * Internet networking up and running for the guest OS.
35 *
36 * TODO:
37 * o) TCP: fin/ack stuff, and connection time-outs and
38 * connection refused (reset on connect?), resend
39 * data to the guest OS if no ack has arrived for
40 * some time (? buffers?)
41 * http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm
42 * o) remove the netbsd-specific options in the tcp header (?)
43 * o) Outgoing UDP packet fragment support.
44 * o) IPv6 (outgoing, incoming, and the nameserver/gateway)
45 * o) Incoming connections
46 *
47 * TODO 2: The following comments are old! Fix this.
48 *
49 *
50 * The emulated NIC has a MAC address of (for example) 10:20:30:00:00:10.
51 * From the emulated environment, the only other machine existing on the
52 * network is a "gateway" or "firewall", which has an address of
53 * 60:50:40:30:20:10. This module (net.c) contains the emulation of that
54 * gateway. It works like a NAT firewall, but emulated in userland software.
55 *
56 * The gateway uses IPv4 address 10.0.0.254, the guest OS (inside the
57 * emulator) could use any 10.x.x.x address, except 10.0.0.254. A suitable
58 * choice is, for example 10.0.0.1.
59 *
60 *
61 * NOTE: The 'extra' argument used in many functions in this file is a pointer
62 * to something unique for each controller, so that if multiple controllers
63 * are emulated concurrently, they will not get packets that aren't meant
64 * for some other controller.
65 *
66 *
67 * |------------------ a network --------------------------------|
68 * ^ ^ ^
69 * | | |
70 * a NIC connected another NIC the gateway
71 * to the network |
72 * v
73 * outside
74 * world
75 *
76 * The gateway isn't connected as a NIC, but is an "implicit" machine on the
77 * network.
78 *
79 * (See http://www.sinclair.org.au/keith/networking/vendor.html for a list
80 * of ethernet MAC assignments.)
81 */
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <unistd.h>
87 #include <errno.h>
88 #include <sys/types.h>
89 #include <sys/time.h>
90 #include <sys/socket.h>
91 #include <netinet/in.h>
92 #include <arpa/inet.h>
93 #include <netdb.h>
94 #include <fcntl.h>
95 #include <signal.h>
96
97 #include "machine.h"
98 #include "misc.h"
99 #include "net.h"
100
101
102 /* #define debug fatal */
103
104
105 #define ADDR_IPV4 1
106 #define ADDR_IPV6 2
107 #define ADDR_ETHERNET 3
108
109
110 /*
111 * net_debugaddr():
112 *
113 * Print an address using debug().
114 */
115 static void net_debugaddr(void *ipv4_addr, int type)
116 {
117 int i;
118 unsigned char *p = ipv4_addr;
119
120 switch (type) {
121 case ADDR_IPV4:
122 for (i=0; i<4; i++)
123 debug("%s%i", i? "." : "", p[i]);
124 break;
125 case ADDR_IPV6:
126 for (i=0; i<16; i+=2)
127 debug("%s%4x", i? ":" : "", p[i] * 256 + p[i+1]);
128 break;
129 case ADDR_ETHERNET:
130 for (i=0; i<6; i++)
131 debug("%s%02x", i? ":" : "", p[i]);
132 break;
133 default:
134 fatal("( net_debugaddr(): UNIMPLEMTED type %i )\n", type);
135 }
136 }
137
138
139 /*
140 * net_generate_unique_mac():
141 *
142 * Generate a "unique" serial number for a machine. The machine's serial
143 * number is combined with the machine's current number of NICs to form a
144 * more-or-less valid MAC address.
145 *
146 * The return value (6 bytes) are written to macbuf.
147 */
148 void net_generate_unique_mac(struct machine *machine, unsigned char *macbuf)
149 {
150 int x, y;
151
152 if (macbuf == NULL || machine == NULL) {
153 fatal("**\n** net_generate_unique_mac(): NULL ptr\n**\n");
154 return;
155 }
156
157 x = machine->serial_nr;
158 y = machine->nr_of_nics;
159
160 /*
161 * TODO: What is a good starting value? Something like this?
162 *
163 * +-----------+-------------------+-------------+-------------+
164 * | 16 bits | 16 bits machine | 12 bits | 4 bits of |
165 * | fixed | serial nr | NIC nr(*) | zeroes |
166 * +-----------+-------------------+-------------+-------------+
167 */
168 macbuf[0] = 0x10;
169 macbuf[1] = 0x20;
170 macbuf[2] = 0x30;
171 macbuf[3] = 0;
172 macbuf[4] = 0;
173 macbuf[5] = machine->serial_nr << 4;
174
175 /* TODO: Remember the mac addresses somewhere? */
176 machine->nr_of_nics ++;
177 }
178
179
180 /*
181 * net_ip_checksum():
182 *
183 * Fill in an IP header checksum. (This works for ICMP too.)
184 * chksumoffset should be 10 for IP headers, and len = 20.
185 * For ICMP packets, chksumoffset = 2 and len = length of the ICMP packet.
186 */
187 void net_ip_checksum(unsigned char *ip_header, int chksumoffset, int len)
188 {
189 int i;
190 uint32_t sum = 0;
191
192 for (i=0; i<len; i+=2)
193 if (i != chksumoffset) {
194 uint16_t w = (ip_header[i] << 8) + ip_header[i+1];
195 sum += w;
196 while (sum > 65535) {
197 int to_add = sum >> 16;
198 sum = (sum & 0xffff) + to_add;
199 }
200 }
201
202 sum ^= 0xffff;
203 ip_header[chksumoffset + 0] = sum >> 8;
204 ip_header[chksumoffset + 1] = sum & 0xff;
205 }
206
207
208 /*
209 * net_ip_tcp_checksum():
210 *
211 * Fill in a TCP header checksum. This differs slightly from the IP
212 * checksum. The checksum is calculated on a pseudo header, the actual
213 * TCP header, and the data. This is what the pseudo header looks like:
214 *
215 * uint32_t srcaddr;
216 * uint32_t dstaddr;
217 * uint16_t protocol; (= 6 for tcp)
218 * uint16_t tcp_len;
219 *
220 * tcp_len is length of header PLUS data. The psedo header is created
221 * internally here, and does not need to be supplied by the caller.
222 */
223 static void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset,
224 int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr,
225 int udpflag)
226 {
227 int i, pad = 0;
228 unsigned char pseudoh[12];
229 uint32_t sum = 0;
230
231 memcpy(pseudoh + 0, srcaddr, 4);
232 memcpy(pseudoh + 4, dstaddr, 4);
233 pseudoh[8] = 0x00;
234 pseudoh[9] = udpflag? 17 : 6;
235 pseudoh[10] = tcp_len >> 8;
236 pseudoh[11] = tcp_len & 255;
237
238 for (i=0; i<12; i+=2) {
239 uint16_t w = (pseudoh[i] << 8) + pseudoh[i+1];
240 sum += w;
241 while (sum > 65535) {
242 int to_add = sum >> 16;
243 sum = (sum & 0xffff) + to_add;
244 }
245 }
246
247 if (tcp_len & 1) {
248 tcp_len ++;
249 pad = 1;
250 }
251
252 for (i=0; i<tcp_len; i+=2)
253 if (i != chksumoffset) {
254 uint16_t w;
255 if (!pad || i < tcp_len-2)
256 w = (tcp_header[i] << 8) + tcp_header[i+1];
257 else
258 w = (tcp_header[i] << 8) + 0x00;
259 sum += w;
260 while (sum > 65535) {
261 int to_add = sum >> 16;
262 sum = (sum & 0xffff) + to_add;
263 }
264 }
265
266 sum ^= 0xffff;
267 tcp_header[chksumoffset + 0] = sum >> 8;
268 tcp_header[chksumoffset + 1] = sum & 0xff;
269 }
270
271
272 /*
273 * net_allocate_packet_link():
274 *
275 * This routine allocates an ethernet_packet_link struct, and adds it at
276 * the end of the packet chain. A data buffer is allocated (and zeroed),
277 * and the data, extra, and len fields of the link are set.
278 *
279 * Return value is a pointer to the link on success. It doesn't return on
280 * failure.
281 */
282 static struct ethernet_packet_link *net_allocate_packet_link(
283 struct net *net, void *extra, int len)
284 {
285 struct ethernet_packet_link *lp;
286
287 lp = malloc(sizeof(struct ethernet_packet_link));
288 if (lp == NULL) {
289 fprintf(stderr, "net_allocate_packet_link(): out of memory\n");
290 exit(1);
291 }
292
293 /* memset(lp, 0, sizeof(struct ethernet_packet_link)); */
294
295 lp->len = len;
296 lp->extra = extra;
297 lp->data = malloc(len);
298 if (lp->data == NULL) {
299 fprintf(stderr, "net_allocate_packet_link(): out of memory\n");
300 exit(1);
301 }
302 lp->next = NULL;
303
304 /* TODO: maybe this is not necessary: */
305 memset(lp->data, 0, len);
306
307 /* Add last in the link chain: */
308 lp->prev = net->last_ethernet_packet;
309 if (lp->prev != NULL)
310 lp->prev->next = lp;
311 else
312 net->first_ethernet_packet = lp;
313 net->last_ethernet_packet = lp;
314
315 return lp;
316 }
317
318
319 /*
320 * net_ip_icmp():
321 *
322 * Handle an ICMP packet.
323 *
324 * The IP header (at offset 14) could look something like
325 *
326 * ver=45 tos=00 len=0054 id=001a ofs=0000 ttl=ff p=01 sum=a87e
327 * src=0a000005 dst=03050607
328 *
329 * and the ICMP specific data (beginning at offset 34):
330 *
331 * type=08 code=00 chksum=b8bf
332 * 000c0008d5cee94089190c0008090a0b
333 * 0c0d0e0f101112131415161718191a1b
334 * 1c1d1e1f202122232425262728292a2b
335 * 2c2d2e2f3031323334353637
336 */
337 static void net_ip_icmp(struct net *net, void *extra,
338 unsigned char *packet, int len)
339 {
340 int type;
341 struct ethernet_packet_link *lp;
342
343 type = packet[34];
344
345 switch (type) {
346 case 8: /* ECHO request */
347 debug("[ ICMP echo ]\n");
348 lp = net_allocate_packet_link(net, extra, len);
349
350 /* Copy the old packet first: */
351 memcpy(lp->data, packet, len);
352
353 /* Switch to and from ethernet addresses: */
354 memcpy(lp->data + 0, packet + 6, 6);
355 memcpy(lp->data + 6, packet + 0, 6);
356
357 /* Switch to and from IP addresses: */
358 memcpy(lp->data + 26, packet + 30, 4);
359 memcpy(lp->data + 30, packet + 26, 4);
360
361 /* Change from echo REQUEST to echo REPLY: */
362 lp->data[34] = 0x00;
363
364 /* Decrease the TTL to a low value: */
365 lp->data[22] = 2;
366
367 /* Recalculate ICMP checksum: */
368 net_ip_checksum(lp->data + 34, 2, len - 34);
369
370 /* Recalculate IP header checksum: */
371 net_ip_checksum(lp->data + 14, 10, 20);
372
373 break;
374 default:
375 fatal("[ net: ICMP type %i not yet implemented ]\n", type);
376 }
377 }
378
379
380 /*
381 * tcp_closeconnection():
382 *
383 * Helper function which closes down a TCP connection completely.
384 */
385 static void tcp_closeconnection(struct net *net, int con_id)
386 {
387 close(net->tcp_connections[con_id].socket);
388 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED;
389 net->tcp_connections[con_id].in_use = 0;
390 net->tcp_connections[con_id].incoming_buf_len = 0;
391 }
392
393
394 /*
395 * net_ip_tcp_connectionreply():
396 *
397 * When changing from state _TRYINGTOCONNECT to _CONNECTED, then this
398 * function should be called with connecting set to 1.
399 *
400 * To send a generic ack reply, set connecting to 0.
401 *
402 * To send data (PSH), set data to non-NULL and datalen to the length.
403 *
404 * This creates an ethernet packet for the guest OS with an ACK to the
405 * initial SYN packet.
406 */
407 static void net_ip_tcp_connectionreply(struct net *net, void *extra,
408 int con_id, int connecting, unsigned char *data, int datalen, int rst)
409 {
410 struct ethernet_packet_link *lp;
411 int tcp_length, ip_len, option_len = 20;
412
413 if (connecting)
414 net->tcp_connections[con_id].outside_acknr =
415 net->tcp_connections[con_id].inside_seqnr + 1;
416
417 net->tcp_connections[con_id].tcp_id ++;
418 tcp_length = 20 + option_len + datalen;
419 ip_len = 20 + tcp_length;
420 lp = net_allocate_packet_link(net, extra, 14 + ip_len);
421
422 /* Ethernet header: */
423 memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6);
424 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
425 lp->data[12] = 0x08; /* IP = 0x0800 */
426 lp->data[13] = 0x00;
427
428 /* IP header: */
429 lp->data[14] = 0x45; /* ver */
430 lp->data[15] = 0x10; /* tos */
431 lp->data[16] = ip_len >> 8;
432 lp->data[17] = ip_len & 0xff;
433 lp->data[18] = net->tcp_connections[con_id].tcp_id >> 8;
434 lp->data[19] = net->tcp_connections[con_id].tcp_id & 0xff;
435 lp->data[20] = 0x40; /* don't fragment */
436 lp->data[21] = 0x00;
437 lp->data[22] = 0x40; /* ttl */
438 lp->data[23] = 6; /* p = TCP */
439 memcpy(lp->data + 26, net->tcp_connections[con_id].
440 outside_ip_address, 4);
441 memcpy(lp->data + 30, net->tcp_connections[con_id].
442 inside_ip_address, 4);
443 net_ip_checksum(lp->data + 14, 10, 20);
444
445 /* TCP header and options at offset 34: */
446 lp->data[34] = net->tcp_connections[con_id].outside_tcp_port >> 8;
447 lp->data[35] = net->tcp_connections[con_id].outside_tcp_port & 0xff;
448 lp->data[36] = net->tcp_connections[con_id].inside_tcp_port >> 8;
449 lp->data[37] = net->tcp_connections[con_id].inside_tcp_port & 0xff;
450 lp->data[38] = (net->tcp_connections[con_id].
451 outside_seqnr >> 24) & 0xff;
452 lp->data[39] = (net->tcp_connections[con_id].
453 outside_seqnr >> 16) & 0xff;
454 lp->data[40] = (net->tcp_connections[con_id].
455 outside_seqnr >> 8) & 0xff;
456 lp->data[41] = net->tcp_connections[con_id].
457 outside_seqnr & 0xff;
458 lp->data[42] = (net->tcp_connections[con_id].
459 outside_acknr >> 24) & 0xff;
460 lp->data[43] = (net->tcp_connections[con_id].
461 outside_acknr >> 16) & 0xff;
462 lp->data[44] = (net->tcp_connections[con_id].
463 outside_acknr >> 8) & 0xff;
464 lp->data[45] = net->tcp_connections[con_id].outside_acknr & 0xff;
465
466 /* Control */
467 lp->data[46] = (option_len + 20) / 4 * 0x10;
468 lp->data[47] = 0x10; /* ACK */
469 if (connecting)
470 lp->data[47] |= 0x02; /* SYN */
471 if (net->tcp_connections[con_id].state == TCP_OUTSIDE_CONNECTED)
472 lp->data[47] |= 0x08; /* PSH */
473 if (rst)
474 lp->data[47] |= 0x04; /* RST */
475 if (net->tcp_connections[con_id].state >= TCP_OUTSIDE_DISCONNECTED)
476 lp->data[47] |= 0x01; /* FIN */
477
478 /* Window */
479 lp->data[48] = 0x10;
480 lp->data[49] = 0x00;
481
482 /* no urgent ptr */
483
484 /* options */
485 /* TODO: HAHA, this is ugly */
486 lp->data[54] = 0x02;
487 lp->data[55] = 0x04;
488 lp->data[56] = 0x05;
489 lp->data[57] = 0xb4;
490 lp->data[58] = 0x01;
491 lp->data[59] = 0x03;
492 lp->data[60] = 0x03;
493 lp->data[61] = 0x00;
494 lp->data[62] = 0x01;
495 lp->data[63] = 0x01;
496 lp->data[64] = 0x08;
497 lp->data[65] = 0x0a;
498 lp->data[66] = (net->timestamp >> 24) & 0xff;
499 lp->data[67] = (net->timestamp >> 16) & 0xff;
500 lp->data[68] = (net->timestamp >> 8) & 0xff;
501 lp->data[69] = net->timestamp & 0xff;
502 lp->data[70] = (net->tcp_connections[con_id].
503 inside_timestamp >> 24) & 0xff;
504 lp->data[71] = (net->tcp_connections[con_id].
505 inside_timestamp >> 16) & 0xff;
506 lp->data[72] = (net->tcp_connections[con_id].
507 inside_timestamp >> 8) & 0xff;
508 lp->data[73] = net->tcp_connections[con_id].
509 inside_timestamp & 0xff;
510
511 /* data: */
512 if (data != NULL) {
513 memcpy(lp->data + 74, data, datalen);
514 net->tcp_connections[con_id].outside_seqnr += datalen;
515 }
516
517 /* Checksum: */
518 net_ip_tcp_checksum(lp->data + 34, 16, tcp_length,
519 lp->data + 26, lp->data + 30, 0);
520
521 #if 0
522 {
523 int i;
524 fatal("[ net_ip_tcp_connectionreply(%i): ", connecting);
525 for (i=0; i<ip_len+14; i++)
526 fatal("%02x", lp->data[i]);
527 fatal(" ]\n");
528 }
529 #endif
530
531 if (connecting)
532 net->tcp_connections[con_id].outside_seqnr ++;
533 }
534
535
536 /*
537 * net_ip_tcp():
538 *
539 * Handle a TCP packet comming from the emulated OS.
540 *
541 * The IP header (at offset 14) could look something like
542 *
543 * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798
544 * src=0a000001 dst=c1abcdef
545 *
546 * TCP header, at offset 34:
547 *
548 * srcport=fffe dstport=0015 seqnr=af419a1d acknr=00000000
549 * control=a002 window=4000 checksum=fe58 urgent=0000
550 * and then "options and padding" and then data.
551 * (020405b4010303000101080a0000000000000000)
552 *
553 * See the following URLs for good descriptions of TCP:
554 *
555 * http://www.networksorcery.com/enp/protocol/tcp.htm
556 * http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm
557 */
558 static void net_ip_tcp(struct net *net, void *extra,
559 unsigned char *packet, int len)
560 {
561 int con_id, free_con_id, i, res;
562 int srcport, dstport, data_offset, window, checksum, urgptr;
563 int syn, ack, psh, rst, urg, fin;
564 uint32_t seqnr, acknr;
565 struct sockaddr_in remote_ip;
566 fd_set rfds;
567 struct timeval tv;
568 int send_ofs;
569
570 #if 0
571 fatal("[ net: TCP: ");
572 for (i=0; i<26; i++)
573 fatal("%02x", packet[i]);
574 fatal(" ");
575 #endif
576
577 srcport = (packet[34] << 8) + packet[35];
578 dstport = (packet[36] << 8) + packet[37];
579
580 seqnr = (packet[38] << 24) + (packet[39] << 16)
581 + (packet[40] << 8) + packet[41];
582 acknr = (packet[42] << 24) + (packet[43] << 16)
583 + (packet[44] << 8) + packet[45];
584
585 #if 0
586 fatal("%i.%i.%i.%i:%i -> %i.%i.%i.%i:%i, seqnr=%lli acknr=%lli ",
587 packet[26], packet[27], packet[28], packet[29], srcport,
588 packet[30], packet[31], packet[32], packet[33], dstport,
589 (long long)seqnr, (long long)acknr);
590 #endif
591
592 data_offset = (packet[46] >> 4) * 4 + 34;
593 /* data_offset is now data offset within packet :-) */
594
595 urg = packet[47] & 32;
596 ack = packet[47] & 16;
597 psh = packet[47] & 8;
598 rst = packet[47] & 4;
599 syn = packet[47] & 2;
600 fin = packet[47] & 1;
601 window = (packet[48] << 8) + packet[49];
602 checksum = (packet[50] << 8) + packet[51];
603 urgptr = (packet[52] << 8) + packet[53];
604
605 #if 0
606 fatal(urg? "URG " : "");
607 fatal(ack? "ACK " : "");
608 fatal(psh? "PSH " : "");
609 fatal(rst? "RST " : "");
610 fatal(syn? "SYN " : "");
611 fatal(fin? "FIN " : "");
612
613 fatal("window=0x%04x checksum=0x%04x urgptr=0x%04x ",
614 window, checksum, urgptr);
615
616 fatal("options=");
617 for (i=34+20; i<data_offset; i++)
618 fatal("%02x", packet[i]);
619
620 fatal(" data=");
621 for (i=data_offset; i<len; i++)
622 fatal("%02x", packet[i]);
623
624 fatal(" ]\n");
625 #endif
626
627 net_ip_tcp_checksum(packet + 34, 16, len - 34,
628 packet + 26, packet + 30, 0);
629 if (packet[50] * 256 + packet[51] != checksum) {
630 debug("TCP: dropping packet because of checksum mismatch "
631 "(0x%04x != 0x%04x)\n", packet[50] * 256 + packet[51],
632 checksum);
633
634 return;
635 }
636
637 /* Does this packet belong to a current connection? */
638 con_id = free_con_id = -1;
639 for (i=0; i<MAX_TCP_CONNECTIONS; i++) {
640 if (!net->tcp_connections[i].in_use)
641 free_con_id = i;
642 if (net->tcp_connections[i].in_use &&
643 net->tcp_connections[i].inside_tcp_port == srcport &&
644 net->tcp_connections[i].outside_tcp_port == dstport &&
645 memcmp(net->tcp_connections[i].inside_ip_address,
646 packet + 26, 4) == 0 &&
647 memcmp(net->tcp_connections[i].outside_ip_address,
648 packet + 30, 4) == 0) {
649 con_id = i;
650 break;
651 }
652 }
653
654 /*
655 * Unknown connection, and not SYN? Then drop the packet.
656 * TODO: Send back RST?
657 */
658 if (con_id < 0 && !syn) {
659 debug("[ net: TCP: dropping packet from unknown connection,"
660 " %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i %s%s%s%s%s]\n",
661 packet[26], packet[27], packet[28], packet[29], srcport,
662 packet[30], packet[31], packet[32], packet[33], dstport,
663 fin? "FIN ": "", syn? "SYN ": "", ack? "ACK ": "",
664 psh? "PSH ": "", rst? "RST ": "");
665 return;
666 }
667
668 /* Known connection, and SYN? Then ignore the packet. */
669 if (con_id >= 0 && syn) {
670 debug("[ net: TCP: ignoring redundant SYN packet from known"
671 " connection, %i.%i.%i.%i:%i -> %i.%i.%i.%i:%i ]\n",
672 packet[26], packet[27], packet[28], packet[29], srcport,
673 packet[30], packet[31], packet[32], packet[33], dstport);
674 return;
675 }
676
677 /*
678 * A new outgoing connection?
679 */
680 if (con_id < 0 && syn) {
681 debug("[ net: TCP: new outgoing connection, %i.%i.%i.%i:%i"
682 " -> %i.%i.%i.%i:%i ]\n",
683 packet[26], packet[27], packet[28], packet[29], srcport,
684 packet[30], packet[31], packet[32], packet[33], dstport);
685
686 /* Find a free connection id to use: */
687 if (free_con_id < 0) {
688 #if 1
689 /*
690 * TODO: Reuse the oldest one currently in use, or
691 * just drop the new connection attempt? Drop for now.
692 */
693 fatal("[ TOO MANY TCP CONNECTIONS IN USE! "
694 "Increase MAX_TCP_CONNECTIONS! ]\n");
695 return;
696 #else
697 int i;
698 int64_t oldest = net->
699 tcp_connections[0].last_used_timestamp;
700 free_con_id = 0;
701
702 fatal("[ NO FREE TCP SLOTS, REUSING OLDEST ONE ]\n");
703 for (i=0; i<MAX_TCP_CONNECTIONS; i++)
704 if (net->tcp_connections[i].
705 last_used_timestamp < oldest) {
706 oldest = net->tcp_connections[i].
707 last_used_timestamp;
708 free_con_id = i;
709 }
710 tcp_closeconnection(net, free_con_id);
711 #endif
712 }
713
714 con_id = free_con_id;
715 memset(&net->tcp_connections[con_id], 0,
716 sizeof(struct tcp_connection));
717
718 memcpy(net->tcp_connections[con_id].ethernet_address,
719 packet + 6, 6);
720 memcpy(net->tcp_connections[con_id].inside_ip_address,
721 packet + 26, 4);
722 net->tcp_connections[con_id].inside_tcp_port = srcport;
723 memcpy(net->tcp_connections[con_id].outside_ip_address,
724 packet + 30, 4);
725 net->tcp_connections[con_id].outside_tcp_port = dstport;
726
727 net->tcp_connections[con_id].socket =
728 socket(AF_INET, SOCK_STREAM, 0);
729 if (net->tcp_connections[con_id].socket < 0) {
730 fatal("[ net: TCP: socket() returned %i ]\n",
731 net->tcp_connections[con_id].socket);
732 return;
733 }
734
735 debug("[ new tcp outgoing socket=%i ]\n",
736 net->tcp_connections[con_id].socket);
737
738 net->tcp_connections[con_id].in_use = 1;
739
740 /* Set the socket to non-blocking: */
741 res = fcntl(net->tcp_connections[con_id].socket, F_GETFL);
742 fcntl(net->tcp_connections[con_id].socket, F_SETFL,
743 res | O_NONBLOCK);
744
745 remote_ip.sin_family = AF_INET;
746 memcpy((unsigned char *)&remote_ip.sin_addr,
747 net->tcp_connections[con_id].outside_ip_address, 4);
748 remote_ip.sin_port = htons(
749 net->tcp_connections[con_id].outside_tcp_port);
750
751 res = connect(net->tcp_connections[con_id].socket,
752 (struct sockaddr *)&remote_ip, sizeof(remote_ip));
753
754 /* connect can return -1, and errno = EINPROGRESS
755 as we might not have connected right away. */
756
757 net->tcp_connections[con_id].state =
758 TCP_OUTSIDE_TRYINGTOCONNECT;
759
760 net->tcp_connections[con_id].outside_acknr = 0;
761 net->tcp_connections[con_id].outside_seqnr =
762 ((random() & 0xffff) << 16) + (random() & 0xffff);
763 }
764
765 if (rst) {
766 debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id);
767 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
768 tcp_closeconnection(net, con_id);
769 return;
770 }
771
772 if (ack && net->tcp_connections[con_id].state
773 == TCP_OUTSIDE_DISCONNECTED2) {
774 debug("[ 'ack': guestOS's final termination of TCP "
775 "connection %i ]\n", con_id);
776
777 /* Send an RST? (TODO, this is wrong...) */
778 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
779
780 /* ... and forget about this connection: */
781 tcp_closeconnection(net, con_id);
782 return;
783 }
784
785 if (fin && net->tcp_connections[con_id].state
786 == TCP_OUTSIDE_DISCONNECTED) {
787 debug("[ 'fin': response to outside's disconnection of "
788 "TCP connection %i ]\n", con_id);
789
790 /* Send an ACK: */
791 net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED;
792 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
793 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
794 return;
795 }
796
797 if (fin) {
798 debug("[ 'fin': guestOS disconnecting TCP connection %i ]\n",
799 con_id);
800
801 /* Send ACK: */
802 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
803 net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
804
805 /* Return and send FIN: */
806 goto ret;
807 }
808
809 if (ack) {
810 debug("ACK %i bytes, inside_acknr=%u outside_seqnr=%u\n",
811 net->tcp_connections[con_id].incoming_buf_len,
812 net->tcp_connections[con_id].inside_acknr,
813 net->tcp_connections[con_id].outside_seqnr);
814 net->tcp_connections[con_id].inside_acknr = acknr;
815 if (net->tcp_connections[con_id].inside_acknr ==
816 net->tcp_connections[con_id].outside_seqnr &&
817 net->tcp_connections[con_id].incoming_buf_len != 0) {
818 debug(" all acked\n");
819 net->tcp_connections[con_id].incoming_buf_len = 0;
820 }
821 }
822
823 net->tcp_connections[con_id].inside_seqnr = seqnr;
824
825 /* TODO: This is hardcoded for a specific NetBSD packet: */
826 if (packet[34 + 30] == 0x08 && packet[34 + 31] == 0x0a)
827 net->tcp_connections[con_id].inside_timestamp =
828 (packet[34 + 32 + 0] << 24) +
829 (packet[34 + 32 + 1] << 16) +
830 (packet[34 + 32 + 2] << 8) +
831 (packet[34 + 32 + 3] << 0);
832
833
834 net->timestamp ++;
835 net->tcp_connections[con_id].last_used_timestamp = net->timestamp;
836
837
838 if (net->tcp_connections[con_id].state != TCP_OUTSIDE_CONNECTED) {
839 debug("[ not connected to outside ]\n");
840 return;
841 }
842
843
844 if (data_offset >= len)
845 return;
846
847
848 /*
849 * We are here if this is a known connection, and data is to be
850 * transmitted to the outside world.
851 */
852
853 send_ofs = data_offset;
854 send_ofs += ((int32_t)net->tcp_connections[con_id].outside_acknr
855 - (int32_t)seqnr);
856 #if 1
857 debug("[ %i bytes of tcp data to be sent, beginning at seqnr %u, ",
858 len - data_offset, seqnr);
859 debug("outside is at acknr %u ==> %i actual bytes to be sent ]\n",
860 net->tcp_connections[con_id].outside_acknr, len - send_ofs);
861 #endif
862
863 /* Drop outgoing packet if the guest OS' seqnr is not
864 the same as we have acked. (We have missed something, perhaps.) */
865 if (seqnr != net->tcp_connections[con_id].outside_acknr) {
866 debug("!! outgoing TCP packet dropped (seqnr = %u, "
867 "outside_acknr = %u)\n", seqnr,
868 net->tcp_connections[con_id].outside_acknr);
869 goto ret;
870 }
871
872 if (len - send_ofs > 0) {
873 /* Is the socket available for output? */
874 FD_ZERO(&rfds); /* write */
875 FD_SET(net->tcp_connections[con_id].socket, &rfds);
876 tv.tv_sec = tv.tv_usec = 0;
877 errno = 0;
878 res = select(net->tcp_connections[con_id].socket+1,
879 NULL, &rfds, NULL, &tv);
880 if (res < 1) {
881 net->tcp_connections[con_id].state =
882 TCP_OUTSIDE_DISCONNECTED;
883 debug("[ TCP: disconnect on select for writing ]\n");
884 goto ret;
885 }
886
887 res = write(net->tcp_connections[con_id].socket,
888 packet + send_ofs, len - send_ofs);
889
890 if (res > 0) {
891 net->tcp_connections[con_id].outside_acknr += res;
892 } else if (errno == EAGAIN) {
893 /* Just ignore this attempt. */
894 return;
895 } else {
896 debug("[ error writing %i bytes to TCP connection %i:"
897 " errno = %i ]\n", len - send_ofs, con_id, errno);
898 net->tcp_connections[con_id].state =
899 TCP_OUTSIDE_DISCONNECTED;
900 debug("[ TCP: disconnect on write() ]\n");
901 goto ret;
902 }
903 }
904
905 ret:
906 /* Send an ACK (or FIN) to the guest OS: */
907 net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
908 }
909
910
911 /*
912 * net_ip_udp():
913 *
914 * Handle a UDP packet.
915 *
916 * (See http://www.networksorcery.com/enp/protocol/udp.htm.)
917 *
918 * The IP header (at offset 14) could look something like
919 *
920 * ver=45 tos=00 len=003c id=0006 ofs=0000 ttl=40 p=11 sum=b798
921 * src=0a000001 dst=c1abcdef
922 *
923 * and the UDP data (beginning at offset 34):
924 *
925 * srcport=fffc dstport=0035 length=0028 chksum=76b6
926 * 43e20100000100000000000003667470066e6574627364036f726700001c0001
927 */
928 static void net_ip_udp(struct net *net, void *extra,
929 unsigned char *packet, int len)
930 {
931 int con_id, free_con_id, i, srcport, dstport, udp_len;
932 ssize_t res;
933 struct sockaddr_in remote_ip;
934
935 if ((packet[20] & 0x3f) != 0) {
936 fatal("[ net_ip_udp(): WARNING! fragmented UDP "
937 "packet, TODO ]\n");
938 return;
939 }
940
941 srcport = (packet[34] << 8) + packet[35];
942 dstport = (packet[36] << 8) + packet[37];
943 udp_len = (packet[38] << 8) + packet[39];
944 /* chksum at offset 40 and 41 */
945
946 debug("[ net: UDP: ");
947 debug("srcport=%i dstport=%i len=%i ", srcport, dstport, udp_len);
948 for (i=42; i<len; i++) {
949 if (packet[i] >= ' ' && packet[i] < 127)
950 debug("%c", packet[i]);
951 else
952 debug("[%02x]", packet[i]);
953 }
954 debug(" ]\n");
955
956 /* Is this "connection" new, or a currently ongoing one? */
957 con_id = free_con_id = -1;
958 for (i=0; i<MAX_UDP_CONNECTIONS; i++) {
959 if (!net->udp_connections[i].in_use)
960 free_con_id = i;
961 if (net->udp_connections[i].in_use &&
962 net->udp_connections[i].inside_udp_port == srcport &&
963 net->udp_connections[i].outside_udp_port == dstport &&
964 memcmp(net->udp_connections[i].inside_ip_address,
965 packet + 26, 4) == 0 &&
966 memcmp(net->udp_connections[i].outside_ip_address,
967 packet + 30, 4) == 0) {
968 con_id = i;
969 break;
970 }
971 }
972
973 debug("&& UDP connection is ");
974 if (con_id >= 0)
975 debug("ONGOING");
976 else {
977 debug("NEW");
978 if (free_con_id < 0) {
979 int i;
980 int64_t oldest = net->
981 udp_connections[0].last_used_timestamp;
982 free_con_id = 0;
983
984 debug(", NO FREE SLOTS, REUSING OLDEST ONE");
985 for (i=0; i<MAX_UDP_CONNECTIONS; i++)
986 if (net->udp_connections[i].
987 last_used_timestamp < oldest) {
988 oldest = net->udp_connections[i].
989 last_used_timestamp;
990 free_con_id = i;
991 }
992 close(net->udp_connections[free_con_id].socket);
993 }
994 con_id = free_con_id;
995 memset(&net->udp_connections[con_id], 0,
996 sizeof(struct udp_connection));
997
998 memcpy(net->udp_connections[con_id].ethernet_address,
999 packet + 6, 6);
1000 memcpy(net->udp_connections[con_id].inside_ip_address,
1001 packet + 26, 4);
1002 net->udp_connections[con_id].inside_udp_port = srcport;
1003 memcpy(net->udp_connections[con_id].outside_ip_address,
1004 packet + 30, 4);
1005 net->udp_connections[con_id].outside_udp_port = dstport;
1006
1007 net->udp_connections[con_id].socket = socket(AF_INET,
1008 SOCK_DGRAM, 0);
1009 if (net->udp_connections[con_id].socket < 0) {
1010 fatal("[ net: UDP: socket() returned %i ]\n",
1011 net->udp_connections[con_id].socket);
1012 return;
1013 }
1014
1015 debug(" {socket=%i}", net->udp_connections[con_id].socket);
1016
1017 net->udp_connections[con_id].in_use = 1;
1018
1019 /* Set the socket to non-blocking: */
1020 res = fcntl(net->udp_connections[con_id].socket, F_GETFL);
1021 fcntl(net->udp_connections[con_id].socket, F_SETFL,
1022 res | O_NONBLOCK);
1023 }
1024
1025 debug(", connection id %i\n", con_id);
1026
1027 net->timestamp ++;
1028 net->udp_connections[con_id].last_used_timestamp = net->timestamp;
1029
1030 remote_ip.sin_family = AF_INET;
1031 memcpy((unsigned char *)&remote_ip.sin_addr,
1032 net->udp_connections[con_id].outside_ip_address, 4);
1033
1034 /*
1035 * Special case for the nameserver: If a UDP packet is sent to
1036 * the gateway, it will be forwarded to the nameserver, if it is
1037 * known.
1038 */
1039 if (net->nameserver_known &&
1040 memcmp(net->udp_connections[con_id].outside_ip_address,
1041 &net->gateway_ipv4_addr[0], 4) == 0) {
1042 memcpy((unsigned char *)&remote_ip.sin_addr,
1043 &net->nameserver_ipv4, 4);
1044 net->udp_connections[con_id].fake_ns = 1;
1045 }
1046
1047 remote_ip.sin_port = htons(
1048 net->udp_connections[con_id].outside_udp_port);
1049
1050 res = sendto(net->udp_connections[con_id].socket, packet + 42,
1051 len - 42, 0, (const struct sockaddr *)&remote_ip,
1052 sizeof(remote_ip));
1053
1054 if (res != len-42)
1055 debug("[ net: UDP: unable to send %i bytes ]\n", len-42);
1056 else
1057 debug("[ net: UDP: OK!!! ]\n");
1058 }
1059
1060
1061 /*
1062 * net_ip():
1063 *
1064 * Handle an IP packet, coming from the emulated NIC.
1065 */
1066 static void net_ip(struct net *net, void *extra,
1067 unsigned char *packet, int len)
1068 {
1069 #if 1
1070 int i;
1071
1072 debug("[ net: IP: ");
1073 debug("ver=%02x ", packet[14]);
1074 debug("tos=%02x ", packet[15]);
1075 debug("len=%02x%02x ", packet[16], packet[17]);
1076 debug("id=%02x%02x ", packet[18], packet[19]);
1077 debug("ofs=%02x%02x ", packet[20], packet[21]);
1078 debug("ttl=%02x ", packet[22]);
1079 debug("p=%02x ", packet[23]);
1080 debug("sum=%02x%02x ", packet[24], packet[25]);
1081 debug("src=%02x%02x%02x%02x ",
1082 packet[26], packet[27], packet[28], packet[29]);
1083 debug("dst=%02x%02x%02x%02x ",
1084 packet[30], packet[31], packet[32], packet[33]);
1085 for (i=34; i<len; i++)
1086 debug("%02x", packet[i]);
1087 debug(" ]\n");
1088 #endif
1089
1090 /* Cut off overflowing tail data: */
1091 if (len > 14 + packet[16]*256 + packet[17])
1092 len = 14 + packet[16]*256 + packet[17];
1093
1094 if (packet[14] == 0x45) {
1095 /* IPv4: */
1096 switch (packet[23]) {
1097 case 1: /* ICMP */
1098 net_ip_icmp(net, extra, packet, len);
1099 break;
1100 case 6: /* TCP */
1101 net_ip_tcp(net, extra, packet, len);
1102 break;
1103 case 17:/* UDP */
1104 net_ip_udp(net, extra, packet, len);
1105 break;
1106 default:
1107 fatal("[ net: IP: UNIMPLEMENTED protocol %i ]\n",
1108 packet[23]);
1109 }
1110 } else
1111 fatal("[ net: IP: UNIMPLEMENTED ip, first byte = 0x%02x ]\n",
1112 packet[14]);
1113 }
1114
1115
1116 /*
1117 * net_ip_broadcast_dhcp():
1118 *
1119 * Handle an IPv4 DHCP broadcast packet, coming from the emulated NIC.
1120 *
1121 * Read http://www.ietf.org/rfc/rfc2131.txt for details on DHCP.
1122 * (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.)
1123 */
1124 static void net_ip_broadcast_dhcp(struct net *net, void *extra,
1125 unsigned char *packet, int len)
1126 {
1127 /*
1128 * TODO
1129 */
1130 #if 0
1131 struct ethernet_packet_link *lp;
1132 int i;
1133
1134 fatal("[ net: IPv4 DHCP: ");
1135 #if 0
1136 fatal("ver=%02x ", packet[14]);
1137 fatal("tos=%02x ", packet[15]);
1138 fatal("len=%02x%02x ", packet[16], packet[17]);
1139 fatal("id=%02x%02x ", packet[18], packet[19]);
1140 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1141 fatal("ttl=%02x ", packet[22]);
1142 fatal("p=%02x ", packet[23]);
1143 fatal("sum=%02x%02x ", packet[24], packet[25]);
1144 #endif
1145 fatal("src=%02x%02x%02x%02x ",
1146 packet[26], packet[27], packet[28], packet[29]);
1147 fatal("dst=%02x%02x%02x%02x ",
1148 packet[30], packet[31], packet[32], packet[33]);
1149 #if 0
1150 for (i=34; i<len; i++)
1151 fatal("%02x", packet[i]);
1152 #endif
1153
1154 if (len < 34 + 8 + 236) {
1155 fatal("[ DHCP packet too short? Len=%i ]\n", len);
1156 return;
1157 }
1158
1159 /*
1160 * UDP data (at offset 34):
1161 *
1162 * srcport=0044 dstport=0043 length=0134 chksum=a973
1163 * data = 01010600d116d276000000000000000000000000000000
1164 * 0000000000102030405060...0000...638253633501...000
1165 */
1166
1167 fatal("op=%02x ", packet[42]);
1168 fatal("htype=%02x ", packet[43]);
1169 fatal("hlen=%02x ", packet[44]);
1170 fatal("hops=%02x ", packet[45]);
1171 fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47],
1172 packet[48], packet[49]);
1173 fatal("secs=%02x%02x ", packet[50], packet[51]);
1174 fatal("flags=%02x%02x ", packet[52], packet[53]);
1175 fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55],
1176 packet[56], packet[57]);
1177 fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59],
1178 packet[60], packet[61]);
1179 fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63],
1180 packet[64], packet[65]);
1181 fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67],
1182 packet[68], packet[69]);
1183 fatal("chaddr=");
1184 for (i=70; i<70+16; i++)
1185 fatal("%02x", packet[i]);
1186 /*
1187 | sname (64) |
1188 | file (128) |
1189 */
1190 fatal(" ]\n");
1191
1192 lp = net_allocate_packet_link(net, extra, len);
1193
1194 /* Copy the old packet first: */
1195 memcpy(lp->data, packet, len);
1196
1197 /* We are sending to the client, from the gateway: */
1198 memcpy(lp->data + 0, packet + 6, 6);
1199 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1200
1201 memcpy(lp->data + 26, &net->gateway_ipv4_addr[0], 4);
1202 lp->data[30] = 0xff;
1203 lp->data[31] = 0xff;
1204 lp->data[32] = 0xff;
1205 lp->data[33] = 0xff;
1206
1207 /* Switch src and dst ports: */
1208 memcpy(lp->data + 34, packet + 36, 2);
1209 memcpy(lp->data + 36, packet + 34, 2);
1210
1211 /* Client's (yiaddr) IPv4 address: */
1212 lp->data[58] = 10;
1213 lp->data[59] = 0;
1214 lp->data[60] = 0;
1215 lp->data[61] = 1;
1216
1217 /* Server's IPv4 address: (giaddr) */
1218 memcpy(lp->data + 66, &net->gateway_ipv4_addr[0], 4);
1219
1220 /* This is a Reply: */
1221 lp->data[42] = 0x02;
1222
1223 snprintf(lp->data + 70+16+64, 8, "gxemul");
1224
1225 /* Recalculate IP header checksum: */
1226 net_ip_checksum(lp->data + 14, 10, 20);
1227
1228 /* ... and the UDP checksum: */
1229 net_ip_tcp_checksum(lp->data + 34, 6, len - 34 - 8,
1230 lp->data + 26, lp->data + 30, 1);
1231
1232
1233 /* Debug dump: */
1234 packet = lp->data;
1235 fatal("[ net: IPv4 DHCP REPLY: ");
1236 for (i=0; i<14; i++)
1237 fatal("%02x", packet[i]);
1238 fatal("ver=%02x ", packet[14]);
1239 fatal("tos=%02x ", packet[15]);
1240 fatal("len=%02x%02x ", packet[16], packet[17]);
1241 fatal("id=%02x%02x ", packet[18], packet[19]);
1242 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1243 fatal("ttl=%02x ", packet[22]);
1244 fatal("p=%02x ", packet[23]);
1245 fatal("sum=%02x%02x ", packet[24], packet[25]);
1246 fatal("src=%02x%02x%02x%02x ",
1247 packet[26], packet[27], packet[28], packet[29]);
1248 fatal("dst=%02x%02x%02x%02x ",
1249 packet[30], packet[31], packet[32], packet[33]);
1250 fatal("op=%02x ", packet[42]);
1251 fatal("htype=%02x ", packet[43]);
1252 fatal("hlen=%02x ", packet[44]);
1253 fatal("hops=%02x ", packet[45]);
1254 fatal("xid=%02x%02x%02x%02x ", packet[46], packet[47],
1255 packet[48], packet[49]);
1256 fatal("secs=%02x%02x ", packet[50], packet[51]);
1257 fatal("flags=%02x%02x ", packet[52], packet[53]);
1258 fatal("ciaddr=%02x%02x%02x%02x ", packet[54], packet[55],
1259 packet[56], packet[57]);
1260 fatal("yiaddr=%02x%02x%02x%02x ", packet[58], packet[59],
1261 packet[60], packet[61]);
1262 fatal("siaddr=%02x%02x%02x%02x ", packet[62], packet[63],
1263 packet[64], packet[65]);
1264 fatal("giaddr=%02x%02x%02x%02x ", packet[66], packet[67],
1265 packet[68], packet[69]);
1266 fatal("chaddr=");
1267 for (i=70; i<70+16; i++)
1268 fatal("%02x", packet[i]);
1269 fatal(" ]\n");
1270
1271 #endif
1272 }
1273
1274
1275 /*
1276 * net_ip_broadcast():
1277 *
1278 * Handle an IP broadcast packet, coming from the emulated NIC.
1279 * (This is usually a DHCP request, or similar.)
1280 */
1281 static void net_ip_broadcast(struct net *net, void *extra,
1282 unsigned char *packet, int len)
1283 {
1284 unsigned char *p = (void *) &net->netmask_ipv4;
1285 uint32_t x, y;
1286 int i, xl, warning = 0, match = 0;
1287
1288 #if 0
1289 fatal("[ net: IP BROADCAST: ");
1290 fatal("ver=%02x ", packet[14]);
1291 fatal("tos=%02x ", packet[15]);
1292 fatal("len=%02x%02x ", packet[16], packet[17]);
1293 fatal("id=%02x%02x ", packet[18], packet[19]);
1294 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1295 fatal("ttl=%02x ", packet[22]);
1296 fatal("p=%02x ", packet[23]);
1297 fatal("sum=%02x%02x ", packet[24], packet[25]);
1298 fatal("src=%02x%02x%02x%02x ",
1299 packet[26], packet[27], packet[28], packet[29]);
1300 fatal("dst=%02x%02x%02x%02x ",
1301 packet[30], packet[31], packet[32], packet[33]);
1302 for (i=34; i<len; i++)
1303 fatal("%02x", packet[i]);
1304 fatal(" ]\n");
1305 #endif
1306
1307 /* Check for 10.0.0.255 first, maybe some guest OSes think that
1308 it's a /24 network, regardless of what it actually is. */
1309 y = (packet[30] << 24) + (packet[31] << 16) +
1310 (packet[32] << 8) + packet[33];
1311
1312 x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
1313 /* Example: x = 10.0.0.0 */
1314 x |= 255;
1315
1316 if (x == y) {
1317 warning = 1;
1318 match = 1;
1319 }
1320
1321 xl = 32 - net->netmask_ipv4_len;
1322 x |= (1 << xl) - 1;
1323 /* x = 10.255.255.255 */
1324
1325 if (x == y)
1326 match = 1;
1327 if (y == 0xffffffff)
1328 match = 1;
1329
1330 if (warning)
1331 fatal("[ net_ip_broadcast(): warning: broadcast to "
1332 "0x%08x, expecting broadcast to 0x%08x or "
1333 "0xffffffff ]\n", y, x);
1334
1335 /* Cut off overflowing tail data: */
1336 if (len > 14 + packet[16]*256 + packet[17])
1337 len = 14 + packet[16]*256 + packet[17];
1338
1339 /* Check for known packets: */
1340 if (packet[14] == 0x45 && /* IPv4 */
1341 packet[23] == 0x11 && /* UDP */
1342 packet[34] == 0 && packet[35] == 68 && /* DHCP client */
1343 packet[36] == 0 && packet[37] == 67) { /* DHCP server */
1344 net_ip_broadcast_dhcp(net, extra, packet, len);
1345 return;
1346 }
1347
1348 /* Unknown packet: */
1349 fatal("[ net: UNIMPLEMENTED IP BROADCAST: ");
1350 fatal("ver=%02x ", packet[14]);
1351 fatal("tos=%02x ", packet[15]);
1352 fatal("len=%02x%02x ", packet[16], packet[17]);
1353 fatal("id=%02x%02x ", packet[18], packet[19]);
1354 fatal("ofs=%02x%02x ", packet[20], packet[21]);
1355 fatal("ttl=%02x ", packet[22]);
1356 fatal("p=%02x ", packet[23]);
1357 fatal("sum=%02x%02x ", packet[24], packet[25]);
1358 fatal("src=%02x%02x%02x%02x ",
1359 packet[26], packet[27], packet[28], packet[29]);
1360 fatal("dst=%02x%02x%02x%02x ",
1361 packet[30], packet[31], packet[32], packet[33]);
1362 for (i=34; i<len; i++)
1363 fatal("%02x", packet[i]);
1364 fatal(" ]\n");
1365 }
1366
1367
1368 /*
1369 * net_arp():
1370 *
1371 * Handle an ARP (or RARP) packet, coming from the emulated NIC.
1372 *
1373 * An ARP packet might look like this:
1374 *
1375 * ARP header:
1376 * ARP hardware addr family: 0001
1377 * ARP protocol addr family: 0800
1378 * ARP addr lengths: 06 04
1379 * ARP request: 0001
1380 * ARP from: 112233445566 01020304
1381 * ARP to: 000000000000 01020301
1382 *
1383 * An ARP request with a 'to' IP value of the gateway should cause an
1384 * ARP response packet to be created.
1385 *
1386 * An ARP request with the same from and to IP addresses should be ignored.
1387 * (This would be a host testing to see if there is an IP collision.)
1388 */
1389 static void net_arp(struct net *net, void *extra,
1390 unsigned char *packet, int len, int reverse)
1391 {
1392 int q;
1393 int i;
1394
1395 /* TODO: This debug dump assumes ethernet->IPv4 translation: */
1396 if (reverse)
1397 debug("[ net: RARP: ");
1398 else
1399 debug("[ net: ARP: ");
1400 for (i=0; i<2; i++)
1401 debug("%02x", packet[i]);
1402 debug(" ");
1403 for (i=2; i<4; i++)
1404 debug("%02x", packet[i]);
1405 debug(" ");
1406 debug("%02x", packet[4]);
1407 debug(" ");
1408 debug("%02x", packet[5]);
1409 debug(" req=");
1410 debug("%02x", packet[6]); /* Request type */
1411 debug("%02x", packet[7]);
1412 debug(" from=");
1413 for (i=8; i<18; i++)
1414 debug("%02x", packet[i]);
1415 debug(" to=");
1416 for (i=18; i<28; i++)
1417 debug("%02x", packet[i]);
1418 debug(" ]\n");
1419
1420 if (packet[0] == 0x00 && packet[1] == 0x01 &&
1421 packet[2] == 0x08 && packet[3] == 0x00 &&
1422 packet[4] == 0x06 && packet[5] == 0x04) {
1423 int r = (packet[6] << 8) + packet[7];
1424 struct ethernet_packet_link *lp;
1425
1426 switch (r) {
1427 case 1: /* Request */
1428 /* Only create a reply if this was meant for the
1429 gateway: */
1430 if (memcmp(packet+24, net->gateway_ipv4_addr, 4) != 0)
1431 break;
1432
1433 lp = net_allocate_packet_link(net, extra, len + 14);
1434
1435 /* Copy the old packet first: */
1436 memcpy(lp->data + 14, packet, len);
1437
1438 /* Add ethernet ARP header: */
1439 memcpy(lp->data + 0, lp->data + 8 + 14, 6);
1440 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1441 lp->data[12] = 0x08; lp->data[13] = 0x06;
1442
1443 /* Address of the emulated machine: */
1444 memcpy(lp->data + 18 + 14, lp->data + 8 + 14, 10);
1445
1446 /* Address of the gateway: */
1447 memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr,
1448 6);
1449 memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4);
1450
1451 /* This is a Reply: */
1452 lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x02;
1453
1454 break;
1455 case 3: /* Reverse Request */
1456 lp = net_allocate_packet_link(net, extra, len + 14);
1457
1458 /* Copy the old packet first: */
1459 memcpy(lp->data + 14, packet, len);
1460
1461 /* Add ethernet RARP header: */
1462 memcpy(lp->data + 0, packet + 8, 6);
1463 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1464 lp->data[12] = 0x80; lp->data[13] = 0x35;
1465
1466 /* This is a RARP reply: */
1467 lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x04;
1468
1469 /* Address of the gateway: */
1470 memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr,
1471 6);
1472 memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4);
1473
1474 /* MAC address of emulated machine: */
1475 memcpy(lp->data + 18 + 14, packet + 8, 6);
1476
1477 /*
1478 * IP address of the emulated machine: Automagically
1479 * generated from the MAC address. :-)
1480 *
1481 * packet+8 points to the client's mac address,
1482 * for example 10:20:30:00:00:z0, where z is 0..15.
1483 * 10:20:30:00:00:10 results in 10.0.0.1.
1484 */
1485 /* q = (packet[8 + 3]) >> 4; */
1486 /* q = q*15 + ((packet[8 + 4]) >> 4); */
1487 q = (packet[8 + 5]) >> 4;
1488 lp->data[24 + 14] = 10;
1489 lp->data[25 + 14] = 0;
1490 lp->data[26 + 14] = 0;
1491 lp->data[27 + 14] = q;
1492 break;
1493 case 2: /* Reply */
1494 case 4: /* Reverse Reply */
1495 default:
1496 fatal("[ net: ARP: UNIMPLEMENTED request type "
1497 "0x%04x ]\n", r);
1498 }
1499 } else {
1500 fatal("[ net: ARP: UNIMPLEMENTED arp packet type: ");
1501 for (i=0; i<len; i++)
1502 fatal("%02x", packet[i]);
1503 fatal(" ]\n");
1504 }
1505 }
1506
1507
1508 /*
1509 * net_ethernet_rx_avail():
1510 *
1511 * Return 1 if there is a packet available for this 'extra' pointer, otherwise
1512 * return 0.
1513 *
1514 * Appart from actually checking for incoming packets from the outside world,
1515 * this function basically works like net_ethernet_rx() but it only receives
1516 * a return value telling us whether there is a packet or not, we don't
1517 * actually get the packet.
1518 */
1519 int net_ethernet_rx_avail(struct net *net, void *extra)
1520 {
1521 int received_packets_this_tick = 0;
1522 int max_packets_this_tick = 200;
1523 int con_id;
1524
1525 if (net == NULL)
1526 return 0;
1527
1528 /*
1529 * If the network is distributed across multiple emulator processes,
1530 * then receive incoming packets from those processes.
1531 */
1532 if (net->local_port != 0) {
1533 struct sockaddr_in si;
1534 socklen_t si_len = sizeof(si);
1535 int res, i;
1536 unsigned char buf[60000];
1537
1538 if ((res = recvfrom(net->local_port_socket, buf, sizeof(buf), 0,
1539 (struct sockaddr *)&si, &si_len)) != -1) {
1540 /* fatal("DISTRIBUTED packet, %i bytes from %s:%d\n",
1541 res, inet_ntoa(si.sin_addr), ntohs(si.sin_port)); */
1542 for (i=0; i<net->n_nics; i++) {
1543 struct ethernet_packet_link *lp;
1544 lp = net_allocate_packet_link(net,
1545 net->nic_extra[i], res);
1546 memcpy(lp->data, buf, res);
1547 }
1548 }
1549 }
1550
1551 /*
1552 * UDP:
1553 */
1554 for (con_id=0; con_id<MAX_UDP_CONNECTIONS; con_id++) {
1555 ssize_t res;
1556 unsigned char buf[66000];
1557 unsigned char udp_data[66008];
1558 struct sockaddr_in from;
1559 socklen_t from_len = sizeof(from);
1560 int ip_len, udp_len;
1561 struct ethernet_packet_link *lp;
1562 int max_per_packet;
1563 int bytes_converted = 0;
1564 int this_packets_data_length;
1565 int fragment_ofs = 0;
1566
1567 if (received_packets_this_tick > max_packets_this_tick)
1568 break;
1569
1570 if (!net->udp_connections[con_id].in_use)
1571 continue;
1572
1573 if (net->udp_connections[con_id].socket < 0) {
1574 fatal("INTERNAL ERROR in net.c, udp socket < 0 "
1575 "but in use?\n");
1576 continue;
1577 }
1578
1579 res = recvfrom(net->udp_connections[con_id].socket, buf,
1580 sizeof(buf), 0, (struct sockaddr *)&from, &from_len);
1581
1582 /* No more incoming UDP on this connection? */
1583 if (res < 0)
1584 continue;
1585
1586 net->timestamp ++;
1587 net->udp_connections[con_id].last_used_timestamp =
1588 net->timestamp;
1589
1590 net->udp_connections[con_id].udp_id ++;
1591
1592 /*
1593 * Special case for the nameserver: If a UDP packet is
1594 * received from the nameserver (if the nameserver's IP is
1595 * known), fake it so that it comes from the gateway instead.
1596 */
1597 if (net->udp_connections[con_id].fake_ns)
1598 memcpy(((unsigned char *)(&from))+4,
1599 &net->gateway_ipv4_addr[0], 4);
1600
1601 /*
1602 * We now have a UDP packet of size 'res' which we need
1603 * turn into one or more ethernet packets for the emulated
1604 * operating system. Ethernet packets are at most 1518
1605 * bytes long. With some margin, that means we can have
1606 * about 1500 bytes per packet.
1607 *
1608 * Ethernet = 14 bytes
1609 * IP = 20 bytes
1610 * (UDP = 8 bytes + data)
1611 *
1612 * So data can be at most max_per_packet - 34. For UDP
1613 * fragments, each multiple should (?) be a multiple of
1614 * 8 bytes, except the last which doesn't have any such
1615 * restriction.
1616 */
1617 max_per_packet = 1500;
1618
1619 /* UDP: */
1620 udp_len = res + 8;
1621 /* from[2..3] = outside_udp_port */
1622 udp_data[0] = ((unsigned char *)&from)[2];
1623 udp_data[1] = ((unsigned char *)&from)[3];
1624 udp_data[2] = (net->udp_connections[con_id].
1625 inside_udp_port >> 8) & 0xff;
1626 udp_data[3] = net->udp_connections[con_id].
1627 inside_udp_port & 0xff;
1628 udp_data[4] = udp_len >> 8;
1629 udp_data[5] = udp_len & 0xff;
1630 udp_data[6] = 0;
1631 udp_data[7] = 0;
1632 memcpy(udp_data + 8, buf, res);
1633 /*
1634 * TODO: UDP checksum, if necessary. At least NetBSD
1635 * and OpenBSD accept UDP packets with 0x0000 in the
1636 * checksum field anyway.
1637 */
1638
1639 while (bytes_converted < udp_len) {
1640 this_packets_data_length = udp_len - bytes_converted;
1641
1642 /* Do we need to fragment? */
1643 if (this_packets_data_length > max_per_packet-34) {
1644 this_packets_data_length =
1645 max_per_packet - 34;
1646 while (this_packets_data_length & 7)
1647 this_packets_data_length --;
1648 }
1649
1650 ip_len = 20 + this_packets_data_length;
1651
1652 lp = net_allocate_packet_link(net, extra,
1653 14 + 20 + this_packets_data_length);
1654
1655 /* Ethernet header: */
1656 memcpy(lp->data + 0, net->udp_connections[con_id].
1657 ethernet_address, 6);
1658 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
1659 lp->data[12] = 0x08; /* IP = 0x0800 */
1660 lp->data[13] = 0x00;
1661
1662 /* IP header: */
1663 lp->data[14] = 0x45; /* ver */
1664 lp->data[15] = 0x00; /* tos */
1665 lp->data[16] = ip_len >> 8;
1666 lp->data[17] = ip_len & 0xff;
1667 lp->data[18] = net->udp_connections[con_id].udp_id >> 8;
1668 lp->data[19] = net->udp_connections[con_id].udp_id
1669 & 0xff;
1670 lp->data[20] = (fragment_ofs >> 8);
1671 if (bytes_converted + this_packets_data_length
1672 < udp_len)
1673 lp->data[20] |= 0x20; /* More fragments */
1674 lp->data[21] = fragment_ofs & 0xff;
1675 lp->data[22] = 0x40; /* ttl */
1676 lp->data[23] = 17; /* p = UDP */
1677 lp->data[26] = ((unsigned char *)&from)[4];
1678 lp->data[27] = ((unsigned char *)&from)[5];
1679 lp->data[28] = ((unsigned char *)&from)[6];
1680 lp->data[29] = ((unsigned char *)&from)[7];
1681 memcpy(lp->data + 30, net->udp_connections[con_id].
1682 inside_ip_address, 4);
1683 net_ip_checksum(lp->data + 14, 10, 20);
1684
1685 memcpy(lp->data+34, udp_data + bytes_converted,
1686 this_packets_data_length);
1687
1688 bytes_converted += this_packets_data_length;
1689 fragment_ofs = bytes_converted / 8;
1690
1691 received_packets_this_tick ++;
1692 }
1693
1694 /* This makes sure we check this connection AGAIN
1695 for more incoming UDP packets, before moving to the
1696 next connection: */
1697 con_id --;
1698 }
1699
1700 /*
1701 * TCP:
1702 */
1703 for (con_id=0; con_id<MAX_TCP_CONNECTIONS; con_id++) {
1704 unsigned char buf[66000];
1705 ssize_t res, res2;
1706 fd_set rfds;
1707 struct timeval tv;
1708
1709 if (received_packets_this_tick > max_packets_this_tick)
1710 break;
1711
1712 if (!net->tcp_connections[con_id].in_use)
1713 continue;
1714
1715 if (net->tcp_connections[con_id].socket < 0) {
1716 fatal("INTERNAL ERROR in net.c, tcp socket < 0"
1717 " but in use?\n");
1718 continue;
1719 }
1720
1721 if (net->tcp_connections[con_id].incoming_buf == NULL) {
1722 net->tcp_connections[con_id].incoming_buf =
1723 malloc(TCP_INCOMING_BUF_LEN);
1724 if (net->tcp_connections[con_id].incoming_buf == NULL) {
1725 printf("out of memory allocating "
1726 "incoming_buf for con_id %i\n", con_id);
1727 exit(1);
1728 }
1729 }
1730
1731 if (net->tcp_connections[con_id].state >=
1732 TCP_OUTSIDE_DISCONNECTED)
1733 continue;
1734
1735 /* Is the socket available for output? */
1736 FD_ZERO(&rfds); /* write */
1737 FD_SET(net->tcp_connections[con_id].socket, &rfds);
1738 tv.tv_sec = tv.tv_usec = 0;
1739 errno = 0;
1740 res = select(net->tcp_connections[con_id].socket+1,
1741 NULL, &rfds, NULL, &tv);
1742
1743 if (errno == ECONNREFUSED) {
1744 fatal("[ ECONNREFUSED: TODO ]\n");
1745 net->tcp_connections[con_id].state =
1746 TCP_OUTSIDE_DISCONNECTED;
1747 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED "
1748 "(refused connection)\n");
1749 continue;
1750 }
1751
1752 if (errno == ETIMEDOUT) {
1753 fatal("[ ETIMEDOUT: TODO ]\n");
1754 /* TODO */
1755 net->tcp_connections[con_id].state =
1756 TCP_OUTSIDE_DISCONNECTED;
1757 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED "
1758 "(timeout)\n");
1759 continue;
1760 }
1761
1762 if (net->tcp_connections[con_id].state ==
1763 TCP_OUTSIDE_TRYINGTOCONNECT && res > 0) {
1764 net->tcp_connections[con_id].state =
1765 TCP_OUTSIDE_CONNECTED;
1766 debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n");
1767 net_ip_tcp_connectionreply(net, extra, con_id, 1,
1768 NULL, 0, 0);
1769 }
1770
1771 if (net->tcp_connections[con_id].state ==
1772 TCP_OUTSIDE_CONNECTED && res < 1) {
1773 continue;
1774 }
1775
1776 /*
1777 * Does this connection have unacknowledged data? Then, if
1778 * enough number of rounds have passed, try to resend it using
1779 * the old value of seqnr.
1780 */
1781 if (net->tcp_connections[con_id].incoming_buf_len != 0) {
1782 net->tcp_connections[con_id].incoming_buf_rounds ++;
1783 if (net->tcp_connections[con_id].incoming_buf_rounds >
1784 10000) {
1785 debug(" at seqnr %u but backing back to %u,"
1786 " resending %i bytes\n",
1787 net->tcp_connections[con_id].outside_seqnr,
1788 net->tcp_connections[con_id].
1789 incoming_buf_seqnr,
1790 net->tcp_connections[con_id].
1791 incoming_buf_len);
1792
1793 net->tcp_connections[con_id].
1794 incoming_buf_rounds = 0;
1795 net->tcp_connections[con_id].outside_seqnr =
1796 net->tcp_connections[con_id].
1797 incoming_buf_seqnr;
1798
1799 net_ip_tcp_connectionreply(net, extra, con_id,
1800 0, net->tcp_connections[con_id].
1801 incoming_buf,
1802 net->tcp_connections[con_id].
1803 incoming_buf_len, 0);
1804 }
1805 continue;
1806 }
1807
1808 /* Don't receive unless the guest OS is ready! */
1809 if (((int32_t)net->tcp_connections[con_id].outside_seqnr -
1810 (int32_t)net->tcp_connections[con_id].inside_acknr) > 0) {
1811 /* fatal("YOYO 1! outside_seqnr - inside_acknr = %i\n",
1812 net->tcp_connections[con_id].outside_seqnr -
1813 net->tcp_connections[con_id].inside_acknr); */
1814 continue;
1815 }
1816
1817 /* Is there incoming data available on the socket? */
1818 FD_ZERO(&rfds); /* read */
1819 FD_SET(net->tcp_connections[con_id].socket, &rfds);
1820 tv.tv_sec = tv.tv_usec = 0;
1821 res2 = select(net->tcp_connections[con_id].socket+1, &rfds,
1822 NULL, NULL, &tv);
1823
1824 /* No more incoming TCP data on this connection? */
1825 if (res2 < 1)
1826 continue;
1827
1828 res = read(net->tcp_connections[con_id].socket, buf, 1400);
1829 if (res > 0) {
1830 /* debug("\n -{- %lli -}-\n", (long long)res); */
1831 net->tcp_connections[con_id].incoming_buf_len = res;
1832 net->tcp_connections[con_id].incoming_buf_rounds = 0;
1833 net->tcp_connections[con_id].incoming_buf_seqnr =
1834 net->tcp_connections[con_id].outside_seqnr;
1835 debug(" putting %i bytes (seqnr %u) in the incoming "
1836 "buf\n", res, net->tcp_connections[con_id].
1837 incoming_buf_seqnr);
1838 memcpy(net->tcp_connections[con_id].incoming_buf,
1839 buf, res);
1840
1841 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1842 buf, res, 0);
1843 } else if (res == 0) {
1844 net->tcp_connections[con_id].state =
1845 TCP_OUTSIDE_DISCONNECTED;
1846 debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read"
1847 " res=0\n");
1848 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1849 NULL, 0, 0);
1850 } else {
1851 net->tcp_connections[con_id].state =
1852 TCP_OUTSIDE_DISCONNECTED;
1853 fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, "
1854 "read res<=0, errno = %i\n", errno);
1855 net_ip_tcp_connectionreply(net, extra, con_id, 0,
1856 NULL, 0, 0);
1857 }
1858
1859 net->timestamp ++;
1860 net->tcp_connections[con_id].last_used_timestamp =
1861 net->timestamp;
1862 }
1863
1864 return net_ethernet_rx(net, extra, NULL, NULL);
1865 }
1866
1867
1868 /*
1869 * net_ethernet_rx():
1870 *
1871 * Receive an ethernet packet. (This means handing over an already prepared
1872 * packet from this module (net.c) to a specific ethernet controller device.)
1873 *
1874 * Return value is 1 if there was a packet available. *packetp and *lenp
1875 * will be set to the packet's data pointer and length, respectively, and
1876 * the packet will be removed from the linked list). If there was no packet
1877 * available, 0 is returned.
1878 *
1879 * If packetp is NULL, then the search is aborted as soon as a packet with
1880 * the correct 'extra' field is found, and a 1 is returned, but as packetp
1881 * is NULL we can't return the actual packet. (This is the internal form
1882 * if net_ethernet_rx_avail().)
1883 */
1884 int net_ethernet_rx(struct net *net, void *extra,
1885 unsigned char **packetp, int *lenp)
1886 {
1887 struct ethernet_packet_link *lp, *prev;
1888
1889 if (net == NULL)
1890 return 0;
1891
1892 /* Find the first packet which has the right 'extra' field. */
1893
1894 lp = net->first_ethernet_packet;
1895 prev = NULL;
1896 while (lp != NULL) {
1897 if (lp->extra == extra) {
1898 /* We found a packet for this controller! */
1899 if (packetp == NULL || lenp == NULL)
1900 return 1;
1901
1902 /* Let's return it: */
1903 (*packetp) = lp->data;
1904 (*lenp) = lp->len;
1905
1906 /* Remove this link from the linked list: */
1907 if (prev == NULL)
1908 net->first_ethernet_packet = lp->next;
1909 else
1910 prev->next = lp->next;
1911
1912 if (lp->next == NULL)
1913 net->last_ethernet_packet = prev;
1914 else
1915 lp->next->prev = prev;
1916
1917 free(lp);
1918
1919 /* ... and return successfully: */
1920 return 1;
1921 }
1922
1923 prev = lp;
1924 lp = lp->next;
1925 }
1926
1927 /* No packet found. :-( */
1928 return 0;
1929 }
1930
1931
1932 /*
1933 * send_udp():
1934 *
1935 * Send a simple UDP packet to some other (real) host. Used for distributed
1936 * network simulations.
1937 */
1938 void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet,
1939 size_t len)
1940 {
1941 int s;
1942 struct sockaddr_in si;
1943
1944 s = socket(AF_INET, SOCK_DGRAM, 0);
1945 if (s < 0) {
1946 perror("send_udp(): socket");
1947 return;
1948 }
1949
1950 /* fatal("send_udp(): sending to port %i\n", portnr); */
1951
1952 si.sin_family = AF_INET;
1953 si.sin_addr = *addrp;
1954 si.sin_port = htons(portnr);
1955
1956 if (sendto(s, packet, len, 0, (struct sockaddr *)&si,
1957 sizeof(si)) != len) {
1958 perror("send_udp(): sendto");
1959 }
1960
1961 close(s);
1962 }
1963
1964
1965 /*
1966 * net_ethernet_tx():
1967 *
1968 * Transmit an ethernet packet, as seen from the emulated ethernet controller.
1969 * If the packet can be handled here, it will not necessarily be transmitted
1970 * to the outside world.
1971 */
1972 void net_ethernet_tx(struct net *net, void *extra,
1973 unsigned char *packet, int len)
1974 {
1975 int i, n;
1976
1977 if (net == NULL)
1978 return;
1979
1980 /* Drop too small packets: */
1981 if (len < 20)
1982 return;
1983
1984 /*
1985 * Copy this packet to all other NICs on this network:
1986 */
1987 if (extra != NULL && net->n_nics > 0) {
1988 for (i=0; i<net->n_nics; i++)
1989 if (extra != net->nic_extra[i]) {
1990 struct ethernet_packet_link *lp;
1991 lp = net_allocate_packet_link(net,
1992 net->nic_extra[i], len);
1993
1994 /* Copy the entire packet: */
1995 memcpy(lp->data, packet, len);
1996 }
1997 }
1998
1999 /*
2000 * If this network is distributed across multiple emulator processes,
2001 * then transmit the packet to those other processes.
2002 */
2003 if (net->remote_nets != NULL) {
2004 struct remote_net *rnp = net->remote_nets;
2005 while (rnp != NULL) {
2006 send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len);
2007 rnp = rnp->next;
2008 }
2009 }
2010
2011 /* Drop packets that are not destined for the gateway: */
2012 if (memcmp(packet, net->gateway_ethernet_addr, 6) != 0
2013 && packet[0] != 0xff && packet[0] != 0x00)
2014 return;
2015
2016 /*
2017 * The code below simulates the behaviour of a "NAT"-style
2018 * gateway.
2019 */
2020 #if 0
2021 fatal("[ net: ethernet: ");
2022 for (i=0; i<6; i++) fatal("%02x", packet[i]); fatal(" ");
2023 for (i=6; i<12; i++) fatal("%02x", packet[i]); fatal(" ");
2024 for (i=12; i<14; i++) fatal("%02x", packet[i]); fatal(" ");
2025 for (i=14; i<len; i++) fatal("%02x", packet[i]); fatal(" ]\n");
2026 #endif
2027
2028 /* Sprite: */
2029 if (packet[12] == 0x05 && packet[13] == 0x00) {
2030 /* TODO. */
2031 fatal("[ net: TX: UNIMPLEMENTED Sprite packet ]\n");
2032 return;
2033 }
2034
2035 /* IP: */
2036 if (packet[12] == 0x08 && packet[13] == 0x00) {
2037 /* Routed via the gateway? */
2038 if (memcmp(packet+0, net->gateway_ethernet_addr, 6) == 0) {
2039 net_ip(net, extra, packet, len);
2040 return;
2041 }
2042
2043 /* Broadcast? (DHCP does this.) */
2044 n = 0;
2045 for (i=0; i<6; i++)
2046 if (packet[i] == 0xff)
2047 n++;
2048 if (n == 6) {
2049 net_ip_broadcast(net, extra, packet, len);
2050 return;
2051 }
2052
2053 if (net->n_nics < 2) {
2054 fatal("[ net: TX: IP packet not for gateway, "
2055 "and not broadcast: ");
2056 for (i=0; i<14; i++)
2057 fatal("%02x", packet[i]);
2058 fatal(" ]\n");
2059 }
2060 return;
2061 }
2062
2063 /* ARP: */
2064 if (packet[12] == 0x08 && packet[13] == 0x06) {
2065 if (len != 60)
2066 fatal("[ net_ethernet_tx: WARNING! unusual "
2067 "ARP len (%i) ]\n", len);
2068 net_arp(net, extra, packet + 14, len - 14, 0);
2069 return;
2070 }
2071
2072 /* RARP: */
2073 if (packet[12] == 0x80 && packet[13] == 0x35) {
2074 net_arp(net, extra, packet + 14, len - 14, 1);
2075 return;
2076 }
2077
2078 /* IPv6: */
2079 if (packet[12] == 0x86 && packet[13] == 0xdd) {
2080 /* TODO. */
2081 fatal("[ net: TX: UNIMPLEMENTED IPv6 packet ]\n");
2082 return;
2083 }
2084
2085 fatal("[ net: TX: UNIMPLEMENTED ethernet packet type 0x%02x%02x! ]\n",
2086 packet[12], packet[13]);
2087 }
2088
2089
2090 /*
2091 * parse_resolvconf():
2092 *
2093 * This function parses "/etc/resolv.conf" to figure out the nameserver
2094 * and domain used by the host.
2095 */
2096 static void parse_resolvconf(struct net *net)
2097 {
2098 FILE *f;
2099 char buf[8000];
2100 size_t len;
2101 int res;
2102 unsigned int i, start;
2103
2104 /*
2105 * This is a very ugly hack, which tries to figure out which
2106 * nameserver the host uses by looking for the string 'nameserver'
2107 * in /etc/resolv.conf.
2108 *
2109 * This can later on be used for DHCP autoconfiguration. (TODO)
2110 *
2111 * TODO: This is hardcoded to use /etc/resolv.conf. Not all
2112 * operating systems use that filename.
2113 *
2114 * TODO: This is hardcoded for AF_INET (that is, IPv4).
2115 *
2116 * TODO: This assumes that the first nameserver listed is the
2117 * one to use.
2118 */
2119 f = fopen("/etc/resolv.conf", "r");
2120 if (f == NULL)
2121 return;
2122
2123 /* TODO: get rid of the hardcoded values */
2124 memset(buf, 0, sizeof(buf));
2125 len = fread(buf, 1, sizeof(buf) - 100, f);
2126 fclose(f);
2127 buf[sizeof(buf) - 1] = '\0';
2128
2129 for (i=0; i<len; i++)
2130 if (strncmp(buf+i, "nameserver", 10) == 0) {
2131 char *p;
2132
2133 /*
2134 * "nameserver" (1 or more whitespace)
2135 * "x.y.z.w" (non-digit)
2136 */
2137
2138 /* debug("found nameserver at offset %i\n", i); */
2139 i += 10;
2140 while (i<len && (buf[i]==' ' || buf[i]=='\t'))
2141 i++;
2142 if (i >= len)
2143 break;
2144 start = i;
2145
2146 p = buf+start;
2147 while ((*p >= '0' && *p <= '9') || *p == '.')
2148 p++;
2149 *p = '\0';
2150
2151 #ifdef HAVE_INET_PTON
2152 res = inet_pton(AF_INET, buf + start,
2153 &net->nameserver_ipv4);
2154 #else
2155 res = inet_aton(buf + start, &net->nameserver_ipv4);
2156 #endif
2157 if (res < 1)
2158 break;
2159
2160 net->nameserver_known = 1;
2161 break;
2162 }
2163
2164 for (i=0; i<len; i++)
2165 if (strncmp(buf+i, "domain", 6) == 0) {
2166 /* "domain" (1 or more whitespace) domain_name */
2167 i += 6;
2168 while (i<len && (buf[i]==' ' || buf[i]=='\t'))
2169 i++;
2170 if (i >= len)
2171 break;
2172
2173 start = i;
2174 while (i<len && buf[i]!='\n' && buf[i]!='\r')
2175 i++;
2176 if (i < len)
2177 buf[i] = '\0';
2178 /* fatal("DOMAIN='%s'\n", buf + start); */
2179 net->domain_name = strdup(buf + start);
2180 break;
2181 }
2182 }
2183
2184
2185 /*
2186 * net_add_nic():
2187 *
2188 * Add a NIC to a network. (All NICs on a network will see each other's
2189 * packets.)
2190 */
2191 void net_add_nic(struct net *net, void *extra, unsigned char *macaddr)
2192 {
2193 if (net == NULL)
2194 return;
2195
2196 if (extra == NULL) {
2197 fprintf(stderr, "net_add_nic(): extra = NULL\n");
2198 exit(1);
2199 }
2200
2201 net->n_nics ++;
2202 net->nic_extra = realloc(net->nic_extra, sizeof(void *)
2203 * net->n_nics);
2204 if (net->nic_extra == NULL) {
2205 fprintf(stderr, "net_add_nic(): out of memory\n");
2206 exit(1);
2207 }
2208
2209 net->nic_extra[net->n_nics - 1] = extra;
2210 }
2211
2212
2213 /*
2214 * net_gateway_init():
2215 *
2216 * This function creates a "gateway" machine (for example at IPv4 address
2217 * 10.0.0.254, if the net is 10.0.0.0/8), which acts as a gateway/router/
2218 * nameserver etc.
2219 */
2220 static void net_gateway_init(struct net *net)
2221 {
2222 unsigned char *p = (void *) &net->netmask_ipv4;
2223 uint32_t x;
2224 int xl;
2225
2226 x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
2227 xl = 32 - net->netmask_ipv4_len;
2228 if (xl > 8)
2229 xl = 8;
2230 x |= ((1 << xl) - 1) & ~1;
2231
2232 net->gateway_ipv4_addr[0] = x >> 24;
2233 net->gateway_ipv4_addr[1] = x >> 16;
2234 net->gateway_ipv4_addr[2] = x >> 8;
2235 net->gateway_ipv4_addr[3] = x;
2236
2237 net->gateway_ethernet_addr[0] = 0x60;
2238 net->gateway_ethernet_addr[1] = 0x50;
2239 net->gateway_ethernet_addr[2] = 0x40;
2240 net->gateway_ethernet_addr[3] = 0x30;
2241 net->gateway_ethernet_addr[4] = 0x20;
2242 net->gateway_ethernet_addr[5] = 0x10;
2243 }
2244
2245
2246 /*
2247 * net_dumpinfo():
2248 *
2249 * Called from the debugger's "machine" command, to print some info about
2250 * a network.
2251 */
2252 void net_dumpinfo(struct net *net)
2253 {
2254 int iadd = 4;
2255 struct remote_net *rnp;
2256
2257 debug("net: simulating ");
2258
2259 net_debugaddr(&net->netmask_ipv4, ADDR_IPV4);
2260 debug("/%i", net->netmask_ipv4_len);
2261
2262 debug(" (max outgoing: TCP=%i, UDP=%i)\n",
2263 MAX_TCP_CONNECTIONS, MAX_UDP_CONNECTIONS);
2264
2265 debug_indentation(iadd);
2266
2267 debug("simulated gateway: ");
2268 net_debugaddr(&net->gateway_ipv4_addr, ADDR_IPV4);
2269 debug(" (");
2270 net_debugaddr(&net->gateway_ethernet_addr, ADDR_ETHERNET);
2271 debug(")\n");
2272
2273 debug_indentation(iadd);
2274 if (!net->nameserver_known) {
2275 debug("(could not determine nameserver)");
2276 } else {
2277 debug("using nameserver ");
2278 net_debugaddr(&net->nameserver_ipv4, ADDR_IPV4);
2279 }
2280 if (net->domain_name != NULL && net->domain_name[0])
2281 debug(", domain \"%s\"", net->domain_name);
2282 debug("\n");
2283 debug_indentation(-iadd);
2284
2285 rnp = net->remote_nets;
2286 if (net->local_port != 0)
2287 debug("distributed network: local port = %i\n",
2288 net->local_port);
2289 debug_indentation(iadd);
2290 while (rnp != NULL) {
2291 debug("remote \"%s\": ", rnp->name);
2292 net_debugaddr(&rnp->ipv4_addr, ADDR_IPV4);
2293 debug(" port %i\n", rnp->portnr);
2294 rnp = rnp->next;
2295 }
2296 debug_indentation(-iadd);
2297
2298 debug_indentation(-iadd);
2299 }
2300
2301
2302 /*
2303 * net_init():
2304 *
2305 * This function creates a network, and returns a pointer to it.
2306 * ipv4addr should be something like "10.0.0.0", netipv4len = 8.
2307 * If n_remote is more than zero, remote should be a pointer to an array
2308 * of strings of the following format: "host:portnr".
2309 *
2310 * On failure, exit() is called.
2311 */
2312 struct net *net_init(struct emul *emul, int init_flags,
2313 char *ipv4addr, int netipv4len, char **remote, int n_remote,
2314 int local_port)
2315 {
2316 struct net *net;
2317 int res;
2318
2319 net = malloc(sizeof(struct net));
2320 if (net == NULL) {
2321 fprintf(stderr, "net_init(): out of memory\n");
2322 exit(1);
2323 }
2324
2325 memset(net, 0, sizeof(struct net));
2326
2327 /* Set the back pointer: */
2328 net->emul = emul;
2329
2330 /* Sane defaults: */
2331 net->timestamp = 0;
2332 net->first_ethernet_packet = net->last_ethernet_packet = NULL;
2333
2334 #ifdef HAVE_INET_PTON
2335 res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4);
2336 #else
2337 res = inet_aton(ipv4addr, &net->netmask_ipv4);
2338 #endif
2339 if (res < 1) {
2340 fprintf(stderr, "net_init(): could not parse IPv4 address"
2341 " '%s'\n", ipv4addr);
2342 exit(1);
2343 }
2344
2345 if (netipv4len < 1 || netipv4len > 30) {
2346 fprintf(stderr, "net_init(): extremely weird ipv4 "
2347 "network length (%i)\n", netipv4len);
2348 exit(1);
2349 }
2350 net->netmask_ipv4_len = netipv4len;
2351
2352 net->nameserver_known = 0;
2353 net->domain_name = "";
2354 parse_resolvconf(net);
2355
2356 /* Distributed network? Then add remote hosts: */
2357 if (local_port != 0) {
2358 struct sockaddr_in si_self;
2359
2360 net->local_port = local_port;
2361 net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0);
2362 if (net->local_port_socket < 0) {
2363 perror("socket");
2364 exit(1);
2365 }
2366
2367 memset((char *)&si_self, sizeof(si_self), 0);
2368 si_self.sin_family = AF_INET;
2369 si_self.sin_port = htons(local_port);
2370 si_self.sin_addr.s_addr = htonl(INADDR_ANY);
2371 if (bind(net->local_port_socket, (struct sockaddr *)&si_self,
2372 sizeof(si_self)) < 0) {
2373 perror("bind");
2374 exit(1);
2375 }
2376
2377 /* Set the socket to non-blocking: */
2378 res = fcntl(net->local_port_socket, F_GETFL);
2379 fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK);
2380 }
2381 if (n_remote != 0) {
2382 struct remote_net *rnp;
2383 while ((n_remote--) != 0) {
2384 struct hostent *hp;
2385
2386 /* debug("adding '%s'\n", remote[n_remote]); */
2387 rnp = malloc(sizeof(struct remote_net));
2388 memset(rnp, 0, sizeof(struct remote_net));
2389
2390 rnp->next = net->remote_nets;
2391 net->remote_nets = rnp;
2392
2393 rnp->name = strdup(remote[n_remote]);
2394 if (strchr(rnp->name, ':') != NULL)
2395 strchr(rnp->name, ':')[0] = '\0';
2396
2397 hp = gethostbyname(rnp->name);
2398 if (hp == NULL) {
2399 fprintf(stderr, "could not resolve '%s'\n",
2400 rnp->name);
2401 exit(1);
2402 }
2403 memcpy(&rnp->ipv4_addr, hp->h_addr, hp->h_length);
2404 free(rnp->name);
2405
2406 /* And again: */
2407 rnp->name = strdup(remote[n_remote]);
2408 if (strchr(rnp->name, ':') == NULL) {
2409 fprintf(stderr, "Remote network '%s' is not "
2410 "'host:portnr'?\n", rnp->name);
2411 exit(1);
2412 }
2413 rnp->portnr = atoi(strchr(rnp->name, ':') + 1);
2414 }
2415 }
2416
2417 if (init_flags & NET_INIT_FLAG_GATEWAY)
2418 net_gateway_init(net);
2419
2420 net_dumpinfo(net);
2421
2422 /* This is neccessary when using the real network: */
2423 signal(SIGPIPE, SIG_IGN);
2424
2425 return net;
2426 }
2427

  ViewVC Help
Powered by ViewVC 1.1.26