/[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 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 67300 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26