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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26