/[gxemul]/upstream/0.3.6/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

Annotation of /upstream/0.3.6/src/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations)
Mon Oct 8 16:18:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 67342 byte(s)
0.3.6
1 dpavlin 2 /*
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 dpavlin 12 * $Id: net.c,v 1.80 2005/08/12 05:49:46 debug Exp $
29 dpavlin 2 *
30     * Emulated (ethernet / internet) network support.
31     *
32     *
33 dpavlin 10 * 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 dpavlin 2 *
36 dpavlin 10 * 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 dpavlin 2 *
47 dpavlin 10 * TODO 2: The following comments are old! Fix this.
48 dpavlin 2 *
49 dpavlin 10 *
50     * The emulated NIC has a MAC address of (for example) 10:20:30:00:00:10.
51 dpavlin 2 * 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 dpavlin 10 * |------------------ a network --------------------------------|
68 dpavlin 2 * ^ ^ ^
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 dpavlin 10 * TODO: What is a good starting value? Something like this?
162 dpavlin 2 *
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 dpavlin 10 macbuf[2] = 0x30;
171     macbuf[3] = 0;
172     macbuf[4] = 0;
173     macbuf[5] = machine->serial_nr << 4;
174 dpavlin 2
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 dpavlin 10 snprintf(lp->data + 70+16+64, 8, "gxemul");
1224 dpavlin 2
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 dpavlin 10 * 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 dpavlin 2 */
1485 dpavlin 10 /* q = (packet[8 + 3]) >> 4; */
1486     /* q = q*15 + ((packet[8 + 4]) >> 4); */
1487     q = (packet[8 + 5]) >> 4;
1488 dpavlin 2 lp->data[24 + 14] = 10;
1489 dpavlin 10 lp->data[25 + 14] = 0;
1490     lp->data[26 + 14] = 0;
1491     lp->data[27 + 14] = q;
1492 dpavlin 2 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 dpavlin 10 * 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 dpavlin 2 * 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 dpavlin 10 * 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 dpavlin 2 * 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 dpavlin 10 /*
1985     * Copy this packet to all other NICs on this network:
1986     */
1987 dpavlin 2 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 dpavlin 10 /*
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 dpavlin 2 /* 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 dpavlin 10 /*
2017     * The code below simulates the behaviour of a "NAT"-style
2018     * gateway.
2019     */
2020 dpavlin 2 #if 0
2021     fatal("[ net: ethernet: ");
2022 dpavlin 10 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 dpavlin 2 #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 dpavlin 10 struct remote_net *rnp;
2256 dpavlin 2
2257 dpavlin 12 debug("net: simulating ");
2258 dpavlin 2
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 dpavlin 12 debug("simulated gateway: ");
2268 dpavlin 2 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 dpavlin 12 debug("using nameserver ");
2278 dpavlin 2 net_debugaddr(&net->nameserver_ipv4, ADDR_IPV4);
2279     }
2280 dpavlin 12 if (net->domain_name != NULL && net->domain_name[0])
2281     debug(", domain \"%s\"", net->domain_name);
2282 dpavlin 2 debug("\n");
2283     debug_indentation(-iadd);
2284    
2285 dpavlin 10 rnp = net->remote_nets;
2286 dpavlin 12 if (net->local_port != 0)
2287     debug("distributed network: local port = %i\n",
2288     net->local_port);
2289 dpavlin 10 debug_indentation(iadd);
2290     while (rnp != NULL) {
2291 dpavlin 12 debug("remote \"%s\": ", rnp->name);
2292 dpavlin 10 net_debugaddr(&rnp->ipv4_addr, ADDR_IPV4);
2293     debug(" port %i\n", rnp->portnr);
2294     rnp = rnp->next;
2295     }
2296 dpavlin 2 debug_indentation(-iadd);
2297 dpavlin 10
2298     debug_indentation(-iadd);
2299 dpavlin 2 }
2300    
2301    
2302     /*
2303     * net_init():
2304     *
2305     * This function creates a network, and returns a pointer to it.
2306 dpavlin 10 * 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 dpavlin 2 *
2310 dpavlin 10 * On failure, exit() is called.
2311 dpavlin 2 */
2312     struct net *net_init(struct emul *emul, int init_flags,
2313 dpavlin 10 char *ipv4addr, int netipv4len, char **remote, int n_remote,
2314     int local_port)
2315 dpavlin 2 {
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 dpavlin 10 /* 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 dpavlin 12 struct hostent *hp;
2385    
2386 dpavlin 10 /* 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 dpavlin 12
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 dpavlin 10 free(rnp->name);
2405 dpavlin 12
2406 dpavlin 10 /* 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 dpavlin 2 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