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

Annotation of /trunk/src/net/net.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 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 dpavlin 32 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 32 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 44 * $Id: net.c,v 1.12 2007/08/25 22:27:28 debug Exp $
29 dpavlin 32 *
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 dpavlin 42 CHECK_ALLOCATION(lp = malloc(sizeof(struct ethernet_packet_link)));
80 dpavlin 32
81     lp->len = len;
82     lp->extra = extra;
83 dpavlin 42 CHECK_ALLOCATION(lp->data = malloc(len));
84 dpavlin 32
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 dpavlin 42 CHECK_ALLOCATION(net->domain_name = strdup(buf+start));
588 dpavlin 32 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 dpavlin 42 CHECK_ALLOCATION(net->nic_extra = realloc(net->nic_extra, sizeof(void *)
611     * net->n_nics));
612 dpavlin 32
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 dpavlin 44 debug("net:\n");
662 dpavlin 32
663 dpavlin 44 debug_indentation(iadd);
664    
665     debug("simulated network: ");
666 dpavlin 32 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 dpavlin 44 debug("simulated gateway+nameserver: ");
673 dpavlin 32 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 dpavlin 44 debug("(could not determine nameserver)\n");
680 dpavlin 32 } else {
681 dpavlin 44 debug("simulated nameserver uses real nameserver ");
682 dpavlin 32 net_debugaddr(&net->nameserver_ipv4, NET_ADDR_IPV4);
683 dpavlin 44 debug("\n");
684 dpavlin 32 }
685 dpavlin 44
686 dpavlin 32 if (net->domain_name != NULL && net->domain_name[0])
687 dpavlin 44 debug("domain: %s\n", net->domain_name);
688 dpavlin 32
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 dpavlin 42 CHECK_ALLOCATION(net = malloc(sizeof(struct net)));
730 dpavlin 32 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 dpavlin 40 memset((char *)&si_self, 0, sizeof(si_self));
773 dpavlin 32 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 dpavlin 42 CHECK_ALLOCATION(rnp =
793     malloc(sizeof(struct remote_net)));
794 dpavlin 32 memset(rnp, 0, sizeof(struct remote_net));
795    
796     rnp->next = net->remote_nets;
797     net->remote_nets = rnp;
798    
799 dpavlin 42 CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote]));
800 dpavlin 32 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 dpavlin 42 CHECK_ALLOCATION(rnp->name = strdup(remote[n_remote]));
814 dpavlin 32 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