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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (show annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22060 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1515 2007/04/14 05:39:46 debug Exp $
20070324	Adding a "--debug" option to the configure script, to disable
		optimizations in unstable development builds.
		Moving out SCSI-specific stuff from diskimage.c into a new
		diskimage_scsicmd.c.
		Applying Hĺvard Eidnes' patch for SCSICDROM_READ_DISKINFO and
		SCSICDROM_READ_TRACKINFO. (Not really tested yet.)
		Implementing disk image "overlays" (to allow simple roll-back
		to previous disk state). Adding a 'V' disk flag for this, and
		updating the man page and misc.html.
20070325	Stability fix to cpu_dyntrans.c, when multiple physical pages
		share the same initial table entry. (The ppp == NULL check
		should be physpage_ofs == 0.) Bug found by analysing GXemul
		against a version patched for Godson.
		Fixing a second occurance of the same problem (also in
		cpu_dyntrans.c).
		Fixing a MAJOR physical page leak in cpu_dyntrans.c; pages
		weren't _added_ to the set of translated pages, they _replaced_
		all previous pages. It's amazing that this bug has been able
		to live for this long. (Triggered when emulating >128MB RAM.)
20070326	Removing the GDB debugging stub support; it was too hackish
		and ugly.
20070328	Moving around some native code generation skeleton code.
20070329	The -lm check in the configure script now also checks for sin()
		in addition to sqrt(). (Thanks to Nigel Horne for noticing that
		sqrt was not enough on Fedora Core 6.) (Not verified yet.)
20070330	Fixing an indexing bug in dev_sh4.c, found by using gcc version
		4.3.0 20070323.
20070331	Some more experimentation with native code generation.
20070404	Attempting to fix some more SH4 SCIF interrupt bugs; rewriting
		the SH interrupt assertion/deassertion code somewhat.
20070410	Splitting src/file.c into separate files in src/file/.
		Cleanup: Removing the dummy TS7200, Walnut, PB1000, and
		Meshcube emulation modes, and dev_epcom and dev_au1x00.
		Removing the experimental CHIP8/RCA180x code; it wasn't really
		working much lately, anyway. It was fun while it lasted.
		Also removing the experimental Transputer CPU support.
20070412	Moving the section about how the dynamic translation system
		works from intro.html to a separate translation.html file.
		Minor SH fixes; attempting to get OpenBSD/landisk to run
		without randomly bugging out, but no success yet.
20070413	SH SCI (serial bit interface) should now work together with a
		(new) RS5C313 clock device (for Landisk emulation).
20070414	Moving Redhat/MIPS down from supported to experimental, in
		guestoses.html.
		Preparing for a new release; doing some regression testing etc.

==============  RELEASE 0.4.5  ==============


1 /*
2 * Copyright (C) 2004-2007 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.8 2007/03/24 06:40:16 debug Exp $
29 *
30 * Emulated network.
31 *
32 * (Read the README file in this directory for more details.)
33 *
34 *
35 * NOTE: The 'extra' argument used in many functions in this file is a pointer
36 * to something unique for each NIC (i.e. the NIC itself :-), so that if
37 * multiple NICs are emulated concurrently, they will not get packets that
38 * are meant for some other controller.
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <errno.h>
46 #include <sys/types.h>
47 #include <sys/socket.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <netdb.h>
51 #include <fcntl.h>
52 #include <signal.h>
53
54 #include "machine.h"
55 #include "misc.h"
56 #include "net.h"
57
58
59 /* #define debug fatal */
60
61
62 /*
63 * net_allocate_ethernet_packet_link():
64 *
65 * This routine allocates an ethernet_packet_link struct, and adds it at
66 * the end of the packet chain. A data buffer is allocated, and the data,
67 * extra, and len fields of the link are set.
68 *
69 * Note: The data buffer is not zeroed.
70 *
71 * Return value is a pointer to the link on success. It doesn't return on
72 * failure.
73 */
74 struct ethernet_packet_link *net_allocate_ethernet_packet_link(
75 struct net *net, void *extra, size_t len)
76 {
77 struct ethernet_packet_link *lp;
78
79 lp = malloc(sizeof(struct ethernet_packet_link));
80 if (lp == NULL)
81 goto fail;
82
83 lp->len = len;
84 lp->extra = extra;
85 lp->data = malloc(len);
86 if (lp->data == NULL)
87 goto fail;
88
89 lp->next = NULL;
90
91 /* Add last in the link chain: */
92 lp->prev = net->last_ethernet_packet;
93 if (lp->prev != NULL)
94 lp->prev->next = lp;
95 else
96 net->first_ethernet_packet = lp;
97 net->last_ethernet_packet = lp;
98
99 return lp;
100
101 fail:
102 fprintf(stderr, "net_allocate_ethernet_packet_link(): out of memory\n");
103 exit(1);
104
105 /* Gets rid of a compiler warning: */
106 return NULL;
107 }
108
109
110 /*
111 * net_arp():
112 *
113 * Handle an ARP (or RARP) packet, coming from the emulated NIC.
114 *
115 * An ARP packet might look like this:
116 *
117 * ARP header:
118 * ARP hardware addr family: 0001
119 * ARP protocol addr family: 0800
120 * ARP addr lengths: 06 04
121 * ARP request: 0001
122 * ARP from: 112233445566 01020304
123 * ARP to: 000000000000 01020301
124 *
125 * An ARP request with a 'to' IP value of the gateway should cause an
126 * ARP response packet to be created.
127 *
128 * An ARP request with the same from and to IP addresses should be ignored.
129 * (This would be a host testing to see if there is an IP collision.)
130 */
131 static void net_arp(struct net *net, void *extra,
132 unsigned char *packet, int len, int reverse)
133 {
134 int q;
135 int i;
136
137 /* TODO: This debug dump assumes ethernet->IPv4 translation: */
138 if (reverse)
139 debug("[ net: RARP: ");
140 else
141 debug("[ net: ARP: ");
142 for (i=0; i<2; i++)
143 debug("%02x", packet[i]);
144 debug(" ");
145 for (i=2; i<4; i++)
146 debug("%02x", packet[i]);
147 debug(" ");
148 debug("%02x", packet[4]);
149 debug(" ");
150 debug("%02x", packet[5]);
151 debug(" req=");
152 debug("%02x", packet[6]); /* Request type */
153 debug("%02x", packet[7]);
154 debug(" from=");
155 for (i=8; i<18; i++)
156 debug("%02x", packet[i]);
157 debug(" to=");
158 for (i=18; i<28; i++)
159 debug("%02x", packet[i]);
160 debug(" ]\n");
161
162 if (packet[0] == 0x00 && packet[1] == 0x01 &&
163 packet[2] == 0x08 && packet[3] == 0x00 &&
164 packet[4] == 0x06 && packet[5] == 0x04) {
165 int r = (packet[6] << 8) + packet[7];
166 struct ethernet_packet_link *lp;
167
168 switch (r) {
169 case 1: /* Request */
170 /* Only create a reply if this was meant for the
171 gateway: */
172 if (memcmp(packet+24, net->gateway_ipv4_addr, 4) != 0)
173 break;
174
175 lp = net_allocate_ethernet_packet_link(
176 net, extra, 60 + 14);
177
178 /* Copy the old packet first: */
179 memset(lp->data, 0, 60 + 14);
180 memcpy(lp->data + 14, packet, len);
181
182 /* Add ethernet ARP header: */
183 memcpy(lp->data + 0, lp->data + 8 + 14, 6);
184 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
185 lp->data[12] = 0x08; lp->data[13] = 0x06;
186
187 /* Address of the emulated machine: */
188 memcpy(lp->data + 18 + 14, lp->data + 8 + 14, 10);
189
190 /* Address of the gateway: */
191 memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr,
192 6);
193 memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4);
194
195 /* This is a Reply: */
196 lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x02;
197
198 break;
199 case 3: /* Reverse Request */
200 lp = net_allocate_ethernet_packet_link(
201 net, extra, 60 + 14);
202
203 /* Copy the old packet first: */
204 memset(lp->data, 0, 60 + 14);
205 memcpy(lp->data + 14, packet, len);
206
207 /* Add ethernet RARP header: */
208 memcpy(lp->data + 0, packet + 8, 6);
209 memcpy(lp->data + 6, net->gateway_ethernet_addr, 6);
210 lp->data[12] = 0x80; lp->data[13] = 0x35;
211
212 /* This is a RARP reply: */
213 lp->data[6 + 14] = 0x00; lp->data[7 + 14] = 0x04;
214
215 /* Address of the gateway: */
216 memcpy(lp->data + 8 + 14, net->gateway_ethernet_addr,
217 6);
218 memcpy(lp->data + 14 + 14, net->gateway_ipv4_addr, 4);
219
220 /* MAC address of emulated machine: */
221 memcpy(lp->data + 18 + 14, packet + 8, 6);
222
223 /*
224 * IP address of the emulated machine: Automagically
225 * generated from the MAC address. :-)
226 *
227 * packet+8 points to the client's mac address,
228 * for example 10:20:30:00:00:z0, where z is 0..15.
229 * 10:20:30:00:00:10 results in 10.0.0.1.
230 */
231 /* q = (packet[8 + 3]) >> 4; */
232 /* q = q*15 + ((packet[8 + 4]) >> 4); */
233 q = (packet[8 + 5]) >> 4;
234 lp->data[24 + 14] = 10;
235 lp->data[25 + 14] = 0;
236 lp->data[26 + 14] = 0;
237 lp->data[27 + 14] = q;
238 break;
239 case 2: /* Reply */
240 case 4: /* Reverse Reply */
241 default:
242 fatal("[ net: ARP: UNIMPLEMENTED request type "
243 "0x%04x ]\n", r);
244 }
245 } else {
246 fatal("[ net: ARP: UNIMPLEMENTED arp packet type: ");
247 for (i=0; i<len; i++)
248 fatal("%02x", packet[i]);
249 fatal(" ]\n");
250 }
251 }
252
253
254 /*
255 * net_ethernet_rx_avail():
256 *
257 * Return 1 if there is a packet available for this 'extra' pointer, otherwise
258 * return 0.
259 *
260 * Appart from actually checking for incoming packets from the outside world,
261 * this function basically works like net_ethernet_rx() but it only receives
262 * a return value telling us whether there is a packet or not, we don't
263 * actually get the packet.
264 */
265 int net_ethernet_rx_avail(struct net *net, void *extra)
266 {
267 if (net == NULL)
268 return 0;
269
270 /*
271 * If the network is distributed across multiple emulator processes,
272 * then receive incoming packets from those processes.
273 */
274 if (net->local_port != 0) {
275 struct sockaddr_in si;
276 socklen_t si_len = sizeof(si);
277 int res, i, nreceived = 0;
278 unsigned char buf[60000];
279
280 do {
281 res = recvfrom(net->local_port_socket, buf,
282 sizeof(buf), 0, (struct sockaddr *)&si, &si_len);
283
284 if (res != -1) {
285 nreceived ++;
286
287 /* fatal("[ incoming DISTRIBUTED packet, %i "
288 "bytes from %s:%d\n", res,
289 inet_ntoa(si.sin_addr),
290 ntohs(si.sin_port)); */
291
292 /* Add the packet to all "our" NICs on this
293 network: */
294 for (i=0; i<net->n_nics; i++) {
295 struct ethernet_packet_link *lp;
296 lp = net_allocate_ethernet_packet_link(
297 net, net->nic_extra[i], res);
298 memcpy(lp->data, buf, res);
299 }
300 }
301 } while (res != -1 && nreceived < 100);
302 }
303
304 /* IP protocol specific: */
305 net_udp_rx_avail(net, extra);
306 net_tcp_rx_avail(net, extra);
307
308 return net_ethernet_rx(net, extra, NULL, NULL);
309 }
310
311
312 /*
313 * net_ethernet_rx():
314 *
315 * Receive an ethernet packet. (This means handing over an already prepared
316 * packet from this module to a specific ethernet controller device.)
317 *
318 * Return value is 1 if there was a packet available. *packetp and *lenp
319 * will be set to the packet's data pointer and length, respectively, and
320 * the packet will be removed from the linked list). If there was no packet
321 * available, 0 is returned.
322 *
323 * If packetp is NULL, then the search is aborted as soon as a packet with
324 * the correct 'extra' field is found, and a 1 is returned, but as packetp
325 * is NULL we can't return the actual packet. (This is the internal form
326 * if net_ethernet_rx_avail().)
327 */
328 int net_ethernet_rx(struct net *net, void *extra,
329 unsigned char **packetp, int *lenp)
330 {
331 struct ethernet_packet_link *lp, *prev;
332
333 if (net == NULL)
334 return 0;
335
336 /* Find the first packet which has the right 'extra' field. */
337
338 lp = net->first_ethernet_packet;
339 prev = NULL;
340 while (lp != NULL) {
341 if (lp->extra == extra) {
342 /* We found a packet for this controller! */
343 if (packetp == NULL || lenp == NULL)
344 return 1;
345
346 /* Let's return it: */
347 (*packetp) = lp->data;
348 (*lenp) = lp->len;
349
350 /* Remove this link from the linked list: */
351 if (prev == NULL)
352 net->first_ethernet_packet = lp->next;
353 else
354 prev->next = lp->next;
355
356 if (lp->next == NULL)
357 net->last_ethernet_packet = prev;
358 else
359 lp->next->prev = prev;
360
361 free(lp);
362
363 /* ... and return successfully: */
364 return 1;
365 }
366
367 prev = lp;
368 lp = lp->next;
369 }
370
371 /* No packet found. :-( */
372 return 0;
373 }
374
375
376 /*
377 * net_ethernet_tx():
378 *
379 * Transmit an ethernet packet, as seen from the emulated ethernet controller.
380 * If the packet can be handled here, it will not necessarily be transmitted
381 * to the outside world.
382 */
383 void net_ethernet_tx(struct net *net, void *extra,
384 unsigned char *packet, int len)
385 {
386 int i, eth_type, for_the_gateway;
387
388 if (net == NULL)
389 return;
390
391 for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6);
392
393 /* Drop too small packets: */
394 if (len < 20) {
395 fatal("[ net_ethernet_tx: Warning: dropping tiny packet "
396 "(%i bytes) ]\n", len);
397 return;
398 }
399
400 /*
401 * Copy this packet to all other NICs on this network (except if
402 * it is aimed specifically at the gateway's ethernet address):
403 */
404 if (!for_the_gateway && extra != NULL && net->n_nics > 0) {
405 for (i=0; i<net->n_nics; i++)
406 if (extra != net->nic_extra[i]) {
407 struct ethernet_packet_link *lp;
408 lp = net_allocate_ethernet_packet_link(net,
409 net->nic_extra[i], len);
410
411 /* Copy the entire packet: */
412 memcpy(lp->data, packet, len);
413 }
414 }
415
416 /*
417 * If this network is distributed across multiple emulator processes,
418 * then transmit the packet to those other processes.
419 */
420 if (!for_the_gateway && net->remote_nets != NULL) {
421 struct remote_net *rnp = net->remote_nets;
422 while (rnp != NULL) {
423 send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len);
424 rnp = rnp->next;
425 }
426 }
427
428
429 /*
430 * The code below simulates the behaviour of a "NAT"-style gateway.
431 *
432 * Packets that are not destined for the gateway are dropped first:
433 * (DHCP packets are let through, though.)
434 */
435
436 if (!for_the_gateway && packet[0] != 0xff && packet[0] != 0x00)
437 return;
438
439 #if 0
440 fatal("[ net: ethernet: ");
441 for (i=0; i<6; i++) fatal("%02x", packet[i]); fatal(" ");
442 for (i=6; i<12; i++) fatal("%02x", packet[i]); fatal(" ");
443 for (i=12; i<14; i++) fatal("%02x", packet[i]); fatal(" ");
444 for (i=14; i<len; i++) fatal("%02x", packet[i]); fatal(" ]\n");
445 #endif
446
447 eth_type = (packet[12] << 8) + packet[13];
448
449 /* IP: */
450 if (eth_type == ETHERTYPE_IP) {
451 /* Routed via the gateway? */
452 if (for_the_gateway) {
453 net_ip(net, extra, packet, len);
454 return;
455 }
456
457 /* Broadcast? (DHCP does this.) */
458 if (packet[0] == 0xff && packet[1] == 0xff &&
459 packet[2] == 0xff && packet[3] == 0xff &&
460 packet[4] == 0xff && packet[5] == 0xff) {
461 net_ip_broadcast(net, extra, packet, len);
462 return;
463 }
464
465 if (net->n_nics < 2) {
466 fatal("[ net_ethernet_tx: IP packet not for gateway, "
467 "and not broadcast: ");
468 for (i=0; i<14; i++)
469 fatal("%02x", packet[i]);
470 fatal(" ]\n");
471 }
472 return;
473 }
474
475 /* ARP: */
476 if (eth_type == ETHERTYPE_ARP) {
477 if (len != 42 && len != 60)
478 fatal("[ net_ethernet_tx: WARNING! unusual "
479 "ARP len (%i) ]\n", len);
480 net_arp(net, extra, packet + 14, len - 14, 0);
481 return;
482 }
483
484 /* RARP: */
485 if (eth_type == ETHERTYPE_REVARP) {
486 net_arp(net, extra, packet + 14, len - 14, 1);
487 return;
488 }
489
490 /* Sprite: */
491 if (eth_type == ETHERTYPE_SPRITE) {
492 /* TODO. */
493 fatal("[ net: TX: UNIMPLEMENTED Sprite packet ]\n");
494 return;
495 }
496
497 /* IPv6: */
498 if (eth_type == ETHERTYPE_IPV6) {
499 /* TODO. */
500 fatal("[ net_ethernet_tx: IPv6 is not implemented yet! ]\n");
501 return;
502 }
503
504 fatal("[ net_ethernet_tx: ethernet packet type 0x%04x not yet "
505 "implemented ]\n", eth_type);
506 }
507
508
509 /*
510 * parse_resolvconf():
511 *
512 * This function parses "/etc/resolv.conf" to figure out the nameserver
513 * and domain used by the host.
514 */
515 static void parse_resolvconf(struct net *net)
516 {
517 FILE *f;
518 char buf[8000];
519 size_t len;
520 int res;
521 unsigned int i, start;
522
523 /*
524 * This is a very ugly hack, which tries to figure out which
525 * nameserver the host uses by looking for the string 'nameserver'
526 * in /etc/resolv.conf.
527 *
528 * This can later on be used for DHCP autoconfiguration. (TODO)
529 *
530 * TODO: This is hardcoded to use /etc/resolv.conf. Not all
531 * operating systems use that filename.
532 *
533 * TODO: This is hardcoded for AF_INET (that is, IPv4).
534 *
535 * TODO: This assumes that the first nameserver listed is the
536 * one to use.
537 */
538 f = fopen("/etc/resolv.conf", "r");
539 if (f == NULL)
540 return;
541
542 /* TODO: get rid of the hardcoded values */
543 memset(buf, 0, sizeof(buf));
544 len = fread(buf, 1, sizeof(buf) - 100, f);
545 fclose(f);
546 buf[sizeof(buf) - 1] = '\0';
547
548 for (i=0; i<len; i++)
549 if (strncmp(buf+i, "nameserver", 10) == 0) {
550 char *p;
551
552 /*
553 * "nameserver" (1 or more whitespace)
554 * "x.y.z.w" (non-digit)
555 */
556
557 /* debug("found nameserver at offset %i\n", i); */
558 i += 10;
559 while (i<len && (buf[i]==' ' || buf[i]=='\t'))
560 i++;
561 if (i >= len)
562 break;
563 start = i;
564
565 p = buf+start;
566 while ((*p >= '0' && *p <= '9') || *p == '.')
567 p++;
568 *p = '\0';
569
570 #ifdef HAVE_INET_PTON
571 res = inet_pton(AF_INET, buf + start,
572 &net->nameserver_ipv4);
573 #else
574 res = inet_aton(buf + start, &net->nameserver_ipv4);
575 #endif
576 if (res < 1)
577 break;
578
579 net->nameserver_known = 1;
580 break;
581 }
582
583 for (i=0; i<len; i++)
584 if (strncmp(buf+i, "domain", 6) == 0) {
585 /* "domain" (1 or more whitespace) domain_name */
586 i += 6;
587 while (i<len && (buf[i]==' ' || buf[i]=='\t'))
588 i++;
589 if (i >= len)
590 break;
591
592 start = i;
593 while (i<len && buf[i]!='\n' && buf[i]!='\r')
594 i++;
595 if (i < len)
596 buf[i] = '\0';
597 /* fatal("DOMAIN='%s'\n", buf + start); */
598 net->domain_name = strdup(buf + start);
599 break;
600 }
601 }
602
603
604 /*
605 * net_add_nic():
606 *
607 * Add a NIC to a network. (All NICs on a network will see each other's
608 * packets.)
609 */
610 void net_add_nic(struct net *net, void *extra, unsigned char *macaddr)
611 {
612 if (net == NULL)
613 return;
614
615 if (extra == NULL) {
616 fprintf(stderr, "net_add_nic(): extra = NULL\n");
617 exit(1);
618 }
619
620 net->n_nics ++;
621 net->nic_extra = realloc(net->nic_extra, sizeof(void *)
622 * net->n_nics);
623 if (net->nic_extra == NULL) {
624 fprintf(stderr, "net_add_nic(): out of memory\n");
625 exit(1);
626 }
627
628 net->nic_extra[net->n_nics - 1] = extra;
629 }
630
631
632 /*
633 * net_gateway_init():
634 *
635 * This function creates a "gateway" machine (for example at IPv4 address
636 * 10.0.0.254, if the net is 10.0.0.0/8), which acts as a gateway/router/
637 * nameserver etc.
638 */
639 static void net_gateway_init(struct net *net)
640 {
641 unsigned char *p = (void *) &net->netmask_ipv4;
642 uint32_t x;
643 int xl;
644
645 x = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
646 xl = 32 - net->netmask_ipv4_len;
647 if (xl > 8)
648 xl = 8;
649 x |= ((1 << xl) - 1) & ~1;
650
651 net->gateway_ipv4_addr[0] = x >> 24;
652 net->gateway_ipv4_addr[1] = x >> 16;
653 net->gateway_ipv4_addr[2] = x >> 8;
654 net->gateway_ipv4_addr[3] = x;
655
656 net->gateway_ethernet_addr[0] = 0x60;
657 net->gateway_ethernet_addr[1] = 0x50;
658 net->gateway_ethernet_addr[2] = 0x40;
659 net->gateway_ethernet_addr[3] = 0x30;
660 net->gateway_ethernet_addr[4] = 0x20;
661 net->gateway_ethernet_addr[5] = 0x10;
662 }
663
664
665 /*
666 * net_dumpinfo():
667 *
668 * Called from the debugger's "machine" command, to print some info about
669 * a network.
670 */
671 void net_dumpinfo(struct net *net)
672 {
673 int iadd = DEBUG_INDENTATION;
674 struct remote_net *rnp;
675
676 debug("net: simulating ");
677
678 net_debugaddr(&net->netmask_ipv4, NET_ADDR_IPV4);
679 debug("/%i", net->netmask_ipv4_len);
680
681 debug(" (max outgoing: TCP=%i, UDP=%i)\n",
682 MAX_TCP_CONNECTIONS, MAX_UDP_CONNECTIONS);
683
684 debug_indentation(iadd);
685
686 debug("simulated gateway: ");
687 net_debugaddr(&net->gateway_ipv4_addr, NET_ADDR_IPV4);
688 debug(" (");
689 net_debugaddr(&net->gateway_ethernet_addr, NET_ADDR_ETHERNET);
690 debug(")\n");
691
692 debug_indentation(iadd);
693 if (!net->nameserver_known) {
694 debug("(could not determine nameserver)");
695 } else {
696 debug("using nameserver ");
697 net_debugaddr(&net->nameserver_ipv4, NET_ADDR_IPV4);
698 }
699 if (net->domain_name != NULL && net->domain_name[0])
700 debug(", domain \"%s\"", net->domain_name);
701 debug("\n");
702 debug_indentation(-iadd);
703
704 rnp = net->remote_nets;
705 if (net->local_port != 0)
706 debug("distributed network: local port = %i\n",
707 net->local_port);
708 debug_indentation(iadd);
709 while (rnp != NULL) {
710 debug("remote \"%s\": ", rnp->name);
711 net_debugaddr(&rnp->ipv4_addr, NET_ADDR_IPV4);
712 debug(" port %i\n", rnp->portnr);
713 rnp = rnp->next;
714 }
715 debug_indentation(-iadd);
716
717 debug_indentation(-iadd);
718 }
719
720
721 /*
722 * net_init():
723 *
724 * This function creates a network, and returns a pointer to it.
725 *
726 * ipv4addr should be something like "10.0.0.0", netipv4len = 8.
727 *
728 * If n_remote is more than zero, remote should be a pointer to an array
729 * of strings of the following format: "host:portnr".
730 *
731 * Network settings are registered if settings_prefix is non-NULL.
732 * (The one calling net_init() is also responsible for calling net_deinit().)
733 *
734 * On failure, exit() is called.
735 */
736 struct net *net_init(struct emul *emul, int init_flags,
737 const char *ipv4addr, int netipv4len,
738 char **remote, int n_remote, int local_port,
739 const char *settings_prefix)
740 {
741 struct net *net;
742 int res;
743
744 net = malloc(sizeof(struct net));
745 if (net == NULL) {
746 fprintf(stderr, "net_init(): out of memory\n");
747 exit(1);
748 }
749
750 memset(net, 0, sizeof(struct net));
751
752 /* Set the back pointer: */
753 net->emul = emul;
754
755 /* Sane defaults: */
756 net->timestamp = 0;
757 net->first_ethernet_packet = net->last_ethernet_packet = NULL;
758
759 #ifdef HAVE_INET_PTON
760 res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4);
761 #else
762 res = inet_aton(ipv4addr, &net->netmask_ipv4);
763 #endif
764 if (res < 1) {
765 fprintf(stderr, "net_init(): could not parse IPv4 address"
766 " '%s'\n", ipv4addr);
767 exit(1);
768 }
769
770 if (netipv4len < 1 || netipv4len > 30) {
771 fprintf(stderr, "net_init(): extremely weird ipv4 "
772 "network length (%i)\n", netipv4len);
773 exit(1);
774 }
775 net->netmask_ipv4_len = netipv4len;
776
777 net->nameserver_known = 0;
778 net->domain_name = "";
779 parse_resolvconf(net);
780
781 /* Distributed network? Then add remote hosts: */
782 if (local_port != 0) {
783 struct sockaddr_in si_self;
784
785 net->local_port = local_port;
786 net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0);
787 if (net->local_port_socket < 0) {
788 perror("socket");
789 exit(1);
790 }
791
792 memset((char *)&si_self, sizeof(si_self), 0);
793 si_self.sin_family = AF_INET;
794 si_self.sin_port = htons(local_port);
795 si_self.sin_addr.s_addr = htonl(INADDR_ANY);
796 if (bind(net->local_port_socket, (struct sockaddr *)&si_self,
797 sizeof(si_self)) < 0) {
798 perror("bind");
799 exit(1);
800 }
801
802 /* Set the socket to non-blocking: */
803 res = fcntl(net->local_port_socket, F_GETFL);
804 fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK);
805 }
806 if (n_remote != 0) {
807 struct remote_net *rnp;
808 while ((n_remote--) != 0) {
809 struct hostent *hp;
810
811 /* debug("adding '%s'\n", remote[n_remote]); */
812 rnp = malloc(sizeof(struct remote_net));
813 memset(rnp, 0, sizeof(struct remote_net));
814
815 rnp->next = net->remote_nets;
816 net->remote_nets = rnp;
817
818 rnp->name = strdup(remote[n_remote]);
819 if (strchr(rnp->name, ':') != NULL)
820 strchr(rnp->name, ':')[0] = '\0';
821
822 hp = gethostbyname(rnp->name);
823 if (hp == NULL) {
824 fprintf(stderr, "could not resolve '%s'\n",
825 rnp->name);
826 exit(1);
827 }
828 memcpy(&rnp->ipv4_addr, hp->h_addr, hp->h_length);
829 free(rnp->name);
830
831 /* And again: */
832 rnp->name = strdup(remote[n_remote]);
833 if (strchr(rnp->name, ':') == NULL) {
834 fprintf(stderr, "Remote network '%s' is not "
835 "'host:portnr'?\n", rnp->name);
836 exit(1);
837 }
838 rnp->portnr = atoi(strchr(rnp->name, ':') + 1);
839 }
840 }
841
842 if (init_flags & NET_INIT_FLAG_GATEWAY)
843 net_gateway_init(net);
844
845 net_dumpinfo(net);
846
847 /* This is necessary when using the real network: */
848 signal(SIGPIPE, SIG_IGN);
849
850 return net;
851 }
852

  ViewVC Help
Powered by ViewVC 1.1.26