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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26