"gerry" == gerry <gerry77 at mail.com> writes:
gerry> Really, we [1] had some problems with fragmented UDP packets,
gerry> mostly due to some cheap IP routers bundled with local ADSL
gerry> connections. Many of them seem to be unable to correctly
gerry> manage UDP fragments and/or have memory leaks which in the end
gerry> cause lockups and other nasty things after some DECnet-in-UDP
gerry> traffic has passed thru them. In at least one case, the
gerry> problem was even nailed down to some ISP apparatus sitting
gerry> between two remote bridges of ours.
Yikes.
gerry> We still do not know how these UDP related problems would/will
gerry> impact other protocols like LAT, LAD/LAST and MOP because we
gerry> haven't experimented so much as with pure DECnet. Any
gerry> contribution and suggestions on how to force reduced frame
gerry> size for those protocols would be much appreciated. :-)
I can't think of any. The general rule at DEC was that some basic
level of design competence was assumed. Getting the Ethernet frame
size right was certainly part of the basic IQ test.
The only solution I can think of is to reduce the MTU of your local
Ethernet on the machine doing the UDP encapsulation. That would force
the packets to be fragmented at origination time, which means your
defective routers will see small-enough packets.
paul
I still prefer EDT. :-)
(Well, unless I have some Emacs around...)
Johnny
Steve Davidson wrote:
Close...
You will need to use SYS$MANAGER:NETCONFIG.COM. Afterwards, assuming a reasonably current version of VMS (the Open is silent :-)), you modify SYS$MANAGER:SYSTARTUP_VMS.COM to enable SYS$MANAGER:STARTNET.COM - just remove the comment. In these cases, SYS$MANAGER actually resolves to SYS$COMMON:[SYSMGR] but you'll see that. This is a chance to get reacquainted to your old friend EDT, or use the "new" kid on the block - TPU. The only reason I plugged EDT is once upon a time I was the project leader...
-Steve
-----Original Message-----
From: owner-hecnet at Update.UU.SE [mailto:owner-hecnet at Update.UU.SE] On Behalf Of Kari Uusim ki
Sent: Friday, February 27, 2009 00:38
To: hecnet at Update.UU.SE
Subject: Re: [HECnet] What use are *you* making of HECnet?
Johnny Billquist wrote:
Jason Stevens wrote:
I see... yeah I have a VMS image, but really no idea how to setup it's
networking... I 'used' VMS as a user ages ago, although it was mostly
using EDT and fighting the gold key thing on terminals....
Anyways is there some online docs on setting up VMS's networking? I'd
love to be able to dig deeper into this....
The good thing is that playing around like this is really the best way of learning. And I think you should play more. I might be wrong, so don't take anything I write as the gospel. :-)
As for docs... Well, the full documentation for VMS is available online at HP, if you can live with fairly recent documentation.
But I seem to remember that it wasn't that difficult to get it running. I think there is a script you run to set things up, and after you've run that, you're basically set.
Quite right. Setting DECnet (Phase IV) up on a VMS machine is really simple. You have to decide your DECnet address and whether your machine is an end node or a router (L1 or L2). The script will ask all the necessary questions. You run it as follows:
$ @netconfigure.com
Further on you'll start it by running:
$ @startnet.com
Kari
But I know I'm very vague here. Better to wait for someone else to answer, perhaps. I know myself around VMS, and have been working with it on and off for over 20 years, but I'm really more familiar with RSX these days, and have to experiment a bit every time I set down with VMS before I remember how you're supposed to do it there. :-)
Johnny
--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol
Close...
You will need to use SYS$MANAGER:NETCONFIG.COM. Afterwards, assuming a reasonably current version of VMS (the Open is silent :-)), you modify SYS$MANAGER:SYSTARTUP_VMS.COM to enable SYS$MANAGER:STARTNET.COM - just remove the comment. In these cases, SYS$MANAGER actually resolves to SYS$COMMON:[SYSMGR] but you'll see that. This is a chance to get reacquainted to your old friend EDT, or use the "new" kid on the block - TPU. The only reason I plugged EDT is once upon a time I was the project leader...
-Steve
-----Original Message-----
From: owner-hecnet at Update.UU.SE [mailto:owner-hecnet at Update.UU.SE] On Behalf Of Kari Uusim ki
Sent: Friday, February 27, 2009 00:38
To: hecnet at Update.UU.SE
Subject: Re: [HECnet] What use are *you* making of HECnet?
Johnny Billquist wrote:
Jason Stevens wrote:
I see... yeah I have a VMS image, but really no idea how to setup it's
networking... I 'used' VMS as a user ages ago, although it was mostly
using EDT and fighting the gold key thing on terminals....
Anyways is there some online docs on setting up VMS's networking? I'd
love to be able to dig deeper into this....
The good thing is that playing around like this is really the best way
of learning. And I think you should play more. I might be wrong, so
don't take anything I write as the gospel. :-)
As for docs... Well, the full documentation for VMS is available online
at HP, if you can live with fairly recent documentation.
But I seem to remember that it wasn't that difficult to get it running.
I think there is a script you run to set things up, and after you've run
that, you're basically set.
Quite right. Setting DECnet (Phase IV) up on a VMS machine is really
simple. You have to decide your DECnet address and whether your machine
is an end node or a router (L1 or L2). The script will ask all the
necessary questions. You run it as follows:
$ @netconfigure.com
Further on you'll start it by running:
$ @startnet.com
Kari
But I know I'm very vague here. Better to wait for someone else to
answer, perhaps. I know myself around VMS, and have been working with it
on and off for over 20 years, but I'm really more familiar with RSX
these days, and have to experiment a bit every time I set down with VMS
before I remember how you're supposed to do it there. :-)
Johnny
On Thu, 26 Feb 2009 14:19:35 +0100, you wrote:
As for fragmentation... Now I assume you are talking about the
encapsulation of ethernet packets in UDP packets. Those will be a bit
larger still, and will almost certainly be fragmented when sent over the
internet, yes. I don't see a problem with that. Do you?
Really, we [1] had some problems with fragmented UDP packets, mostly due to
some cheap IP routers bundled with local ADSL connections. Many of them seem
to be unable to correctly manage UDP fragments and/or have memory leaks which
in the end cause lockups and other nasty things after some DECnet-in-UDP
traffic has passed thru them. In at least one case, the problem was even
nailed down to some ISP apparatus sitting between two remote bridges of ours.
The most common symptom is a working connection (as long as it's used only for
interactive light traffic such as CTERM) which hangs when used for bulk data
transfers like file COPY. In one specific case, a system with a very complex
announce text (the one shown before login) was actually unreachable because
the contents of the announce were so large that they caused a fragmented UDP
packet to be sent, leading to a SET HOST hang without "Username:" prompt.
Our solution was to reduce the overall size of DECnet packets.
This is for the actual live DECnet (not permanent across network restarts):
$ MCR NCP SET CIRC SVA-0 STATE OFF
$ MCR NCP SET LINE SVA-0 STATE OFF
$ MCR NCP SET LINE SVA-0 BUFF SIZE 1456
$ MCR NCP SET LINE SVA-0 STATE ON
$ MCR NCP SET CIRC SVA-0 STATE ON
This to make it a permanent change:
$ MCR NCP DEF LINE SVA-0 BUFF SIZE 1456
The actual line/circuit name (SVA-0 in the above examples) can be seen with:
$ MCR NCP SHOW KNOWN LINE
$ MCR NCP SHOW KNOWN CIRC
The 1456 bytes value was chosen (after some trial-and-error with tcpdump) so
to have 1492 bytes long UDP packets, which is exactly the local MTU of our
ADSL links. One of us had to trim even more its buffer size, down to 1428. We
don't know why, but that was the biggest size he could use without incurring
in DECnet link hangs. The latter appears to be a ISP-side problem with UDP.
We still do not know how these UDP related problems would/will impact other
protocols like LAT, LAD/LAST and MOP because we haven't experimented so much
as with pure DECnet. Any contribution and suggestions on how to force reduced
frame size for those protocols would be much appreciated. :-)
Hope this helps,
G.
[1] http://decnet.ipv7.net/
Johnny Billquist wrote:
Jason Stevens wrote:
I see... yeah I have a VMS image, but really no idea how to setup it's
networking... I 'used' VMS as a user ages ago, although it was mostly
using EDT and fighting the gold key thing on terminals....
Anyways is there some online docs on setting up VMS's networking? I'd
love to be able to dig deeper into this....
The good thing is that playing around like this is really the best way of learning. And I think you should play more. I might be wrong, so don't take anything I write as the gospel. :-)
As for docs... Well, the full documentation for VMS is available online at HP, if you can live with fairly recent documentation.
But I seem to remember that it wasn't that difficult to get it running. I think there is a script you run to set things up, and after you've run that, you're basically set.
Quite right. Setting DECnet (Phase IV) up on a VMS machine is really simple. You have to decide your DECnet address and whether your machine is an end node or a router (L1 or L2). The script will ask all the necessary questions. You run it as follows:
$ @netconfigure.com
Further on you'll start it by running:
$ @startnet.com
Kari
But I know I'm very vague here. Better to wait for someone else to answer, perhaps. I know myself around VMS, and have been working with it on and off for over 20 years, but I'm really more familiar with RSX these days, and have to experiment a bit every time I set down with VMS before I remember how you're supposed to do it there. :-)
Johnny
On Fri, 27 Feb 2009, Johnny Billquist wrote:
But I seem to remember that it wasn't that difficult to get it running. I think there is a script you run to set things up, and after you've run that, you're basically set.
I think the Hobbyist site has a couple doc's, one for VAX and one for Alpha. Really it's a piece of cake. I find a VMS install to typically be easier
than a Windows install.
But I know I'm very vague here. Better to wait for someone else to answer, perhaps. I know myself around VMS, and have been working with it on and off for over 20 years, but I'm really more familiar with RSX these days, and have to experiment a bit every time I set down with VMS before I remember how you're supposed to do it there. :-)
I assume the OP is planning on using SIMH? Other questions would revolve
around what version of VMS he has. Depending on the time of install kit, it
may or may not include the networking install kits. One such example is the
Hobbyist V1 CD-ROM, which does not include DECnet or UCX (TCP/IP) install
kits.
Zane
Jason Stevens wrote:
I see... yeah I have a VMS image, but really no idea how to setup it's
networking... I 'used' VMS as a user ages ago, although it was mostly
using EDT and fighting the gold key thing on terminals....
Anyways is there some online docs on setting up VMS's networking? I'd
love to be able to dig deeper into this....
The good thing is that playing around like this is really the best way of learning. And I think you should play more. I might be wrong, so don't take anything I write as the gospel. :-)
As for docs... Well, the full documentation for VMS is available online at HP, if you can live with fairly recent documentation.
But I seem to remember that it wasn't that difficult to get it running. I think there is a script you run to set things up, and after you've run that, you're basically set.
But I know I'm very vague here. Better to wait for someone else to answer, perhaps. I know myself around VMS, and have been working with it on and off for over 20 years, but I'm really more familiar with RSX these days, and have to experiment a bit every time I set down with VMS before I remember how you're supposed to do it there. :-)
Johnny
--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol
TCP/IP don't care about the source MAC address. And destination MAC address
is just used to make the packet end up at the right destination, without any
other meaning to it. And the mapping between destination IP address and MAC
address is solved by ARP. And several different IP addresses can use the
same MAC address. Exactly how that MAC address looks like isn't an issue
either. So, for TCP/IP, everything will work fine if you just use the actual
MAC address the card have, even though you might be doing traffic both from
the host, and from a simulator within the host. Reception is a bit worse,
since you need to figure out if the received packet should go to the host or
the simulator.
DECnet works in a very different way, where each host *must* have a unique
MAC address, and where the recipient really checks that the source MAC
address is consistent with what was expected, or else the packet is dropped
(yes, I'm writing and meaning source address here). And sending data is done
to a specific MAC address without ARP. Instead the MAC address is calculated
from the DECnet address, and is thus "known" already. For all hosts on the
network.
Believe me. You are not really seeing or understanding the problem yet, with
the tests you are doing.
Parts are things you need to read up on, on how DECnet works. And parts
you'll only find out the hard way, as I did. :-)
Johnny
--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol
I see... yeah I have a VMS image, but really no idea how to setup it's
networking... I 'used' VMS as a user ages ago, although it was mostly
using EDT and fighting the gold key thing on terminals....
Anyways is there some online docs on setting up VMS's networking? I'd
love to be able to dig deeper into this....
Jason Stevens wrote:
Well, normally libpcap is used to recieve packets, so it don't neccesarily
help with sending them.
Second, sending packets is one thing, sending packets with a "fake" source
MAC address is yet another thing (as a short note, the DEUNA and DELUA
ethernet controllers for the Unibus can never do this. They set the source
MAC address from the controller, no matter what you place in the packet you
want to send).
But please report if you have success with this.
This is what i'm using right now to have two versions of SIMH send
pings to eachother... I added the tcp/ip stuff, and removed all of
the libpcap parts of the code.. I also noticed it uses blocking
sockets so it'll get 'stuck' from time to time reading stuff. I
started work on porting it to windows but I've been away on vacation
so it didn't get any work done...
"ping" sortof implies that you are talking tcp/ip. If so, the test is meaningless.
TCP/IP don't care about the source MAC address. And destination MAC address is just used to make the packet end up at the right destination, without any other meaning to it. And the mapping between destination IP address and MAC address is solved by ARP. And several different IP addresses can use the same MAC address. Exactly how that MAC address looks like isn't an issue either. So, for TCP/IP, everything will work fine if you just use the actual MAC address the card have, even though you might be doing traffic both from the host, and from a simulator within the host. Reception is a bit worse, since you need to figure out if the received packet should go to the host or the simulator.
DECnet works in a very different way, where each host *must* have a unique MAC address, and where the recipient really checks that the source MAC address is consistent with what was expected, or else the packet is dropped (yes, I'm writing and meaning source address here). And sending data is done to a specific MAC address without ARP. Instead the MAC address is calculated from the DECnet address, and is thus "known" already. For all hosts on the network.
Believe me. You are not really seeing or understanding the problem yet, with the tests you are doing.
Parts are things you need to read up on, on how DECnet works. And parts you'll only find out the hard way, as I did. :-)
Johnny
--
Johnny Billquist || "I'm on a bus
|| on a psychedelic trip
email: bqt at softjar.se || Reading murder books
pdp is alive! || tryin' to stay hip" - B. Idol
Well, normally libpcap is used to recieve packets, so it don't neccesarily
help with sending them.
Second, sending packets is one thing, sending packets with a "fake" source
MAC address is yet another thing (as a short note, the DEUNA and DELUA
ethernet controllers for the Unibus can never do this. They set the source
MAC address from the controller, no matter what you place in the packet you
want to send).
But please report if you have success with this.
This is what i'm using right now to have two versions of SIMH send
pings to eachother... I added the tcp/ip stuff, and removed all of
the libpcap parts of the code.. I also noticed it uses blocking
sockets so it'll get 'stuck' from time to time reading stuff. I
started work on porting it to windows but I've been away on vacation
so it didn't get any work done...
Hopefully gmail doesn't screw the formatting up too badly.
---8<---8<---8<---8<---8<---8<---8<---8<---8<---8<
/* A simple DECnet bridge program
* (c) 2003, 2005 by Johnny Billquist
* Version 2.1 Fixed code for OpenBSD and FreeBSD as well.
* Version 2.0 (I had to start using a version number sometime, and
* since I don't have any clue to the history of my
* development here, I just picked 2.0 because I liked
* it.)
* Some more text will come here later. */
#define DEBUG 0
#define MAX_HOST 16
#define CONF_FILE "bridge.conf"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#include <string.h>
/* Throttling control:
* THROTTLETIME - (mS)
* If packets come closer in time than this, they are
* a base for perhaps considering throttling.
* THROTTLEPKT - (#)
* The number of packets in sequence that fulfill
* THROTTLETIME that means throttling will kick in.
* THROTTLEDELAY - (uS)
* The delay to insert when throttling is active.
*
* Passive connection control:
* PASSIVE_TMO - (mS)
* If nothing has been received from a passive node
* in this time, sending to it will stop.
*/
#define THROTTLETIME 5
#define THROTTLEPKT 4
#define THROTTLEDELAY 10
#define PASSIVE_TMO 180000L
#define THROTTLEMASK ((1 << THROTTLEPKT) - 1)
#define ETHERTYPE_DECnet 0x6003
#define ETHERTYPE_LAT 0x6004
#define ETHERTYPE_MOPDL 0x6001
#define ETHERTYPE_MOPRC 0x6002
#define ETHERTYPE_IP 0x0800
#define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_REVARP 0x8035
#define MAX(a,b) (a>b?a:b)
/* The structures and other global data we keep info in.
It would perhaps be nice if we could reload this, and
in case of failure keep the old stuff, but for now we
don't care that much... */
/* The data structures we have are the port, which describe
a source/destination for data. It also holds info about which
kind of traffic should be forwarded to this site. It is also
used to filter incoming packets. If we don't send something, we
don't want it from that side either.
We have the host table, which is a hash table for all known
destinations, so that we can optimize the traffic a bit.
When data arrives, we filter, process and send it out again.
*/
typedef enum {DECnet, LAT, IP} pkttyp;
#define MAXTYP 3
struct BRIDGE {
char name[40];
char host[80];
in_addr_t addr;
short port;
int passive;
int fd;
int types[MAXTYP];
char last[8][14];
int lastptr;
int rcount;
int tcount;
int xcount;
struct timeval lasttime;
int throttle;
int throttlecount;
struct timeval lastrcv;
};
struct DATA {
int source;
pkttyp type;
int len;
const char *data;
};
struct HOST {
struct HOST *next;
unsigned char mac[6];
int bridge;
};
#define HOST_HASH 65536
struct HOST *hosts[HOST_HASH];
struct BRIDGE bridge[MAX_HOST];
int bcnt = 0;
int sd;
/* Here come the code... */
int lookup(struct sockaddr_in *sa, char *data)
{
int i;
for (i=0; i<bcnt; i++) {
if ((bridge[i].addr == sa->sin_addr.s_addr) &&
(bridge[i].port == sa->sin_port))
return i;
}
return -1;
}
int lookup_bridge(char *newbridge)
{
int i;
int l = strlen(newbridge);
#if DEBUG
printf("Trying to match %s\n", newbridge);
#endif
for (i=0; i<bcnt; i++) {
#if DEBUG
printf("Matching against: %s\n", bridge[i].name);
#endif
if ((strcmp(newbridge,bridge[i].name) == 0) &&
(l == strlen(bridge[i].name))) {
#if DEBUG
printf("Found match: %s == %s\n", newbridge, bridge[i].name);
#endif
return i;
}
}
#if DEBUG
printf("No match found\n");
#endif
return -1;
}
void add_bridge(char *name, char *dst)
{
struct hostent *he;
char rhost[40];
int port;
int i,found=0;
in_addr_t addr;
char *p;
int passive = 0;
if (bcnt < MAX_HOST) {
bzero(&bridge[bcnt],sizeof(struct BRIDGE));
if (*name == '~') {
passive = 1;
name++;
}
strcpy(bridge[bcnt].name,name);
p = strchr(dst,':');
if (p == NULL) { /* Assume local descriptor */
found = -1;
} else {
*p = ' ';
sscanf(dst,"%s %d", rhost, &port);
if ((he = gethostbyname(rhost)) != NULL) {
addr = *(in_addr_t *)he->h_addr;
found = -1;
} else {
found = inet_aton(rhost,&addr);
}
if (found) {
strcpy(bridge[bcnt].host,rhost);
bridge[bcnt].addr = addr;
bridge[bcnt].port = htons(port);
bridge[bcnt].fd = sd;
}
}
if (found) {
for (i=0; i<MAXTYP; i++) bridge[bcnt].types[i] = 0;
bridge[bcnt].rcount = 0;
bridge[bcnt].tcount = 0;
bridge[bcnt].passive = passive;
bcnt++;
#if DEBUG
printf("Adding router ''%s''. %08x:%d\n", name, addr, port);
#endif
}
} else {
printf("Warning. Bridge table full. Not adding %d (%d)\n", name, dst);
}
}
int add_service(char *newbridge, pkttyp type, char *name)
{
int i;
#if DEBUG
printf("Adding %s bridge %s.\n", name, newbridge);
#endif
if ((i = lookup_bridge(newbridge)) >= 0) {
if (bridge[i].types[type]++ > 0) {
printf("%s bridge %s added multiple times.\n", name, bridge);
}
return 1;
}
return 0;
}
void read_conf()
{
FILE *f;
int mode = 0;
int area,node;
int line;
char buf[80];
char buf1[40],buf2[40];
int i;
if ((f = fopen(CONF_FILE,"r")) == NULL) {
perror("opening bridge.conf");
exit(1);
}
for (i=0; i<bcnt; i++) {
if (bridge[i].fd != sd) close(bridge[i].fd);
}
bcnt = 0;
for (i=0; i<HOST_HASH; i++) {
struct HOST *h, *n;
h = hosts[i];
hosts[i] = NULL;
while(h) {
n = h->next;
free(h);
h = n;
}
}
line = 0;
while (!feof(f)) {
if (fgets(buf,80,f) == NULL) continue;
buf[strlen(buf)-1] = 0;
line++;
if((strlen(buf) > 2) && (buf[0] != '!')) {
if(buf[0]=='[') {
mode = -1;
if(strcmp(buf,"[bridge]") == 0) mode = 0;
if(strcmp(buf,"[decnet]") == 0) mode = 1;
if(strcmp(buf,"[lat]") == 0) mode = 2;
if(sscanf(buf,"[source %d.%d]", &area, &node) == 2) mode = 3;
if(strcmp(buf,"[relay]") == 0) mode = 4;
if(strcmp(buf,"[ip]") == 0) mode = 5;
if(mode < 0) {
printf("Bad configuration at line %d\n%s\n", line,buf);
exit(1);
}
} else {
switch (mode) {
case 0:
if (sscanf(buf, "%s %s", buf1, buf2) == 2) {
add_bridge(buf1,buf2);
} else {
printf("Bad bridge at line %d\n%s\n", line, buf);
exit(1);
}
break;
case 1:
if (!add_service(buf,DECnet,"DECnet"))
printf("%d: DECnet bridge %s don't exist.\n", line, buf);
break;
case 2:
if (!add_service(buf,LAT,"LAT"))
printf("%d: LAT bridge %s don't exist.\n", line, buf);
break;
case 3:
break;
case 4:
break;
case 5:
if (!add_service(buf,IP,"IP"))
printf("%d: IP bridge %s don't exist.\n", line, buf);
break;
default:
printf("weird state at line %d\n",line);
exit(1);
}
}
}
}
fclose(f);
}
int is_ethertype(struct DATA *d, int type)
{
return ((d->data[13] == (type & 0xff)) &&
(d->data[12] == (type >> 8)));
}
int is_decnet(struct DATA *data)
{
return is_ethertype(data, ETHERTYPE_DECnet);
}
int is_lat(struct DATA *data)
{
return (is_ethertype(data, ETHERTYPE_LAT) ||
is_ethertype(data, ETHERTYPE_MOPDL) ||
is_ethertype(data, ETHERTYPE_MOPRC));
}
int is_ip(struct DATA *data)
{
return (is_ethertype(data, ETHERTYPE_IP) ||
is_ethertype(data, ETHERTYPE_ARP) ||
is_ethertype(data, ETHERTYPE_REVARP));
}
unsigned long timedelta(struct timeval old)
{
struct timeval now;
unsigned long delta;
gettimeofday(&now, NULL);
delta = now.tv_sec - old.tv_sec;
delta *= 1000;
delta += ((now.tv_usec - old.tv_usec) / 1000);
return delta;
}
void throttle(int index)
{
long delta;
delta = timedelta(bridge[index].lasttime);
bridge[index].throttle <<= 1;
bridge[index].throttle += (delta < THROTTLETIME ? 1 : 0);
if ((bridge[index].throttle & THROTTLEMASK) == THROTTLEMASK) {
bridge[index].throttlecount++;
usleep(THROTTLEDELAY);
}
gettimeofday(&bridge[index].lasttime,NULL);
}
int active(int index)
{
if (bridge[index].passive == 0) return 1;
if (timedelta(bridge[index].lastrcv) < PASSIVE_TMO) return 1;
return 0;
}
/* do the actual sending */
void send_packet(int index, struct DATA *d)
{
struct sockaddr_in sa;
if (index == d->source) return; /* Avoid loopback of data. */
if (bridge[index].types[d->type] == 0) return; /* Avoid sending
unwanted frames */
if (active(index)) {
bridge[index].tcount++;
throttle(index);
if (bridge[index].addr == 0) {
write(bridge[index].fd,d->data,d->len); /* Local network. */
} else {
sa.sin_family = AF_INET; /* Remote network. */
sa.sin_port = bridge[index].port;
sa.sin_addr.s_addr = bridge[index].addr;
if (sendto(bridge[index].fd,d->data,d->len,0,(struct sockaddr
*)&sa,sizeof(sa)) == -1)
perror("sendto");
}
bridge[index].lastptr = (bridge[index].lastptr+1) & 7;
memcpy(bridge[index].last[bridge[index].lastptr],d->data,14);
}
}
void register_source(struct DATA *d)
{
unsigned short hash;
struct HOST *h;
hash = *(unsigned short *)(d->data+10);
h = hosts[hash];
while (h) {
if (memcmp(h->mac, d->data+6, 6) == 0) {
h->bridge = d->source;
#if DEBUG
printf("Setting existing hash to bridge %d\n", h->bridge);
#endif
return;
}
h = h->next;
}
h = malloc(sizeof(struct HOST));
h->next = hosts[hash];
memcpy(h->mac,d->data+6,6);
h->bridge = d->source;
#if DEBUG
printf("Adding new hash entry. Port is %d\n", h->bridge);
#endif
hosts[hash] = h;
}
int locate_dest(struct DATA *d)
{
unsigned short hash;
struct HOST *h;
if (d->data[0] & 1) return -1; /* Ethernet multicast */
hash = *(unsigned short *)(d->data+4);
h = hosts[hash];
while (h) {
if (memcmp(h->mac, d->data, 6) == 0) return h->bridge;
h = h->next;
}
return -1;
}
void process_packet(struct DATA *d)
{
int dst;
int i;
bridge[d->source].rcount++;
gettimeofday(&bridge[d->source].lastrcv, NULL);
for (i=0; i<8; i++) {
if (memcmp(bridge[d->source].last[i],d->data,14) == 0) {
return;
}
}
if (is_decnet(d)) d->type = DECnet;
if (is_lat(d)) d->type = LAT;
if (is_ip(d)) d->type = IP;
if (bridge[d->source].types[d->type] == 0) return;
if (d->type == -1) return;
bridge[d->source].xcount++;
register_source(d);
dst = locate_dest(d);
if (dst == -1) {
int i;
for (i=0; i<bcnt; i++) send_packet(i, d);
} else {
send_packet(dst, d);
}
}
void dump_data()
{
int i;
printf("Host table:\n");
for (i=0; i<bcnt; i++)
printf("%d: %s %s:%d (Rx: %d Tx: %d (Drop rx: %d)) Active: %d
Throttle: %d(%03o)\n",
i,
bridge[i].name,
inet_ntoa(bridge[i].addr),
ntohs(bridge[i].port),
bridge[i].rcount,
bridge[i].tcount,
bridge[i].rcount - bridge[i].xcount,
active(i),
bridge[i].throttlecount,
bridge[i].throttle & 255);
printf("Hash of known destinations:\n");
for (i=0; i<HOST_HASH; i++) {
struct HOST *h;
h=hosts[i];
while (h) {
printf("%02x%02x%02x%02x%02x%02x -> %d",
(unsigned char)h->mac[0],
(unsigned char)h->mac[1],
(unsigned char)h->mac[2],
(unsigned char)h->mac[3],
(unsigned char)h->mac[4],
(unsigned char)h->mac[5],
h->bridge);
if ((unsigned char)h->mac[0] == 0xaa &&
(unsigned char)h->mac[1] == 0x00 &&
(unsigned char)h->mac[2] == 0x04 &&
(unsigned char)h->mac[3] == 0x00) {
printf(" (%d.%d)", h->mac[5] >> 2, ((h->mac[5] & 3) << 8) + h->mac[4]);
}
printf("\n");
h = h->next;
}
}
}
int main(int argc, char **argv)
{
struct sockaddr_in sa,rsa;
int len,i,hsock;
fd_set fds;
socklen_t ilen;
int port;
struct DATA d;
char buf[8192];
signal(SIGHUP, read_conf);
signal(SIGUSR1, dump_data);
if (argc != 2) {
printf("usage: %s <port>\n", argv[0]);
exit(1);
}
if ((sd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
sa.sin_family = AF_INET;
sa.sin_port = htons(atoi(argv[1]));
sa.sin_addr.s_addr = INADDR_ANY;
if (bind(sd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
perror("bind");
exit(1);
}
read_conf();
#if DEBUG
dump_data();
#endif
while(1) {
FD_ZERO(&fds);
hsock = 0;
for (i=0; i<bcnt; i++) {
FD_SET(bridge[i].fd, &fds);
if (bridge[i].fd > hsock) hsock = bridge[i].fd;
}
if (select(hsock+1,&fds,NULL,NULL,NULL) == -1) {
if (errno != EINTR) {
perror("select");
exit(1);
}
}
for (i=0; i<bcnt; i++) {
if (FD_ISSET(bridge[i].fd,&fds)) {
d.source = i;
d.type = -1;
if (bridge[i].addr == 0) {
d.data = NULL;
d.len = NULL;//h.caplen;
if (d.data) {
process_packet(&d);
}
} else {
ilen = sizeof(rsa);
if ((d.len = recvfrom(bridge[i].fd, buf, 1518, 0,
(struct sockaddr *)&rsa, &ilen)) > 0) {
if ((d.source = lookup(&rsa, buf)) >= 0) {
d.data = buf;
process_packet(&d);
}
}
}
FD_CLR(bridge[i].fd, &fds);
}
}
}
}