/[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 40 - (hide annotations)
Mon Oct 8 16:22:11 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.1539 2007/05/01 04:03:51 debug Exp $
20070415	Landisk PCLOCK should be 33.33 MHz, not 50 MHz. (This makes
		the clock run at correct speed.)
		FINALLY found and fixed the bug which caused OpenBSD/landisk
		to randomly bug out: an &-sign was missing in the special case
		handling of FPSCR in the 'LDS.L @Rm+,FPSCR' instruction.
		Adding similar special case handling for 'LDC.L @Rm+,SR'
		(calling sh_update_sr() instead of just loading).
		Implementing the 'FCNVSD FPUL,DRn' and 'FCNVDS DRm,FPUL'
		SuperH instructions.
		The 'LDC Rm,SR' instruction now immediately breaks out of the
		dyntrans loop if an interrupt is to be triggered.
20070416	In memory_rw.c, if mapping a page as writable, make sure to
		invalidate code translations even if the data access was a
		read.
		Minor SuperH updates.
20070418	Removing the dummy M68K emulation mode.
		Minor SH update (turning unnecessary sts_mach_rn, sts_macl_rn,
		and sts_pr_rn instruction handlers into mov_rm_rn).
20070419	Beginning to add a skeleton for an M88K mode: Adding a hack to
		allow OpenBSD/m88k a.out binaries to be loaded, and disassembly
		of a few simple 88K instructions.
		Commenting out the 'LDC Rm,SR' fix from a few days ago, because
		it made Linux/dreamcast bug out.
		Adding a hack to dev_sh4.c (an extra translation cache
		invalidation), which allows OpenBSD/landisk to boot ok after
		an install. Upgrading the Landisk machine mode to stable,
		updating documentation, etc.
20070420	Experimenting with adding a PCI controller (pcic) to dev_sh4.
		Adding a dummy Realtek 8139C+ skeleton device (dev_rtl8139c).
		Implementing the first M88K instructions (br, or[.u] imm), and
		adding disassembly of some more instructions.
20070421	Continuing a little on dev_rtl8139c.
20070422	Implementing the 9346 EEPROM "read" command for dev_rtl8139c.
		Finally found and fixed an old bug in the log n symbol search
		(it sometimes missed symbols). Debug trace (-i, -t etc) should
		now show more symbols. :-)
20070423	Continuing a little on M88K disassembly.
20070428	Fixing a memset arg order bug in src/net/net.c (thanks to
		Nigel Horne for noticing the bug).
		Applying parts of a patch from Carl van Schaik to clear out
		bottom bits of MIPS addresses more correctly, when using large
		page sizes, and doing some other minor cleanup/refactoring.
		Fixing a couple of warnings given by gcc with the -W option (a
		few more warnings than just plain -Wall).
		Reducing SuperH dyntrans physical address space from 64-bit to
		32-bit (since SH5/SH64 isn't imlemented yet anyway).
		Adding address-to-symbol annotation to a few more instructions
		in the SuperH instruction trace output.
		Beginning regression testing for the next release.
		Reverting the value of SCIF_DELAYED_TX_VALUE from 1 to 2,
		because OpenBSD/landisk may otherwise hang randomly.
20070429	The ugly hack/workaround to get OpenBSD/landisk booting without
		crashing does NOT work anymore (with the April 21 snapshot
		of OpenBSD/landisk). Strangely enough, removing the hack
		completely causes OpenBSD/landisk to work (!).
		More regression testing (re-testing everything SuperH-related,
		and some other things).
		Cobalt interrupts were actually broken; fixing by commenting
		out the DEC21143s in the Cobalt machine.
20070430	More regression testing.
20070501	Updating the OpenBSD/landisk install instructions to use
		4.1 instead of the current snapshot.
		GAAAH! OpenBSD/landisk 4.1 _needs_ the ugly hack/workaround;
		reintroducing it again. (The 4.1 kernel is actually from
		2007-03-11.)
		Simplifying the NetBSD/evbarm install instructions a bit.
		More regression testing.

==============  RELEASE 0.4.5.1  ==============


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 40 * $Id: net.c,v 1.9 2007/04/28 00:10:11 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     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 dpavlin 38
105     /* Gets rid of a compiler warning: */
106     return NULL;
107 dpavlin 32 }
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 dpavlin 40 memset((char *)&si_self, 0, sizeof(si_self));
793 dpavlin 32 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