25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: net.c,v 1.72 2005/03/14 19:14:05 debug Exp $ |
* $Id: net.c,v 1.77 2005/06/26 11:36:28 debug Exp $ |
29 |
* |
* |
30 |
* Emulated (ethernet / internet) network support. |
* Emulated (ethernet / internet) network support. |
31 |
* |
* |
32 |
* |
* |
33 |
* NOTE: This is just an ugly hack, and just barely enough to get some |
* NOTE: This is just an ugly hack, and just barely enough to get some |
34 |
* Internet networking up and running for the guest OS. |
* Internet networking up and running for the guest OS. |
35 |
* |
* |
36 |
* TODO: o) TCP: fin/ack stuff, and connection time-outs and |
* TODO: |
37 |
* connection refused (reset on connect?), resend |
* o) TCP: fin/ack stuff, and connection time-outs and |
38 |
* data to the guest OS if no ack has arrived for |
* connection refused (reset on connect?), resend |
39 |
* some time (? buffers?) |
* data to the guest OS if no ack has arrived for |
40 |
* http://www.tcpipguide.com/free/ |
* some time (? buffers?) |
41 |
* t_TCPConnectionTermination-2.htm |
* http://www.tcpipguide.com/free/t_TCPConnectionTermination-2.htm |
42 |
* o) remove the netbsd-specific options in the tcp header (?) |
* o) remove the netbsd-specific options in the tcp header (?) |
43 |
* o) Outgoing UDP packet fragment support. |
* o) Outgoing UDP packet fragment support. |
44 |
* o) IPv6 (outgoing, incoming, and the nameserver/gateway) |
* o) IPv6 (outgoing, incoming, and the nameserver/gateway) |
45 |
* o) Incoming connections |
* o) Incoming connections |
|
* o) if multiple NICs are connected to the same network, |
|
|
* they should be able to see each other's packets, and |
|
|
* they should have different MAC addresses! |
|
46 |
* |
* |
47 |
|
* TODO 2: The following comments are old! Fix this. |
48 |
* |
* |
49 |
* The emulated NIC has a MAC address of (for example) 10:20:30:40:50:60. |
* |
50 |
|
* The emulated NIC has a MAC address of (for example) 10:20:30:00:00:10. |
51 |
* From the emulated environment, the only other machine existing on the |
* From the emulated environment, the only other machine existing on the |
52 |
* network is a "gateway" or "firewall", which has an address of |
* network is a "gateway" or "firewall", which has an address of |
53 |
* 60:50:40:30:20:10. This module (net.c) contains the emulation of that |
* 60:50:40:30:20:10. This module (net.c) contains the emulation of that |
64 |
* for some other controller. |
* for some other controller. |
65 |
* |
* |
66 |
* |
* |
67 |
* <------------------ a network ------------------------------> |
* |------------------ a network --------------------------------| |
68 |
* ^ ^ ^ |
* ^ ^ ^ |
69 |
* | | | |
* | | | |
70 |
* a NIC connected another NIC the gateway |
* a NIC connected another NIC the gateway |
158 |
y = machine->nr_of_nics; |
y = machine->nr_of_nics; |
159 |
|
|
160 |
/* |
/* |
161 |
* TODO: What is a good starting value? Right now, it looks like this: |
* TODO: What is a good starting value? Something like this? |
162 |
* |
* |
163 |
* +-----------+-------------------+-------------+-------------+ |
* +-----------+-------------------+-------------+-------------+ |
164 |
* | 16 bits | 16 bits machine | 12 bits | 4 bits of | |
* | 16 bits | 16 bits machine | 12 bits | 4 bits of | |
165 |
* | fixed | serial nr | NIC nr(*) | zeroes | |
* | fixed | serial nr | NIC nr(*) | zeroes | |
166 |
* +-----------+-------------------+-------------+-------------+ |
* +-----------+-------------------+-------------+-------------+ |
|
* |
|
|
* (*) = almost |
|
167 |
*/ |
*/ |
168 |
macbuf[0] = 0x10; |
macbuf[0] = 0x10; |
169 |
macbuf[1] = 0x20; |
macbuf[1] = 0x20; |
170 |
macbuf[2] = x >> 8; |
macbuf[2] = 0x30; |
171 |
macbuf[3] = x & 255; |
macbuf[3] = 0; |
172 |
macbuf[4] = y / 15; |
macbuf[4] = 0; |
173 |
macbuf[5] = (y % 15) * 0x10 + 0x10; |
macbuf[5] = machine->serial_nr << 4; |
174 |
|
|
175 |
/* TODO: Remember the mac addresses somewhere? */ |
/* TODO: Remember the mac addresses somewhere? */ |
176 |
machine->nr_of_nics ++; |
machine->nr_of_nics ++; |
1220 |
/* This is a Reply: */ |
/* This is a Reply: */ |
1221 |
lp->data[42] = 0x02; |
lp->data[42] = 0x02; |
1222 |
|
|
1223 |
sprintf(lp->data + 70+16+64, "gxemul"); |
snprintf(lp->data + 70+16+64, 8, "gxemul"); |
1224 |
|
|
1225 |
/* Recalculate IP header checksum: */ |
/* Recalculate IP header checksum: */ |
1226 |
net_ip_checksum(lp->data + 14, 10, 20); |
net_ip_checksum(lp->data + 14, 10, 20); |
1479 |
* generated from the MAC address. :-) |
* generated from the MAC address. :-) |
1480 |
* |
* |
1481 |
* packet+8 points to the client's mac address, |
* packet+8 points to the client's mac address, |
1482 |
* for example 10:20:30:x0:y0:z0, where x,y,z are |
* for example 10:20:30:00:00:z0, where z is 0..15. |
1483 |
* 1..15. |
* 10:20:30:00:00:10 results in 10.0.0.1. |
|
* 10:20:30:10:10:10 results in 10.0.0.1. |
|
1484 |
*/ |
*/ |
1485 |
q = (((packet[8 + 3]) >> 4) - 1); |
/* q = (packet[8 + 3]) >> 4; */ |
1486 |
q = q*15 + (((packet[8 + 4]) >> 4) - 1); |
/* q = q*15 + ((packet[8 + 4]) >> 4); */ |
1487 |
q = q*15 + (((packet[8 + 5]) >> 4) - 1); |
q = (packet[8 + 5]) >> 4; |
1488 |
lp->data[24 + 14] = 10; |
lp->data[24 + 14] = 10; |
1489 |
lp->data[25 + 14] = q / 225; q /= 15; |
lp->data[25 + 14] = 0; |
1490 |
lp->data[26 + 14] = q / 15; q /= 15; |
lp->data[26 + 14] = 0; |
1491 |
lp->data[27 + 14] = q + 1; |
lp->data[27 + 14] = q; |
|
|
|
1492 |
break; |
break; |
1493 |
case 2: /* Reply */ |
case 2: /* Reply */ |
1494 |
case 4: /* Reverse Reply */ |
case 4: /* Reverse Reply */ |
1526 |
return 0; |
return 0; |
1527 |
|
|
1528 |
/* |
/* |
1529 |
|
* If the network is distributed across multiple emulator processes, |
1530 |
|
* then receive incoming packets from those processes. |
1531 |
|
*/ |
1532 |
|
if (net->local_port != 0) { |
1533 |
|
struct sockaddr_in si; |
1534 |
|
socklen_t si_len = sizeof(si); |
1535 |
|
int res, i; |
1536 |
|
unsigned char buf[60000]; |
1537 |
|
|
1538 |
|
if ((res = recvfrom(net->local_port_socket, buf, sizeof(buf), 0, |
1539 |
|
(struct sockaddr *)&si, &si_len)) != -1) { |
1540 |
|
/* fatal("DISTRIBUTED packet, %i bytes from %s:%d\n", |
1541 |
|
res, inet_ntoa(si.sin_addr), ntohs(si.sin_port)); */ |
1542 |
|
for (i=0; i<net->n_nics; i++) { |
1543 |
|
struct ethernet_packet_link *lp; |
1544 |
|
lp = net_allocate_packet_link(net, |
1545 |
|
net->nic_extra[i], res); |
1546 |
|
memcpy(lp->data, buf, res); |
1547 |
|
} |
1548 |
|
} |
1549 |
|
} |
1550 |
|
|
1551 |
|
/* |
1552 |
* UDP: |
* UDP: |
1553 |
*/ |
*/ |
1554 |
for (con_id=0; con_id<MAX_UDP_CONNECTIONS; con_id++) { |
for (con_id=0; con_id<MAX_UDP_CONNECTIONS; con_id++) { |
1930 |
|
|
1931 |
|
|
1932 |
/* |
/* |
1933 |
|
* send_udp(): |
1934 |
|
* |
1935 |
|
* Send a simple UDP packet to some other (real) host. Used for distributed |
1936 |
|
* network simulations. |
1937 |
|
*/ |
1938 |
|
void send_udp(struct in_addr *addrp, int portnr, unsigned char *packet, |
1939 |
|
size_t len) |
1940 |
|
{ |
1941 |
|
int s; |
1942 |
|
struct sockaddr_in si; |
1943 |
|
|
1944 |
|
s = socket(AF_INET, SOCK_DGRAM, 0); |
1945 |
|
if (s < 0) { |
1946 |
|
perror("send_udp(): socket"); |
1947 |
|
return; |
1948 |
|
} |
1949 |
|
|
1950 |
|
/* fatal("send_udp(): sending to port %i\n", portnr); */ |
1951 |
|
|
1952 |
|
si.sin_family = AF_INET; |
1953 |
|
si.sin_addr = *addrp; |
1954 |
|
si.sin_port = htons(portnr); |
1955 |
|
|
1956 |
|
if (sendto(s, packet, len, 0, (struct sockaddr *)&si, |
1957 |
|
sizeof(si)) != len) { |
1958 |
|
perror("send_udp(): sendto"); |
1959 |
|
} |
1960 |
|
|
1961 |
|
close(s); |
1962 |
|
} |
1963 |
|
|
1964 |
|
|
1965 |
|
/* |
1966 |
* net_ethernet_tx(): |
* net_ethernet_tx(): |
1967 |
* |
* |
1968 |
* Transmit an ethernet packet, as seen from the emulated ethernet controller. |
* Transmit an ethernet packet, as seen from the emulated ethernet controller. |
1981 |
if (len < 20) |
if (len < 20) |
1982 |
return; |
return; |
1983 |
|
|
1984 |
/* Copy this packet to all other NICs on this network: */ |
/* |
1985 |
|
* Copy this packet to all other NICs on this network: |
1986 |
|
*/ |
1987 |
if (extra != NULL && net->n_nics > 0) { |
if (extra != NULL && net->n_nics > 0) { |
1988 |
for (i=0; i<net->n_nics; i++) |
for (i=0; i<net->n_nics; i++) |
1989 |
if (extra != net->nic_extra[i]) { |
if (extra != net->nic_extra[i]) { |
1996 |
} |
} |
1997 |
} |
} |
1998 |
|
|
1999 |
|
/* |
2000 |
|
* If this network is distributed across multiple emulator processes, |
2001 |
|
* then transmit the packet to those other processes. |
2002 |
|
*/ |
2003 |
|
if (net->remote_nets != NULL) { |
2004 |
|
struct remote_net *rnp = net->remote_nets; |
2005 |
|
while (rnp != NULL) { |
2006 |
|
send_udp(&rnp->ipv4_addr, rnp->portnr, packet, len); |
2007 |
|
rnp = rnp->next; |
2008 |
|
} |
2009 |
|
} |
2010 |
|
|
2011 |
/* Drop packets that are not destined for the gateway: */ |
/* Drop packets that are not destined for the gateway: */ |
2012 |
if (memcmp(packet, net->gateway_ethernet_addr, 6) != 0 |
if (memcmp(packet, net->gateway_ethernet_addr, 6) != 0 |
2013 |
&& packet[0] != 0xff && packet[0] != 0x00) |
&& packet[0] != 0xff && packet[0] != 0x00) |
2014 |
return; |
return; |
2015 |
|
|
2016 |
|
/* |
2017 |
|
* The code below simulates the behaviour of a "NAT"-style |
2018 |
|
* gateway. |
2019 |
|
*/ |
2020 |
#if 0 |
#if 0 |
2021 |
fatal("[ net: ethernet: "); |
fatal("[ net: ethernet: "); |
2022 |
for (i=0; i<6; i++) |
for (i=0; i<6; i++) fatal("%02x", packet[i]); fatal(" "); |
2023 |
fatal("%02x", packet[i]); |
for (i=6; i<12; i++) fatal("%02x", packet[i]); fatal(" "); |
2024 |
fatal(" "); |
for (i=12; i<14; i++) fatal("%02x", packet[i]); fatal(" "); |
2025 |
for (i=6; i<12; i++) |
for (i=14; i<len; i++) fatal("%02x", packet[i]); fatal(" ]\n"); |
|
fatal("%02x", packet[i]); |
|
|
fatal(" "); |
|
|
for (i=12; i<14; i++) |
|
|
fatal("%02x", packet[i]); |
|
|
fatal(" "); |
|
|
for (i=14; i<len; i++) |
|
|
fatal("%02x", packet[i]); |
|
|
fatal(" ]\n"); |
|
2026 |
#endif |
#endif |
2027 |
|
|
2028 |
/* Sprite: */ |
/* Sprite: */ |
2252 |
void net_dumpinfo(struct net *net) |
void net_dumpinfo(struct net *net) |
2253 |
{ |
{ |
2254 |
int iadd = 4; |
int iadd = 4; |
2255 |
|
struct remote_net *rnp; |
2256 |
|
|
2257 |
debug("net: "); |
debug("net: "); |
2258 |
|
|
2282 |
debug("\n"); |
debug("\n"); |
2283 |
debug_indentation(-iadd); |
debug_indentation(-iadd); |
2284 |
|
|
2285 |
|
rnp = net->remote_nets; |
2286 |
|
if (rnp != NULL) |
2287 |
|
debug("distributed network: other hosts:\n"); |
2288 |
|
|
2289 |
|
debug_indentation(iadd); |
2290 |
|
while (rnp != NULL) { |
2291 |
|
debug("\"%s\": ", rnp->name); |
2292 |
|
net_debugaddr(&rnp->ipv4_addr, ADDR_IPV4); |
2293 |
|
debug(" port %i\n", rnp->portnr); |
2294 |
|
rnp = rnp->next; |
2295 |
|
} |
2296 |
|
debug_indentation(-iadd); |
2297 |
|
|
2298 |
|
if (net->local_port != 0) |
2299 |
|
debug("distributed network: local port = %i\n", |
2300 |
|
net->local_port); |
2301 |
|
|
2302 |
debug_indentation(-iadd); |
debug_indentation(-iadd); |
2303 |
} |
} |
2304 |
|
|
2307 |
* net_init(): |
* net_init(): |
2308 |
* |
* |
2309 |
* This function creates a network, and returns a pointer to it. |
* This function creates a network, and returns a pointer to it. |
2310 |
* Example: ipv4addr should be something like "10.0.0.0", netipv4len = 8. |
* ipv4addr should be something like "10.0.0.0", netipv4len = 8. |
2311 |
|
* If n_remote is more than zero, remote should be a pointer to an array |
2312 |
|
* of strings of the following format: "host:portnr". |
2313 |
* |
* |
2314 |
* (On failure, exit() is called.) |
* On failure, exit() is called. |
2315 |
*/ |
*/ |
2316 |
struct net *net_init(struct emul *emul, int init_flags, |
struct net *net_init(struct emul *emul, int init_flags, |
2317 |
char *ipv4addr, int netipv4len) |
char *ipv4addr, int netipv4len, char **remote, int n_remote, |
2318 |
|
int local_port) |
2319 |
{ |
{ |
2320 |
struct net *net; |
struct net *net; |
2321 |
int res; |
int res; |
2357 |
net->domain_name = ""; |
net->domain_name = ""; |
2358 |
parse_resolvconf(net); |
parse_resolvconf(net); |
2359 |
|
|
2360 |
|
/* Distributed network? Then add remote hosts: */ |
2361 |
|
if (local_port != 0) { |
2362 |
|
struct sockaddr_in si_self; |
2363 |
|
|
2364 |
|
net->local_port = local_port; |
2365 |
|
net->local_port_socket = socket(AF_INET, SOCK_DGRAM, 0); |
2366 |
|
if (net->local_port_socket < 0) { |
2367 |
|
perror("socket"); |
2368 |
|
exit(1); |
2369 |
|
} |
2370 |
|
|
2371 |
|
memset((char *)&si_self, sizeof(si_self), 0); |
2372 |
|
si_self.sin_family = AF_INET; |
2373 |
|
si_self.sin_port = htons(local_port); |
2374 |
|
si_self.sin_addr.s_addr = htonl(INADDR_ANY); |
2375 |
|
if (bind(net->local_port_socket, (struct sockaddr *)&si_self, |
2376 |
|
sizeof(si_self)) < 0) { |
2377 |
|
perror("bind"); |
2378 |
|
exit(1); |
2379 |
|
} |
2380 |
|
|
2381 |
|
/* Set the socket to non-blocking: */ |
2382 |
|
res = fcntl(net->local_port_socket, F_GETFL); |
2383 |
|
fcntl(net->local_port_socket, F_SETFL, res | O_NONBLOCK); |
2384 |
|
} |
2385 |
|
if (n_remote != 0) { |
2386 |
|
struct remote_net *rnp; |
2387 |
|
while ((n_remote--) != 0) { |
2388 |
|
/* debug("adding '%s'\n", remote[n_remote]); */ |
2389 |
|
rnp = malloc(sizeof(struct remote_net)); |
2390 |
|
memset(rnp, 0, sizeof(struct remote_net)); |
2391 |
|
|
2392 |
|
rnp->next = net->remote_nets; |
2393 |
|
net->remote_nets = rnp; |
2394 |
|
|
2395 |
|
rnp->name = strdup(remote[n_remote]); |
2396 |
|
if (strchr(rnp->name, ':') != NULL) |
2397 |
|
strchr(rnp->name, ':')[0] = '\0'; |
2398 |
|
/* TODO: Name resolution? */ |
2399 |
|
#ifdef HAVE_INET_PTON |
2400 |
|
res = inet_pton(AF_INET, rnp->name, &rnp->ipv4_addr); |
2401 |
|
#else |
2402 |
|
res = inet_aton(rnp->name, &rnp->ipv4_addr); |
2403 |
|
#endif |
2404 |
|
free(rnp->name); |
2405 |
|
/* And again: */ |
2406 |
|
rnp->name = strdup(remote[n_remote]); |
2407 |
|
if (strchr(rnp->name, ':') == NULL) { |
2408 |
|
fprintf(stderr, "Remote network '%s' is not " |
2409 |
|
"'host:portnr'?\n", rnp->name); |
2410 |
|
exit(1); |
2411 |
|
} |
2412 |
|
rnp->portnr = atoi(strchr(rnp->name, ':') + 1); |
2413 |
|
} |
2414 |
|
} |
2415 |
|
|
2416 |
if (init_flags & NET_INIT_FLAG_GATEWAY) |
if (init_flags & NET_INIT_FLAG_GATEWAY) |
2417 |
net_gateway_init(net); |
net_gateway_init(net); |
2418 |
|
|