/[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 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 21819 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26