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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (12 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 67342 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26