Networking with SIMH
The aim of this quick tutorial is to show how to setup SIMH's networking.
Contents
libpcap
By default SIMH supports networking via libpcap. The restrction of this method is that the host machine is unable to communicate with the emulator. Otherwise it's realitivly straight forward. First you need to make sure your binary has networking built in.
Showing host ethernet adapters
By issuing the command 'show xq eth' you will get either a list of adapters, or an error that this version does not support networking.
On the Windows platform it would look something like this:
With networking:
sim> show xq eth ETH devices: 0 \Device\NPF_GenericDialupAdapter (Adapter for generic dialup and VPN capture) 1 \Device\NPF_{9E485825-641F-45C3-BC3B-E9DF4DDE520D} (Local Area Connection 4) 2 \Device\NPF_{279EDB55-7802-44D3-8FA1-15B14452B309} (Local Area Connection) sim>
Without networking:
sim> show xq eth ETH devices: network support not available in simulator sim>
Setting the MAC address
To set the MAC address to something other then the default (Which is important if you ever plan on having more then one SIMH device talking to another, say in HecNET) you need to change the MAC address. Remember this needs to be done before you attach the device. The command is simple as all you have to do is type in something to the effect of:
sim> set xq mac=00:00:01:00:00:01
Remember the first half is the vendor code, and the second half is the unique identifier. Do not use all 0's or all FF's it will create major issues on your network.
Attaching the device
Once the host ethernet adapter to bind to has been identified, the MAC address has been configured, you can now attach the emulator to the host network card. you can either specifiy the whole name as listed from the 'xq show dev' command, or use the corresponding number. Thusly:
att xq eth2
And
att xq \Device\NPF_{279EDB55-7802-44D3-8FA1-15B14452B309}
Are identical. You can now boot your emulator and it will have network accesss.
SLiRP
To be done later
Writing your own
According to my old notes, the following code in the sim_ether.c file, replacing the either NON WORKING, or LIB_PCAP sections will produce an exe that will write packets to a directory, and constantly scan another directory for files to 'input' as packets.
#include <fcntl.h> /*constants defined*/ #include <sys\types.h> #include <sys\stat.h> /*constants defined*/ #include <share.h> /*constants defined*/ #include <io.h> //Packet couters for reading/writing //int Packet; int PacketR; //Internal counter to what we have read last. char Path[255]; char Readpath[255]; /************Helper functions...***************************/ //sopenreadcounter Opens the readcounter file //return 1 with the file handle, 0 if the file doesnt exist //-1 if there was some other error related to the file int sopenreadcounter(char *path,int *filehndl) { //char *filename; #ifdef DEBUG printf("sopenreadcounter opening %s\n",path); #endif *filehndl=sopen(path,O_RDWR | O_BINARY, SH_DENYRW, S_IREAD | S_IWRITE); //Check to see if it barfed if (*filehndl==-1) { #ifdef DEBUG printf("sopenreadcounter sopen returned -1 errno %d\n\n",errno); #endif //file doesnt exist! if (errno==ENOENT) { #ifdef DEBUG printf("sopenreadercount file doesnt exist(ENOENT)!\n"); #endif return 0; } //file is there, but we missed the lock. if (errno==EACCES) { int j=0; while(*filehndl==-1) { *filehndl=sopen(path,O_RDWR|O_BINARY, SH_DENYRW, S_IREAD | S_IWRITE); #ifdef DEBUG printf("\rEACCES on %s fh %d errno %d\t\t%d",path,*filehndl,errno,j); //printf("\rEACCES fh %d errno %d\t\t%d",*filehndl,errno,j); #endif Sleep(5); //jiffy wait.. j++; } return 1; //we got the filehandle } //Some other error.. we're fucked for now let's panic! printf("\ndrop out with error sopenreadcounter\n"); return -1; } return 1; //it worked on first shot! } /***********************************************************/ t_stat eth_open (ETH_DEV* dev, char* name) { FILE *packetcount; char packetcountpath[255]; PacketR=0; memset(Path,0x0,sizeof(Path)); sprintf(Path,"%s",name); sprintf(Readpath,"%s\\%02X%02X%02X%02X%02X%02X",Path,dev->mac_address[0],dev->mac_address[1],dev->mac_address[2],dev->mac_address[3],dev->mac_address[4],dev->mac_address[5]); printf("\nPath:\t%s\nReadpath:\t%s\n",Path,Readpath); mkdir(Readpath); //Since we are new, we are going to reset the counter to 0. We //wouldnt want the old packets anyways. yes I knkow this will //liter the filesystem... clear those temp dirs! sprintf(packetcountpath,"%s\\packetcount",Readpath); packetcount=fopen(packetcountpath,"w"); fprintf(packetcount,"0"); fclose(packetcount); return SCPE_OK; } t_stat eth_close (ETH_DEV* dev) { //rmdir(Readpath); return SCPE_NOFNC; } /*************************************************************/ t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { int status = 1; /* default to failure */ /* make sure device exists */ if (!dev) return SCPE_UNATT; /* make sure packet exists */ if (!packet) return SCPE_ARG; /* make sure packet is acceptable length */ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { char buffer[5000]; char fname[255]; int err=0; int outz=0; int FHpacketcount=0; //filehandle for the packet file char packetcountpath[255]; int Packet=0; //the packet # //verify path exists first.. by making it.... memset(packetcountpath,0x0,sizeof(packetcountpath)); sprintf(packetcountpath,"%s\\%02X%02X%02X%02X%02X%02X",Path,packet->msg[0],packet->msg[1],packet->msg[2],packet->msg[3],packet->msg[4],packet->msg[5]); mkdir(packetcountpath); sprintf(packetcountpath,"%s\\%02X%02X%02X%02X%02X%02X\\packetcount",Path,packet->msg[0],packet->msg[1],packet->msg[2],packet->msg[3],packet->msg[4],packet->msg[5]); err=sopenreadcounter(&packetcountpath,&FHpacketcount); if(err==0) //The file didn't exist! For now we'll just assume this works... { FHpacketcount=sopen(packetcountpath,O_RDWR | O_BINARY | O_CREAT, SH_DENYRW, S_IREAD | S_IWRITE); Packet=0; } if(err==-1)//something bombed! { #ifdef DEBUG printf("something bombed openening the packet counter"); #endif exit(-1); } if(err==1) { char buffer[20]; memset(buffer,0x0,sizeof(buffer)); read(FHpacketcount,buffer,sizeof(buffer)); sscanf(buffer,"%d",&Packet); lseek(FHpacketcount,0,0); } memset(buffer,0x0,sizeof(buffer)); memset(fname,0x0,sizeof(fname)); sprintf(fname,"%s\\%02X%02X%02X%02X%02X%02X\\packet_%d.cap",Path,packet->msg[0],packet->msg[1],packet->msg[2],packet->msg[3],packet->msg[4],packet->msg[5],Packet); //printf("writing frame %s\n",fname); outz=sopen(fname,O_RDWR | O_BINARY | O_CREAT, SH_DENYRW, S_IREAD | S_IWRITE); eth_add_crc32(packet->msg); write(outz,packet->msg,packet->len); close(outz); status=0; Packet++; { char buffer[20]; memset(buffer,0x0,sizeof(buffer)); sprintf(buffer,"%d",Packet); #ifdef DEBUG printf("Writing packetcount[%d] %s\n",Packet,packetcountpath); #endif write(FHpacketcount,buffer,sizeof(buffer)); close(FHpacketcount); } /* detect sending of decnet loopback packet */ if ((status == 0) && DECNET_SELF_FRAME(dev->decnet_addr, packet->msg)) dev->decnet_self_sent += dev->reflections; } /* if packet->len */ /* call optional write callback function */ if (routine) (routine)(status); return SCPE_OK; } /*************************************************************/ t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) { int status; /* make sure device exists */ if (!dev) return SCPE_UNATT; /* make sure packet exists */ if (!packet) return SCPE_ARG; /* set read packet */ dev->read_packet = packet; packet->len = 0; /* set optional callback routine */ dev->read_callback = routine; /* dispatch read request to either receive a filtered packet or timeout */ do { char fname[255]; FILE *inz; FILE *packetcount; int j=0; sprintf(fname,"%s\\packet_%d.cap",Readpath,PacketR); #ifdef DEBUG //printf("eth_read from %s\n",fname); #endif inz=sopen(fname,O_RDWR | O_BINARY, SH_DENYRW); if(inz==-1) { return SCPE_OK; } else { unsigned char packetbuffer[2000]; memset(packetbuffer,0x0,sizeof(packetbuffer)); j=read(inz,packetbuffer,sizeof(packetbuffer)); close(inz); unlink(fname); #ifdef DEBUG printf("read frame %s\n",fname); #endif dev->read_packet->len=j; memcpy(dev->read_packet->msg,packetbuffer,j); eth_add_crc32(dev->read_packet); if (dev->read_callback) (dev->read_callback)(0); PacketR++; } return SCPE_OK; } while ((status) && (0 == packet->len)); } t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* addresses, ETH_BOOL all_multicast, ETH_BOOL promiscuous) {return SCPE_NOFNC;} int eth_devices (int max, ETH_LIST* dev) {return 0;} #endif ////////////////////////////////////////////////////////////////////////