/[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

Contents of /trunk/src/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (show 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 /*
2 * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: net.c,v 1.89 2006/02/09 22:40:26 debug Exp $
29 *
30 * Emulated (ethernet / internet) network support.
31 *
32 *
33 * NOTE: This is just an ugly hack, and just barely enough to get some
34 * Internet networking up and running for the guest OS.
35 *
36 * TODO:
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 *
47 * TODO 2: The following comments are old! Fix this.
48 *
49 *
50 * The emulated NIC has a MAC address of (for example) 10:20:30:00:00:10.
51 * 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 * |------------------ a network --------------------------------|
68 * ^ ^ ^
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 macbuf[2] = 0x30;
163 macbuf[3] = 0;
164 macbuf[4] = 0;
165 /* NOTE/TODO: This only allows 8 nics per machine! */
166 macbuf[5] = (machine->serial_nr << 4) + (machine->nr_of_nics << 1);
167
168 if (macbuf[0] & 1 || macbuf[5] & 1) {
169 fatal("Internal error in net_generate_unique_mac().\n");
170 exit(1);
171 }
172
173 /* 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 snprintf(lp->data + 70+16+64, 8, "gxemul");
1222
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 lp = net_allocate_packet_link(net, extra, 60 + 14);
1432
1433 /* Copy the old packet first: */
1434 memset(lp->data, 0, 60 + 14);
1435 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 lp = net_allocate_packet_link(net, extra, 60 + 14);
1456
1457 /* Copy the old packet first: */
1458 memset(lp->data, 0, 60 + 14);
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 * 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 */
1485 /* q = (packet[8 + 3]) >> 4; */
1486 /* q = q*15 + ((packet[8 + 4]) >> 4); */
1487 q = (packet[8 + 5]) >> 4;
1488 lp->data[24 + 14] = 10;
1489 lp->data[25 + 14] = 0;
1490 lp->data[26 + 14] = 0;
1491 lp->data[27 + 14] = q;
1492 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 * 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 * 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 * 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)) != (ssize_t)len) {
1958 perror("send_udp(): sendto");
1959 }
1960
1961 close(s);
1962 }
1963
1964
1965 /*
1966 * 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 /*
1985 * Copy this packet to all other NICs on this network:
1986 */
1987 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 /*
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 /* 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 /*
2017 * The code below simulates the behaviour of a "NAT"-style
2018 * gateway.
2019 */
2020 #if 0
2021 fatal("[ net: ethernet: ");
2022 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 #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 != 42 && 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 = DEBUG_INDENTATION;
2255 struct remote_net *rnp;
2256
2257 debug("net: simulating ");
2258
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 debug("simulated gateway: ");
2268 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 debug("using nameserver ");
2278 net_debugaddr(&net->nameserver_ipv4, ADDR_IPV4);
2279 }
2280 if (net->domain_name != NULL && net->domain_name[0])
2281 debug(", domain \"%s\"", net->domain_name);
2282 debug("\n");
2283 debug_indentation(-iadd);
2284
2285 rnp = net->remote_nets;
2286 if (net->local_port != 0)
2287 debug("distributed network: local port = %i\n",
2288 net->local_port);
2289 debug_indentation(iadd);
2290 while (rnp != NULL) {
2291 debug("remote \"%s\": ", rnp->name);
2292 net_debugaddr(&rnp->ipv4_addr, ADDR_IPV4);
2293 debug(" port %i\n", rnp->portnr);
2294 rnp = rnp->next;
2295 }
2296 debug_indentation(-iadd);
2297
2298 debug_indentation(-iadd);
2299 }
2300
2301
2302 /*
2303 * net_init():
2304 *
2305 * This function creates a network, and returns a pointer to it.
2306 * 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 *
2310 * On failure, exit() is called.
2311 */
2312 struct net *net_init(struct emul *emul, int init_flags,
2313 char *ipv4addr, int netipv4len, char **remote, int n_remote,
2314 int local_port)
2315 {
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 /* 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 struct hostent *hp;
2385
2386 /* 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
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 free(rnp->name);
2405
2406 /* 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 if (init_flags & NET_INIT_FLAG_GATEWAY)
2418 net_gateway_init(net);
2419
2420 net_dumpinfo(net);
2421
2422 /* This is necessary when using the real network: */
2423 signal(SIGPIPE, SIG_IGN);
2424
2425 return net;
2426 }
2427

  ViewVC Help
Powered by ViewVC 1.1.26