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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 7 months ago) by dpavlin
Original Path: trunk/src/net.c
File MIME type: text/plain
File size: 67532 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26