#define VERSION "13-Nov-1989\n" /*************************************************************************/ /* */ /* */ /* ________________________________________________________ */ /* / \ */ /* | AAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */ /* | AAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */ /* | AAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */ /* | AAAA AAAA CCCC CCCC | */ /* | AAAA AAAA CCCC CCCC | */ /* | AAAA AAAA CCCC CCCC | */ /* | AAAA AAAA CCCC CCCC | */ /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCC | */ /* | AAAA AAAAAAAAAAA CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC | */ /* | AAAA AAAAAAAAA CCCCCCCCCCCCCC CCCCCCCCCCCCCC | */ /* \________________________________________________________/ */ /* */ /* Copyright (c) 1988 by Advanced Computer Communications */ /* 720 Santa Barbara Street, Santa Barbara, California 93101 */ /* (805) 963-9431 */ /* */ /* */ /* File: acpconfig.c */ /* */ /* Author: Clare E. Russ */ /* */ /* Project: Installation verification program for ACC */ /* ACP 5100/6100 and ACP 5250/6250 network */ /* interface drivers. Acpconfig provides a user */ /* interface which supports the configuration of a */ /* network interface. */ /* */ /* Function: */ /* Based on socket ioctls, provide user interface to Network */ /* Interface Drivers for the following ACC ACP devices: */ /* */ /* ACP 5100/6100 'acp' interface */ /* ACP 5250/6250 'dda' interface */ /* ACP 625 'ddn' interface */ /* */ /* The ioctl indicates what type of message is to be sent to the */ /* front end device (ie, bring up the HDLC line in external */ /* loopback mode). */ /* */ /* Components: acpconfig.c, ioctl.h */ /* */ /* */ /* Usage Notes: */ /* */ /* -A filename */ /* Add the contents of the named file to the address */ /* translation table for PDN service */ /* */ /* -a ipaddr x25addr */ /* Add the specified address pair to the address */ /* translation table for PDN service */ /* */ /* -b baud */ /* Note that the baud rate values are different for the */ /* ACP 625. Table 1 contains the baud rates which apply */ /* to the ACP 6100, ACP 5250/6250 products. Table 2 */ /* contains the baud rates which apply to the ACP 625. */ /* */ /* Table 1: Nominal baud rates for ACP 5100/6100, ACP 5250/6250 */ /* */ /* 2.00M 2000K 2.0M 1.33M 1333K 1.3M */ /* 1.00M 1000K 1.0M 500K 250K 100K */ /* 64K 64000 56K 56000 30K 19.2K */ /* 9.6K 9600 4.8K 4800 2.4K 2400 */ /* 1.2K 1200 */ /* */ /* Table 2: Nominal baud rates for ACP 625 */ /* */ /* 316000 153600 115200 76800 76.8K */ /* 57600 57.6K 38400 38.4K 28800 */ /* 28.8K 19200 19.2K 9600 9.6K */ /* 4800 4.8K 2400 2.4K 2150 */ /* 1760 1200 */ /* */ /* An argument of 0 or "external" to the -b option */ /* specifies external clocking for the ACP 5100/6100 */ /* and ACP 5250/6250 interfaces. (The ACP 625 does not */ /* support this feature.) All other values imply */ /* internal clocking. */ /* The M for megabits/second and K for kilobits/second */ /* are optional. Note that Table 1 allows for the entry */ /* of 9.6 (with the assumed unit of Kilobits/second), but */ /* also allows for the entry of 9600 (bits/second). Thus */ /* there is more than one entry for some of the baud rate */ /* values. */ /* */ /* -c msgnum */ /* Toggle the enable status of driver message number msgnum */ /* */ /* -d ipaddr */ /* Delete the specified address entry from the address */ /* translation table for PDN service */ /* */ /* -D */ /* Delete all address entries form the address translation */ /* table for PDN service */ /* */ /* -e size */ /* set the firmware buffer size to size. This also resets */ /* the board. size comes from a table of valid sizes and */ /* may also be "default" to get the default size. */ /* */ /* -h mode */ /* Read driver histogram and print on standard output. Each */ /* entry is of the form sec.usec. The entries are as */ /* follows: */ /* 0 : number of seconds the link was up */ /* 1 : starting time */ /* 2 : ending time */ /* 3 : current value for tmo_data_idle */ /* 4-69 : seconds n logical channels were open for */ /* n = 0 to 64 (126) */ /* */ /* If mode is 0 then data is read. If mode is 1 then data */ /* is read and the histogram is reinitialized. */ /* */ /* -f parameter status */ /* Control flow control parameter negotiation where */ /* parameter is either "packet" or "window" and */ /* status is either "on" or "off". */ /* Note: incoming flow control parameter negotiation */ /* if not effected by this option. */ /* */ /* -l */ /* -ln */ /* List the currently active lcns. The 'n' suffix */ /* disables address to name lookups. */ /* */ /* -m message */ /* Pass ``message'' to the FEP as a supervisory channel */ /* message. Message is a sequence of numbers separated */ /* by white space. Numbers with leading ``0'' are taken */ /* as octal, other numbers taken as HEX, decimal is not */ /* supported. Hex and octal may be intermixed, as in */ /* ``0140 0 0 2 89 017''. The message is terminated by the */ /* end of the argument list or by an argument beginning */ /* with a dash ``-''. Absolutely no checking is performed; */ /* the bytes are written to the FEP as a supervisor */ /* message. The message is limited to MLEN = 112 bytes. */ /* */ /* -N network */ /* Set network type */ /* transpac - french transpac network addressing */ /* default - normal x25 network */ /* net15 - normal network but with 15 digit addrs */ /* */ /* -n circuits */ /* Set the number of logical channels to ``circuits'', which*/ /* must be less than some implementation defined maximum. */ /* */ /* -q query-type */ /* Query the board or driver and place results on stdout. */ /* */ /* -q 0 Statistics query to FEP */ /* -q 1 Driver operating mode query */ /* -q 2 Reserved for ACC debugging */ /* */ /* -r count */ /* Read the specified number of entries from the address */ /* translation table for PDN service */ /* */ /* -r 0 read all entries from the address translation table */ /* */ /* -s X.25 service */ /* Select DDN standard X.25 service or basic X.25 service */ /* or Public Data Network X.25 service */ /* */ /* -s standard select standard X.25 service */ /* -s basic select basic X.25 service */ /* -s pdn select X.25 Public Data Network service */ /* */ /* -t sec Set idle circuit timeout */ /* */ /* -u down bring down the link */ /* -u dte bring up link, no loopback, DTE */ /* -u dce bring up link, no loopback, DCE */ /* -u ext bring up link, external loopback mode */ /* -u int bring up link, internal loopback mode */ /* */ /* -v variable value */ /* Set the value of a driver variable symbolized by */ /* "variable" to "value" decimal. "Variables" understood */ /* are "window" and "packet" to set the driver's notion of */ /* negotiable window size, and negotiable packet size. */ /* */ /* -z reset the specifed front-end device */ /* */ /* Compile Notes: */ /* */ /* The associated makefile builds the acpconfig executable image */ /* for UNIX or the specified emulation/simulation such as */ /* The Wollongong Group (TWG) software which runs under VAX/VMS. */ /* The makefile must be invoked with the argument which specifies */ /* the target host operating system, otherwise the makefile */ /* defaults to creating an executable image for UNIX. */ /* */ /* make (compile for UNIX 4.nBSD) */ /* make clean */ /* make print */ /* */ /* */ /* System Notes: */ /* */ /* Create a socket of the AF_INET address family and of type */ /* datagram, SOCK_DGRAM. Use the socket to send a socket ioctl */ /* to the network driver of the specified interface ('acp0' in */ /* the usage notes). Depending on the type of message specified */ /* in the command line, send the appropriate socket ioctl to */ /* specify what kind of action is to be taken. */ /* */ /* For those drivers which support the Control Interface (CIF) */ /* the message exchange conforms to the CIF which defines paired */ /* command/response Control Interface Messages (CIMs) between the */ /* host and the front end. Otherwise, the exchange of messages */ /* is the pre-CIF protocol (i.e., that used by the ddn interface). */ /* */ /* Assignment of subcodes for the SIOCACPCONFIG ioctl: */ /* */ /* 1..14 -bRATE for RATE != 0 */ /* `0'..`4' -u N (line control) */ /* `a' -A and -a commands (PDN) */ /* `b' -b0 (set external clock) */ /* `c' -c msgnum */ /* `d' -d command (PDN) */ /* `e' -e size */ /* `h' -h 0 */ /* `H' -h 1 */ /* `m' -m (message command) */ /* `n' -n circuits (limit lcns) */ /* `p' -q 0 (statistics query) */ /* `q' -q 1 (driver query) */ /* `r' -r command (PDN) */ /* `t' -t sec (timeout set) */ /* `S' -s 0 */ /* `T' -s 1 */ /* `U' -s 2 */ /* `V' -v command (set variable) */ /* `z' -z command (reset) */ /* */ /*************************************************************************/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% %%*/ /*%% INCLUDE FILES %%*/ /*%% %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* There are alternate path names for The Wollongong Group (TWG) */ /* IPTCP and Eunice software which runs under VMS, */ /* and for TGV, Incorporated's MultiNet software which also runs */ /* under VMS. */ #ifdef VAXVMS # ifdef eunice # define WINS # else # define MULTINET # endif #endif #ifdef vax11c # define EXIT_ERR 0 # define EXIT_OK 1 #else # define EXIT_ERR 1 # define EXIT_OK 0 #endif #include <sys/param.h> #include <stdio.h> #include <errno.h> #include <ctype.h> #include <netdb.h> #include <nlist.h> #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/ioctl.h> #ifdef MULTINET #include <vaxif/if_ddaioctl.h> /* multinet doesn't fix ioctl.h */ #endif #ifdef VAXVMS /* TWG or TGV */ #include <netinet/in.h> #include <net/if.h> #else #include "/sys/netinet/in.h" #include "/sys/net/if.h" #endif #ifdef MULTINET #ifdef errno #undef errno #endif errno #define errno socket_errno /* MultiNet runtime errors */ #define Perror(s) XPerror(s) /* Keep different from perror() */ #define ioctl(s,c,d) socket_ioctl(s,c,d)/* MultiNet ioctl() routine */ #endif MULTINET #define NDDA 1 #define NONE 0 /* used by the -o option */ #define EXTENDED 1 /* used by -o option */ /* 'iface' interface definitions */ #define ACP_INTERFACE 0x01 /* for acp interface */ #define DDN_INTERFACE 0x02 /* for ddn interface */ #define BAUD_VAL 50 /* for baud rate flag, -b */ #define SERVICE_VAL 35 /* for X.25 service flag, -s */ #define ACTUAL_VAL 83 /* for X.25 service flag 'S' */ /* network values */ #define NET_STANDARD 0 /* on standard network */ #define NET_TRANSPAC 1 /* on transpac style network */ /* delay macro from /sys/vax/param.h */ #ifdef vax11c #define NEW_DELAY(n) sleep(n / 100000) #else #define NEW_DELAY(n) { register int N = (n); while (--N > 0); } #endif /* The baud_rate structure maps the user-supplied baud rate into the */ /* parameter used in the socket ioctl to the driver. In some cases, */ /* more than one representation of a value is present to ease the */ /* interface. The manual page for acpconfig recommends that the */ /* user give the baud rate with the assumed unit of Kilobits/second. */ struct baud { char *b_rate; char parameter; } baud_rate[] = { { "2.00", 1 }, /* these are nominal baud rates */ { "2.00M", 1 }, { "2000K", 1 }, { "2000k", 1 }, { "2.0", 1 }, { "2.0M", 1 }, { "1.33", 2 }, { "1.33M", 2 }, { "1333K", 2 }, { "1333k", 2 }, { "1.3", 2 }, { "1.3M", 2 }, { "1.00", 3 }, { "1.00M", 3 }, { "1000K", 3 }, { "1000k", 3 }, { "1.0M", 3 }, { "1.0", 3 }, { "500", 4 }, { "500K", 4 }, { "500k", 4 }, { "250", 5 }, { "250K", 5 }, { "250k", 5 }, { "100", 6 }, { "100K", 6 }, { "100k", 6 }, { "64", 7 }, { "64K", 7 }, { "64k", 7 }, { "64000", 7 }, { "56", 8 }, { "56K", 8 }, { "56k", 8 }, { "56000", 8 }, { "30", 9 }, { "30K", 9 }, { "30k", 9 }, { "19.2", 10 }, { "19.2K", 10 }, { "19.2k", 10 }, { "9.6", 11 }, { "9.6K", 11 }, { "9.6k", 11 }, { "9600", 11 }, { "4.8", 12 }, { "4.8K", 12 }, { "4.8k", 12 }, { "4800", 12 }, { "2.4", 13 }, { "2.4K", 13 }, { "2.4k", 13 }, { "2400", 13 }, { "1.2", 14 }, { "1.2K", 14 }, { "1.2k", 14 }, { "1200", 14 }, { 0, 0 }, }; /* Table of baud rate values and the associated parameter for the Set */ /* System Parameters message, ddninit_msg. The 'parameter1' is nonzero */ /* for valid baud rate divisors. The user's manual gives both the */ /* actual and nominal baud rates, either one is accepted from the user, */ /* but the nominal baud rate is the figure which is closest to the rate */ /* set on the front end. */ struct baud ddnbaud_rate[] = { { "333333", 1 }, /* actual baud rate */ { "316000", 1 }, /* nominal baud rate */ { "153846", 2 }, /* actual baud rate */ { "153600", 2 }, /* nominal baud rate */ { "114285", 3 }, /* actual baud rate */ { "115200", 3 }, /* nominal baud rate */ { "76923", 4 }, /* actual baud rate */ { "76800", 4 }, /* nominal baud rate */ { "76.8K", 4 }, /* nominal baud rate */ { "76.8k", 4 }, /* nominal baud rate */ { "57971", 5 }, /* actual baud rate */ { "57600", 5 }, /* nominal baud rate */ { "57.6K", 5 }, /* nominal baud rate */ { "57.6k", 5 }, /* nominal baud rate */ { "38461", 6 }, /* actual baud rate */ { "38400", 6 }, /* nominal baud rate */ { "38.4K", 6 }, /* nominal baud rate */ { "38.4k", 6 }, /* nominal baud rate */ { "28776", 7 }, /* actual baud rate */ { "28800", 7 }, /* nominal baud rate */ { "28.8K", 7 }, /* nominal baud rate */ { "28.8k", 7 }, /* nominal baud rate */ { "19230", 8 }, /* actual baud rate */ { "19200", 8 }, /* nominal baud rate */ { "19.2K", 8 }, /* nominal baud rate */ { "19.2k", 8 }, /* nominal baud rate */ { "9592", 9 }, /* actual baud rate */ { "9600", 9 }, /* nominal baud rate */ { "9.6K", 9 }, /* nominal baud rate */ { "9.6k", 9 }, /* nominal baud rate */ { "4801", 10 }, /* actual baud rate */ { "4800", 10 }, /* nominal baud rate */ { "4.8K", 10 }, /* nominal baud rate */ { "4.8k", 10 }, /* nominal baud rate */ { "2400", 11 }, /* actual baud rate */ { "2.4K", 11 }, /* actual baud rate */ { "2.4k", 11 }, /* actual baud rate */ { "2150", 12 }, /* nominal baud rate */ { "1760", 13 }, /* actual baud rate */ { "1760", 13 }, /* actual baud rate */ { "1200", 14 }, /* nominal baud rate */ { "1.2K", 14 }, /* nominal baud rate */ { "1.2k", 14 }, /* nominal baud rate */ { 0, 0 }, }; #ifndef MULTINET char *kmemf = "/dev/kmem"; int kmem; #endif MULTINET #include <strings.h> #include <sys/time.h> #ifdef VAXVMS # ifdef WINS # include <vaxif/if_ddareg.h> # include <vaxif/if_ddavar.h> # endif # ifdef MULTINET # include "[-.kernel.vaxif]if_ddareg.h" # include "[-.kernel.vaxif]if_ddavar.h" # endif #else VAXVMS /* must be unix or ultrix */ # include "/sys/vaxif/if_ddareg.h" # include "/sys/vaxif/if_ddavar.h" #endif VAXVMS /* EXTERNAL FUNCTIONS */ extern char *routename(); extern off_t lseek(); extern u_long inet_addr(); extern char *inet_ntoa(); extern u_long inet_network(); /* * Weirdness for test-jig, re-map all ioctl and socket calls to go * through driver simulator. */ #ifdef SIMULATION #define ioctl fake_unix_ioctl #define socket fake_unix_socket #define main cf_main #endif /* * Print contents of queues and various data structures */ char *state_tab[] = { "Down", "Rstrt", "Idle", "Call", "Open", "Clear" }; #define NSTATES 5 /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% MAIN() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* For the specified interface, create a socket for a socket */ /* ioctl to set the Internet address and configuration. The */ /* ioctl kicks the appropriate driver, the value in ifr_data */ /* indicates the type of action to be taken. ('b' indicates */ /* external clock, 1-14 indicates baud rate from the table of */ /* possible values, '0' - '4' indicates -u options, and 's','t', */ /* 'u' indicate -s options.) */ /* Enhancement: 'a' indicates addition of an address table */ /* entry, 'd' indicates deletion of an address table entry, */ /* and 'r' is a request to read address table entries. */ /* Etc, etc (see comment at top for complete list) */ /* */ /* Call: main( argc, argv) */ /* Arguments: argc: argument count */ /* argv: argument value */ /* Returns: nothing */ /* Called by: invoked by privileged user */ /* Calls to: socket() */ /* perror() */ /* strcpy() */ /* strncpy() */ /* sizeof() */ /* usage() */ /* long_usage() */ /* get_bfrsize_index() */ /* ioctl() */ /* exit() */ /* Perror() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ struct ifreq ifr; struct sockaddr_in sin = { AF_INET }; char name[30]; int s; /* socket descriptor */ int nflag; /* control host name lookup (symbolic) */ struct ddactl ddactl; struct trtab trtab; struct lg2tab { /* For use with packet sizes, so just the */ int base2log; /* legal packet sizes for X.25 are here */ int binval; } lg2tab[] = { 4, 16, 5, 32, 6, 64, 7, 128, 8, 256, 9, 512, 10, 1024, 11, 2048, 12, 4096, 0, 0, }; char *fe_bfr_sizes[] = { "default", /* entry 0: Default Size */ "256", /* entry 1: 256 bytes */ "512", /* entry 2: 512 bytes */ "1024", /* entry 3: 1K bytes (currently same as default) */ "2048", /* entry 4: 2K bytes */ "4096", /* entry 5: 4K bytes */ "8192", /* entry 6: 8K bytes */ "16384", /* entry 7: 16K bytes */ NULL }; extern int errno; /* * Structure used to hold the results of an nlist library * function call. */ struct nlist nl[] = { { "_dda_softc" }, #define SOFTC 0 "", }; #ifndef VAXVMS /* * Seek into the kernel for a value. * Used by the -l option of acpconfig. */ klseek(fd, base, off) int fd; off_t base; int off; { if (lseek(fd, base, off) == (off_t)-1 ){ fprintf(stderr,"acpconfig: Bad lseek fd=%d,bas=%x,off=%d ",fd,base,off); perror(""); exit(1); } } klread(fd,buf,size) int fd; char *buf; int size; { if ( read(fd,buf,size) < 0 ){ perror("Read"); exit(2); } } #endif VAXVMS /* * Routine used in conjunction with the -l option. * This function displays the status of each active * lcn for the given unit. */ display(addr,nddach) off_t addr; int nddach; /* number of circuits currently available */ { struct dda_softc dda_softc; register struct dda_cb *dc; struct sockaddr_in sin; char *p; int i; int header; if (addr == 0) { printf("acpconfig: nlist--symbol not defined\n"); return; } #ifdef MULTINET klseek(addr); klread((char *)&dda_softc, sizeof(dda_softc)); #else MULTINET klseek(kmem, addr, 0); klread(kmem, (char *)&dda_softc, sizeof(dda_softc)); #endif MULTINET header = 0; for ( i=0; i<= nddach ; i++) { dc = &dda_softc.dda_cb[i]; if ((dc->dc_state != LC_IDLE) && (dc->dc_state != LC_DOWN)) { if (!header) { printf("\n\t\t\tACP 6250 / 5250 (dda%d) Status\n", dda_softc.dda_if.if_unit); printf("lcn Qlen Dropped Flags Timer State Pin Pout Win Wout IP Addr\n"); } header++; printf("%3d ",i); printf("%4d ",dc->dc_oq.ifq_len); printf("%6d ",dc->dc_oq.ifq_drops); switch (dc->dc_flags & DC_CLIENTS) { case DC_X29: p="Pad "; break; case DC_X29W: p="Host"; break; case DC_RAW: p="PI "; break; case DC_IP: p="IP "; break; default: p="bug!"; break; } printf("%c %s", (dc->dc_flags & DC_OBUSY ? 'B' : ' '), p); printf(" %3d ", dc->dc_timer); if (dc->dc_state > NSTATES) printf ("%4x? ", dc->dc_state); else printf("%-5s ", state_tab [dc->dc_state]); printf(dc->dc_pktsizein ? "%4d ":" ??? ",1<<dc->dc_pktsizein); printf(dc->dc_pktsizeout ?"%4d ":" ??? ",1<<dc->dc_pktsizeout); printf(dc->dc_wsizein ? "%3d ":"??? ",dc->dc_wsizein); printf(dc->dc_wsizeout ?"%3d ":"??? ",dc->dc_wsizeout); if ((dc->dc_flags & DC_CLIENTS) == DC_IP) printf(" %s",routename(dc->dc_inaddr)); putchar('\n'); } } if ((!header) && (i == nddach + 1)) printf("lcns 0 through %d inactive\n",nddach); sin.sin_addr.s_addr = dda_softc.dda_ipaddr.s_addr; printf("Our addr: %s", routename(sin.sin_addr)); (void)putchar('\n'); } char * routename(in) struct in_addr in; { char *cp = 0; static char line[50]; int lna, net; net = inet_netof(in); lna = inet_lnaof(in); if (!nflag) { if (lna == INADDR_ANY) { struct netent *np = getnetbyaddr(net, AF_INET); if (np) cp = np->n_name; } else { struct hostent *hp; hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), AF_INET); if (hp) cp = hp->h_name; } } if (cp) (void)strcpy(line, cp); else { u_char *ucp = (u_char *)∈ if (lna == INADDR_ANY) (void)sprintf(line, "%u.%u.%u", ucp[0], ucp[1], ucp[2]); else (void)sprintf(line, "%u.%u.%u.%u", ucp[0], ucp[1], ucp[2], ucp[3]); } return (line); } get_bfrsize_index(str) char *str; { register int i; for(i = 0; fe_bfr_sizes[i]; i++) if(strcmp(str,fe_bfr_sizes[i]) == 0) return(i); fprintf(stderr,"Invalid size: %s\nBuffer sizes available are: "); for(i = 0; fe_bfr_sizes[i]; i++) fprintf(stderr,"%s ",fe_bfr_sizes[i]); fprintf(stderr,"\n"); return(-1); } main(argc, argv) int argc; char *argv[]; { register struct baud *p; /* baud rates */ int iface = 0; /* indicate interface, i.e. acp */ int tmp, top, offset; int unit; FILE *fp; char line[80], arg1[40], arg2[40]; char *ap; char option_byte1 = 0; int o_flag = 0; if (argc == 1) { long_usage(); } if (argc < 3) { fprintf(stderr,"\n acpconfig: invalid number of arguments\n"); usage(); /* display proper syntax for user */ } s = socket(AF_INET, SOCK_DGRAM, 0); /* try create socket */ if (s < 0) { perror("acpconfig: socket"); exit(1); } argc--, argv++; /* interface name */ (void)strcpy(name, *argv); (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if ((*argv)[2] == 'n') /* check for 'ddn' interface */ iface |= DDN_INTERFACE; if ((*argv)[0] == 'a') /* check for 'acp' interface */ iface |= ACP_INTERFACE; if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCGIFFLAGS)"); exit(1); } unit = (*argv)[3] & 0x0F; while (--argc > 0) { argv++; if(**argv != '-') setifaddr(*argv); /* set interface address */ else { ifr.ifr_data = 0; switch((*argv)[1]) /* process flag(s) */ { case 'b': /* set baud rate or ext clocking */ ap = *argv; if (ap[2] == '\0') { /* -b N case */ argc--, argv++, ap = *argv; if (ap == 0) ap = "???"; } else ap += 2; /* -bN case, skip over the "-b" */ /* ap points to purported number, regardless -bN or -b N */ if ((*ap == '0') || (strcmp(ap, "external") == 0)) { if (iface&DDN_INTERFACE) { fprintf (stderr, "\nacpconfig %s: -b 0 invalid\n", name); break; } arg1[0] = 'b'; ifr.ifr_data = arg1; } else /* set baud rate, if N is valid */ { if (iface&DDN_INTERFACE) p = ddnbaud_rate; else p = baud_rate; while (p->b_rate) { if (strcmp (ap, p->b_rate) == 0) break; p++; } if (p->parameter) ifr.ifr_data = &(p->parameter); } if (setconfig(ifr.ifr_data, s)) { fprintf(stderr,"\nacpconfig: -b %s invalid\n", ap); usage(); } break; case 'l': /* monitor status of lcns */ if ((*argv)[2] == 'n' && (*argv)[3] == '\0') nflag = 1; /* "-ln" - numeric */ else if ((*argv)[2] == '\0') nflag = 0; /* "-l" - symbolic */ else usage(); /* other - wrong. */ if (strlen(*argv) < 3) { #ifdef VAXVMS # ifdef MULTINET if(multinet_kernel_nlist("MULTINET_NETWORK_IMAGE:",nl) ==-1) # else MULTINET /* must be TWG instead */ char *vmsnlist(); kmemf = vmsnlist(); if(nlist(kmemf, nl) == -1) # endif MULTINET #else VAXVMS if(nlist("/vmunix", nl) == -1) #endif VAXVMS { fprintf(stderr,"acpconfig: could not open /vmunix\n"); exit(1); } if (nl[SOFTC].n_value == 0) { fprintf(stderr, "acpconfig: No namelist\n"); exit(1); } #ifndef VAXVMS kmem = open (kmemf, 0); if (kmem < 0) { fprintf(stderr, "acpconfig: cannot open "); perror(kmemf); exit(1); } #endif ddactl.func = 'n'; ddactl.drval = 0; ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } display((off_t)(nl[SOFTC].n_value+unit * sizeof(struct dda_softc)),*(int *)ifr.ifr_data); } else usage(); (void)close(kmem); break; case 'o': /* collect X.25 1984 options */ { char *cp = *argv; if (strlen (cp) > 2) /* handle -oNAME and -o NAME */ cp += 2; else { argc--; argv++; cp = *argv; if (cp == 0) { fprintf (stderr, "acpconfig: -o what?\n"); exit(1); } } if (strcmp(cp,"none") == 0) option_byte1 = NONE; else if (strcmp(cp,"extended") == 0) option_byte1 |= EXTENDED; else { fprintf(stderr,"acpconfig: -o %s invalid\n",cp); exit(1); } o_flag++; } break; case 's': /* select DDN standard X.25 service */ /* or basic X.25 service, accept -sn */ /* or -s n */ if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"\n acpconfig: '-s' flag invalid for"); fprintf(stderr," specified interface\n"); break; } ifr.ifr_data = 0; /* clear value */ if (!(*argv)[2]) { offset = 0; argc--; argv++; } else offset = 2; if (((*argv)[offset] >='0' && (*argv)[offset]< '3') && (*argv)[offset + 1] == 0) { (*argv)[offset] += SERVICE_VAL; /* match 'S','T','U' */ ifr.ifr_data = &((*argv)[offset]); } else if ((strncmp(&(*argv)[offset],"standard",8)==0) && (*argv)[offset + 8] == 0) { (*argv)[offset] = ACTUAL_VAL; /* match 'S' */ ifr.ifr_data = &((*argv)[offset]); } else if ((strncmp(&(*argv)[offset],"basic",5)==0) && (*argv)[offset + 5] == 0) { (*argv)[offset] = ACTUAL_VAL + 1; /* match 'T' */ ifr.ifr_data = &((*argv)[offset]); } else if ((strncmp(&(*argv)[offset],"pdn",3)==0) && (*argv)[offset + 3]==0) { (*argv)[offset] = ACTUAL_VAL + 2; /* 'U' */ ifr.ifr_data = &((*argv)[offset]); } else { fprintf(stderr, "\nacpconfig: invalid X.25 service\n"); usage();/* display proper syntax for user */ } if ((ifr.ifr_data == 0) || setconfig(ifr.ifr_data, s)) { if (errno == EALREADY) { fprintf(stderr,"acpconfig: must shut down interface to\ change modes between DDN and PDN\n"); exit(1); } } break; case 'u': { char *vp = *argv; /* value to set it to. */ char *cp; ifr.ifr_data = NULL; if (vp[2] == '\0') { argc--; /* value is next arg; fix pointers */ argv++; vp = *argv; } else vp += 2; /* value at 3rd char of this arg */ if (argc > 1) { fprintf(stderr, "-u command must be last on line\n"); exit(1); } if (strcmp(vp, "down") == 0 || *vp == '0') ifr.ifr_data = "0"; if (strcmp(vp, "dte") == 0 || *vp == '1') ifr.ifr_data = "1"; if (strcmp(vp, "dce") == 0 || *vp == '2') ifr.ifr_data = "2"; if (strcmp(vp, "ext") == 0 || *vp == '3') ifr.ifr_data = "3"; if (strcmp(vp, "int") == 0 || *vp == '4') ifr.ifr_data = "4"; if (ifr.ifr_data == 0) { fprintf(stderr,"acpconfig: -u invalid mode '%s'\n", *vp); usage(); /* display proper syntax for user */ } else { if ( setconfig(ifr.ifr_data, s) ) { if (errno == EADDRNOTAVAIL) { fprintf(stderr, "acpconfig: no local X.25 address \ translation in table; cannot start up PDN mode\n"); exit(1); } else { usage(); /* display proper syntax for user */ } } } } break; case 'f': /* control initiation of flow control */ /* parameters netgotiation. */ { char *cp; /* keyword determining which parameter */ /* to control*/ char *vp; /* value to set it to. */ cp = *argv; if (strlen (cp) > 2) /* handle -fNAME VAL and -f NAME VAL */ cp += 2; else { argc--; argv++; cp = *argv; if (cp == 0) { fprintf (stderr, "acpconfig: -f what?\n"); exit(1); } } argc--; argv++; vp = *argv; if (vp == 0) { fprintf (stderr, "acpconfig: -f %s what?\n", cp); exit(1); } if (strcmp(cp,"packet") == 0) ddactl.msg[0] = 0; else if (strcmp(cp,"window") == 0) ddactl.msg[0] = 1; else { fprintf(stderr,"acpconfig: -f %s invalid\n",cp); exit(1); } if (strcmp(vp,"on") == 0) ddactl.drval = 1; else if (strcmp(vp,"off") == 0) ddactl.drval = 0; else { fprintf(stderr,"acpconfig: -f %s invalid\n",cp); exit(1); } ddactl.func = 'f'; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } break; case 'h': /* histogram information */ { char *cp = *argv; struct timeval databuf[HISTSIZE]; register int i; if (strlen (cp) > 2) cp += 2; else { argc--; argv++; cp = *argv; if (cp == 0) { fprintf(stderr, "acpconfig: -h what?\n"); exit(1); } } *((char *)databuf) = (*cp == '1') ? 'H' : 'h'; ifr.ifr_data = (caddr_t) databuf; (void)strncpy (ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } if(*(cp+1) == 'r') { printf("%ld.%06ld\t",databuf[H_LINK_UP].tv_sec,databuf[H_LINK_UP].tv_usec); printf("%ld.%06ld",databuf[H_START].tv_sec,databuf[H_START].tv_usec); printf("\t%ld.%06ld",databuf[H_END].tv_sec,databuf[H_END].tv_usec); printf("\t%ld.%06ld",databuf[H_TMO].tv_sec,databuf[H_TMO].tv_usec); for(i = 0; i < H_LINK_UP; i++) printf("\t%ld.%06ld",databuf[i].tv_sec,databuf[i].tv_usec); printf("\n"); } else hist_data_out(databuf); } break; case 'm': /* Send supervisory message to FEP */ { char *mp = ddactl.msg; int i; static char *xfmt = "%x"; static char *ofmt = "%o"; bzero (ddactl.msg, sizeof (ddactl.msg)); while (--argc > 0) { argv++; if (*argv[0] == '-') { /* hit a non-number */ argc++; /* fix these guys for */ argv--; /* the main loop */ break; } if (mp > &ddactl.msg[sizeof (ddactl.msg)]) { fprintf (stderr,"\nacpconfig: -m message too long\n"); exit(1); } (void)sscanf (*argv, (**argv == '0') ? ofmt : xfmt, &i); *mp++ = i; } /* while */ ddactl.func = 'm'; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } break; case 'n': /* set SVC limit */ { char *ap = *argv; if (ap[2] == '\0') { argc--; /* value is next arg; fix pointers */ argv++; ap = *argv; } else ap += 2; /* value at 3rd char of this arg */ ddactl.func = 'n'; ddactl.drval = atoi(ap); (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } else if (*(int *)ifr.ifr_data != 0) printf("acpconfig: %s: %d circuits currently available.\n",name,*(int *)ifr.ifr_data); } break; case 'q': /* query board or driver for status */ { char *cp = *argv; int mode; if (strlen (cp) > 2) cp += 2; else { argc--; argv++; cp = *argv; if (cp == 0) { fprintf(stderr, "acpconfig: -q what?\n"); exit(1); } } mode = atoi(cp); ddactl.func = 'q'; ddactl.msg[0] = mode; ifr.ifr_data = (caddr_t) &ddactl; (void)strncpy (ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } switch (mode) { case 0: fmtstats(ddactl.msg); break; case 1: fmtmode(ddactl.msg); break; case 2: fmtsilo(ddactl.msg); break; } } break; case 't': /* set idle circuit timeout limit */ { char *ap = *argv; if (ap[2] == '\0') { argc--; /* value is next arg; fix pointers */ argv++; ap = *argv; } else ap += 2; /* value at 3rd char of this arg */ ddactl.func = 't'; ddactl.drval = atoi(ap); (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } break; case 'c': /* disable/enable driver console message */ { char *ap = *argv; int val; if (ap[2] == '\0') { argc--; /* value is next arg; fix pointers */ argv++; ap = *argv; } else ap += 2; /* value at 3rd char of this arg */ if ((ap == NULL) || (*ap == '-') || (*ap == '\0')) { fprintf(stderr, "\nacpconfig: no message number specified for -c\n"); exit(1); } ddactl.func = 'c'; val = ddactl.drval = atoi(ap); (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } else { printf("acpconfig: %s: Driver message #%d is now %s\n",name,val,*(u_char *)ifr.ifr_data ? "disabled" : "enabled"); } } break; case 'N': /* set net id */ { char *vp = *argv; /* value to set it to. */ char *cp; int net_type = -1; if (vp[2] == '\0') { argc--; /* value is next arg; fix pointers */ argv++; vp = *argv; } else vp += 2; /* value at 3rd char of this arg */ if (strcmp(vp, "transpac") == 0) net_type = NET_TRANSPAC; if (strcmp(vp, "0") == 0 || strcmp(vp, "standard") == 0) net_type = NET_STANDARD; if (net_type != -1) { ddactl.func = 'N'; ddactl.drval = net_type; ifr.ifr_data = (caddr_t) &ddactl; if (setconfig(&ifr.ifr_data, s)) exit(1); } if (net_type == NET_TRANSPAC || strcmp(vp, "net15") == 0) { /* allow 15 digit addrs */ ddactl.func = 'm'; bzero(ddactl.msg, sizeof (ddactl.msg)); bcopy("\140\0\0\2\177\17", ddactl.msg, 6); ifr.ifr_data = (caddr_t) &ddactl; if (setconfig(&ifr.ifr_data, s)) exit(1); } } break; case 'v': /* set variable */ { char *cp; /* keyword determining what to set */ char *vp; /* value to set it to. */ int i, val; /* * The ORDERING of this table must match the * cases in the processing for this ioctl * inside the driver (kludgy interface!) */ /* debug, dbgunit, and log are obsolete */ static char *nametab[] = { "log", "debug", "dbgunit", "packet", "window", 0 }; cp = *argv; if (strlen (cp) > 2) /* handle -vNAME VAL and -v NAME VAL */ cp += 2; else { argc--; argv++; cp = *argv; if (cp == 0) { fprintf (stderr, "acpconfig: -v what?\n"); exit(1); } } argc--; argv++; vp = *argv; if (vp == 0) { fprintf (stderr, "acpconfig: -v %s what?\n", cp); exit(1); } for (i = 0; nametab[i] != 0; i++) if (0 == strcmp (nametab[i], cp)) goto strmatch; fprintf (stderr, "acpconfig: -v: \"%s\" unknown\n", cp); exit(1); strmatch: /* hit the keyword, and "i" is its index */ if (i < 3) /* log, debug: masks: read in hexadecimal */ (void)sscanf (vp, "%x", &val); else /* window, packet: counts: read in decimal */ (void)sscanf (vp, "%d", &val); if (i == 3) { /* packet size: take base 2 log */ struct lg2tab *lp; /* * The sad thing is that after putting in all this * code to take the base 2 log, I realized that the * FEP takes this argument in BYTES and does the * log internally. Left the code in, though, since * it's the easiest way to check the argument. * (The driver converts to bytes with a shift). */ for (lp = lg2tab; lp->base2log; ++lp) if (lp->binval == val) { val = lp->base2log; goto goodsize; } fprintf (stderr, "acpconfig: -v: bad packet size\n"); exit(1); } goodsize: ddactl.drval = val; ddactl.msg[0] = i; ddactl.func = 'v'; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } break; case 'e': { char *cp = *argv; char databuf[10]; register int i; if (strlen (cp) > 2) cp += 2; else { argc--; argv++; cp = *argv; } databuf[0] = 'e'; i = get_bfrsize_index(cp); if(i == -1) exit(1); /* get_bfrsize_index will print error message */ else databuf[1] = i; ifr.ifr_data = (caddr_t) databuf; if (!setconfig(ifr.ifr_data, s)) fprintf(stderr,"\nacpconfig: buffer reset in progress, wait 1 minute\n"); break; } case 'z': /* reset the specified front-end device*/ ifr.ifr_data = &((*argv)[1]); if (!setconfig(ifr.ifr_data, s)) fprintf(stderr,"\nacpconfig: reset in progress, wait 1 minute\n"); break; case 'x': ifr.ifr_data = &((*argv)[1]); if (setconfig(ifr.ifr_data, s)) fprintf(stderr,"acpconfig: Could not create UCBs\n"); break; case 'A': /* add a file of address translation table entries */ /* accept "-A filename OR "-Afilename" */ if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"acpconfig: '-A' flag invalid for specified \ interface\n"); exit(1); } ifr.ifr_data = 0; /* clear value */ if (strlen(*argv) > 2) fp = fopen(&((*argv)[2]),"r"); else { argc--, argv++; fp = fopen(*argv,"r"); } if (fp==NULL) { fprintf(stderr,"acpconfig: cannot open file '%s'\n", ((*argv)[0] == '-') ? &((*argv)[2]) : *argv); exit(1); } fprintf(stdout, "acpconfig: processing file '%s'; please wait...\n", ((*argv)[0] == '-') ? &((*argv)[2]) : *argv); while (fgets(line, 80, fp) != NULL) { if (line[0] == '#' || line[0] == '\n') continue; (void)sscanf (line, "%s %s", arg1, arg2); /* fprintf(stdout, "acpconfig: processing translation %s ==> %s\n", arg1, arg2); */ if ((top=strlen(arg2)) > (MAXADDRLEN-1) || top < (MINADDRLEN-1)) { fprintf(stderr, "acpconfig: bad X.25 address length: '%s'\n", arg2); exit(1); } for (tmp=0; tmp<top; tmp++) if (arg2[tmp] > '9' || arg2[tmp] < '0') { fprintf(stderr, "acpconfig: invalid X.25 address '%s'\n", arg2); exit(1); } getaddr(arg1,&sin); trtab.func = 'a'; trtab.ipaddr = sin.sin_addr.s_addr; trtab.x25addr[0]=strlen(arg2); (void)strncpy((char *)&trtab.x25addr[1], arg2, MAXADDRLEN-1); ifr.ifr_data = (caddr_t)&trtab; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } (void)fclose(fp); break; case 'a': /* add an address translation table entry */ /* accept "-a inet_addr x25_addr" */ /* OR "-ainet_addr x25_addr" */ if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"acpconfig: '-a' flag invalid for specified \ interface\n"); exit(1); } ifr.ifr_data = 0; /* clear value */ if (strlen(*argv) > 2) getaddr(&((*argv)[2]),&sin); else { argc--, argv++; getaddr(*argv,&sin); } trtab.func = 'a'; trtab.ipaddr = sin.sin_addr.s_addr; argc--, argv++; if ((top=strlen(*argv)) > (MAXADDRLEN-1) || top < (MINADDRLEN-1)) { fprintf(stderr, "acpconfig: bad X.25 address length: '%s'\n", *argv); exit(1); } for (tmp=0; tmp<top; tmp++) if ((*argv)[tmp] > '9' || (*argv)[tmp] < '0') { fprintf(stderr, "acpconfig: invalid X.25 address '%s'\n", *argv); exit(1); } trtab.x25addr[0]=strlen(*argv); (void)strncpy((char *)&trtab.x25addr[1], *argv, MAXADDRLEN-1); ifr.ifr_data = (caddr_t)&trtab; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } break; case 'd': /* delete an address translation table entry */ /* accept "-d inet_addr" OR "-dinet_addr" */ if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"acpconfig: '-d' flag invalid for specified \ interface\n"); exit(1); } ifr.ifr_data = 0; /* clear value */ if (strlen(*argv) > 2) getaddr(&((*argv)[2]),&sin); else { argc--, argv++; getaddr(*argv,&sin); } trtab.func = 'd'; trtab.ipaddr = sin.sin_addr.s_addr; ifr.ifr_data = (caddr_t)&trtab; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } break; case 'D': if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"acpconfig: '-d' flag invalid for specified \ interface\n"); exit(1); } trtab.func = 'D'; ifr.ifr_data = (caddr_t)&trtab; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } break; case 'r': /* read an address translation table entry */ /* accept "-r length" OR "-rlength" */ if (iface & ACP_INTERFACE) { /* error if 'acp' device */ fprintf(stderr,"acpconfig: '-r' flag invalid for specified \ interface\n"); exit(1); } ifr.ifr_data = 0; /* clear value */ if (strlen(*argv) > 2) top = atoi(&((*argv)[2])); else { argc--, argv++; top = atoi(*argv); } if (top==0) top = 30000; /* (a big number) */ for (tmp=0; tmp<top; tmp++) { trtab.ipaddr = (u_long) tmp; trtab.func = 'r'; ifr.ifr_data = (caddr_t)&trtab; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { if (errno == EFAULT) { fprintf(stdout,"acpconfig: end of address table \ (%d entries max)\n", tmp); break; } else { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } /* * The byte ordering "works" on the inet_ntoa() call. * Probably only on VAXen, though (fine for us). */ if (trtab.x25addr[0]) { printf("acpconfig: address table entry %d: ", tmp); printf ("%s ==> %01.16s\n", inet_ntoa (trtab.ipaddr), &trtab.x25addr[1]); } } break; default: usage(); /* display proper syntax for user */ } } } /* * Send ioctl for gathered -o options. * Presently (08-31-87) the -o option supports only * one byte of options. If the number of firmware * supported options reaches 9, then a second byte * will be used. The driver must be modified if a * second byte is used. The value of PKT_OPTIONS * must be changed from 0x77 to 0xB7 to notify the * FE that PKT_OPTIONS is a 2-Byte Valued ID. */ if (o_flag) { /* send ioctl for gathered options */ ddactl.func = 'o'; ddactl.msg[0] = option_byte1; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t) &ddactl; if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); exit(1); } } /* * if simulation, simply return to main loop of test jig */ #ifndef SIMULATION exit(0); #endif } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% SETIFADDR() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* Set the interface address. */ /* */ /* Call: setifaddr(addr) */ /* Arguments: addr: internet address */ /* Returns: nothing */ /* Called by: main() */ /* Calls to: getaddr() */ /* strncpy() */ /* ioctl() */ /* Perror() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ setifaddr(addr) char *addr; { getaddr(addr, (struct sockaddr_in *)&ifr.ifr_addr); (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCSIFADDR, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCSIFADDR)"); exit(1); } } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% GETADDR() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* THIS ROUTINE IS SLOW AS MOLASSES - - FIX IT SOONER OR LATER !!! */ /* Purpose: */ /* */ /* Get the interface address and stick it in the appropriate */ /* data structure. This routine has four different methods for */ /* deriving the address. If successful return nothing, else */ /* print error message and exit. */ /* */ /* */ /* Call: getaddr(s, sin) */ /* Arguments: s: string for address */ /* sin: socket address struct */ /* Returns: nothing for success, else error message exit */ /* Called by: setifaddr() */ /* Calls to: gethostbyname() */ /* bcopy() */ /* getnetbyname() */ /* inet_makeaddr() */ /* inet_addr() */ /* inet_network() */ /* fprintf() */ /* exit() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ struct in_addr inet_makeaddr(); getaddr(s, sin) char *s; struct sockaddr_in *sin; { struct hostent *hp, #ifdef VAXVMS *_gethtbyname(); #else VAXVMS *gethostbyname(); #endif VAXVMS struct netent *np; int val; sin->sin_family = AF_INET; val = inet_addr(s); if (val != -1) { sin->sin_addr.s_addr = val; return; } #ifdef VAXVMS hp = _gethtbyname(s); /* Use host table, not name server */ #else VAXVMS # ifdef SIMULATION hp = 0; /* don't find our address by host name */ # else SIMULATION hp = gethostbyname(s); # endif SIMULATION #endif VAXVMS if (hp) { sin->sin_family = hp->h_addrtype; bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length); return; } np = getnetbyname(s); if (np) { sin->sin_family = np->n_addrtype; sin->sin_addr = inet_makeaddr((int)np->n_net, INADDR_ANY); return; } sin->sin_family = AF_INET; val = inet_addr(s); if (val != -1) { sin->sin_addr.s_addr = val; return; } val = inet_network(s); if (val != -1) { sin->sin_addr = inet_makeaddr(val, INADDR_ANY); return; } fprintf(stderr, "acpconfig: invalid internet address '%s'\n", s); exit(1); } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% SETCONFIG() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* Set the configuration parameters by sending socket ioctl */ /* to the specified interface driver. */ /* */ /* */ /* Call: setconfig(action, s) */ /* Arguments: action indicates action to be taken */ /* s socket descriptor */ /* Returns: 0 for success, nonzero for failure */ /* NOTE: if no internet address, doesn't return, */ /* program exits */ /* Called by: main() */ /* Calls to: fprintf() */ /* strncpy() */ /* sizeof() */ /* ioctl() */ /* Perror() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ setconfig(action, s) char *action; int s; { extern int errno; int saves; if (action == 0) return(1); saves = s; (void)strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); if (ioctl(s, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { if (errno == EINTR) { fprintf(stderr,"\nacpconfig: command in progress\n"); NEW_DELAY(3000000); /* wait for device pwrup diags */ if (ioctl(saves, SIOCACPCONFIG, (caddr_t)&ifr) < 0) { Perror("ioctl (SIOCACPCONFIG) returns"); return(1); } else return(0); } else { Perror("ioctl (SIOCACPCONFIG) returns"); return(1); } } return(0); } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% USAGE() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* Display the correct syntax for the acpconfig command line. */ /* */ /* Call: usage() */ /* Returns: nothing */ /* Called by: main() */ /* Calls to: fprintf() */ /* exit() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ static char *usemsg = "Usage: acpconfig interface [address] [-A filename] [-a ipaddr x25addr]\n\ \t[-b baud] [-c msgnum] [-d ipaddr] [-D] [-e size] [-f facility status]\n\ \t[-h mode[r]] [-l] [-m message] [-n circuits] [-o option]\n\ \t[-q type] [-r count] [-s X.25_service] [-t secs]\n\ \t[-u mode] [-v variable value] [-z]\n"; usage() { fprintf(stderr, usemsg); fprintf(stderr, "\nacpconfig generation %s\n", VERSION); exit(1); } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% LONG_USAGE() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* Display the correct syntax for the acpconfig command line. */ /* This routine is called when no arguments are passed to */ /* acpconfig, this generally indicates that the user want to see */ /* the usage line as opposed to making a mistake in the */ /* arguments */ /* */ /* Call: usage() */ /* Returns: nothing */ /* Called by: main() */ /* Calls to: fprintf() */ /* exit() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ static char *longusemsg = "Usage: acpconfig interface [address] \n\ [-a ipaddr x25addr] : add a single IP to X.25 address translation (PDN only)\n\ [-A filename] : read IP to X.25 addr translations from file (PDN only)\n\ [-b baud] : set baud rate to baud. 0 designates external clocking\n\ [-c msgnum] : enable/disable driver console message\n\ [-d ipaddr] : delete an IP to X.25 translation (PDN only)\n\ [-D] : delete all IP to X.25 translations (PDN only)\n\ [-e size] : set front-end buffer size\n\ [-f facility status] : control initiation of flow control negotiation\n\ status is \"on\" or \"off\"; facility is \"packet\" or\n\ \"window\"\n\ [-h mode[r]] : print statistics on logical circuit usage\n\ mode is 0 (read) or 1 (read and reset); \"r\"\n\ specifies raw mode\n\ [-l[n]] : display status of each active logical channel\n\ the optional \"n\" argument will cause acpconfig\n\ [-m message] : send specified supervisor message\n\ [-n circuits] : set number of virtual circuits\n\ [-N net] : set network type; values for net are one of:\n\ transpac - the French Transpac network\n\ net15 - any network using 15 digit addresses\n\ default - standard network configuration\n\ [-o option] : set or disable extended clear handling; option is\n\ \"extended\" or \"none\"\n\ [-q type] : query driver or front end status; type is 0 for\n\ front end, 1 for driver\n\ [-r count] : read and print address translation table; count\n\ is number of translations to read; 0 means all\n\ [-s X.25_service] : specify DDN standard, DDN basic or PDN service;\n\ X.25_service is: \"standard\", \"basic\" or \"pdn\"\n\ [-t secs] : set the idle circuit timeout to secs seconds\n\ [-u mode] : set interface mode to:\n\ down - disable interface\n\ dte - online as DTE\n\ dce - online as DCE\n\ ext - external loopback\n\ int - internal loopback\n\ [-v variable value] : set driver variable; variable/values are one of:\n\ packet DDD - set X.25 packet size to DDD decimal\n\ window DDD - set X.25 window size to DDD decimal\n\ [-z] : reset the board\n"; long_usage() { fprintf(stderr, longusemsg); fprintf(stderr, "\nacpconfig generation %s\n", VERSION); exit(1); } /*@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /*%% PERROR() %%*/ /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ /* */ /* Purpose: */ /* */ /* print error message, based on errno */ /* */ /* Call: Perror(cmd) */ /* Arguments: cmd: error message */ /* Returns: nothing, exits if no internet address is set */ /* Called by: main() */ /* Calls to: fprintf() */ /* perror() */ /* */ /*##%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ Perror(cmd) char *cmd; { extern int errno; fprintf(stderr, "acpconfig: "); switch (errno) { case ENXIO: fprintf(stderr, "%s: ", cmd); fprintf(stderr, "no such interface\n"); break; case EPERM: fprintf(stderr, "permission denied\n"); break; case EDESTADDRREQ: fprintf(stderr, "%s: ", cmd); fprintf(stderr, "no internet address assigned to interface\n"); usage(); /* display proper syntax for user */ exit(1); break; case EINVAL: fprintf(stderr, "%s: ", cmd); fprintf(stderr, "invalid command\n"); break; case EINTR: fprintf(stderr, "%s: ", cmd); fprintf(stderr, "device not operational\n"); break; case EINPROGRESS: fprintf(stderr, "%s: ", cmd); fprintf (stderr, "Can't change parameters with link up\n"); fprintf (stderr, "Bring the link down and try again\n"); break; case ENOPROTOOPT: fprintf (stderr, "%s: ", cmd); fprintf (stderr, "Operation not supported by this version of the firmware.\n"); break; default: perror(cmd); } } /* * from SAGE::PROJECT:[X25.ACP5250W.HCOMMON]NCP.H on */ struct stat_rsp { u_char cmnd, path, var, count; /* message header */ u_long uptime; /* seconds since startup */ u_long elapsed; /* tenths since last statistics response */ u_long frames_sent; /* frames and... */ u_long bytes_sent; /* bytes transmitted */ u_long frames_rcvd; /* frames and... */ u_long bytes_rcvd; /* bytes received */ u_short SABMs_sent; /* similarly for SABMs, */ u_short SABMs_rcvd; u_short DISCs_sent; /* DISCs */ u_short DISCs_rcvd; u_short FRMRs_sent; /* FRMRs */ u_short FRMRs_rcvd; u_short RRs_sent; /* RRs */ u_short RRs_rcvd; u_short REJs_sent; /* REJs */ u_short REJs_rcvd; u_short RNRs_sent; /* RNRs */ u_short RNRs_rcvd; u_short crc_errors; /* CRC errors received */ u_short bad_frames; /* invalid frames received */ u_short rexmitted; /* I-frames RE-transmitted */ u_short UAs_sent; /* UAs transmitted, received */ u_short UAs_rcvd; u_short DMs_sent; /* DMs transmitted, received */ u_short DMs_rcvd; u_short I_frames_sent; /* I frames transmitted, received */ u_short I_frames_rcvd; }; /* * A long time ago in a UNIBUS far, far away, there was a Z80 based * front end processor happily talking to its PDP-11 host. They * exchanged many cheerful messages, some of which were statistics * queries. The statistics query was defined in the only logical * format, the format shared by both the Z80 and its PDP-11 host. * Well, thousands of computer generations passed, and the little * Z80 grew up into a big, strong 68000 based front end. His * friendly little PDP-11 host grew up too, into a big honkin' * VAX. They still liked to exchange cheerful messages, though, * and some of those were still the same well-worn statistics * queries, which are still in the only "logical" data format. * So don't ask again why a VAX and a 68000 exchange data in Z80 * byte ordering! */ #define z80toVAX(l) (((l) << 16) | (((l) >> 16) & 0xFFFF)) #ifdef __GNU__ /* gnu compiler prefers ANSII C */ #define pr(A) printf("%-10s%10d%10d\n", #A, sp->A##_sent, sp->A##_rcvd) #else /* idiot compiler */ #define pr(A) printf("%-10s%10d%10d\n", "A", sp->A/**/_sent, sp->A/**/_rcvd) #endif /* * internal routines for use by query commands */ fmtstats (buf) char *buf; { register struct stat_rsp *sp = (struct stat_rsp *) buf; struct timeval t; char *cp; sp->elapsed = z80toVAX (sp->elapsed); sp->uptime = z80toVAX (sp->uptime); sp->frames_sent = z80toVAX (sp->frames_sent); sp->frames_rcvd = z80toVAX (sp->frames_rcvd); sp->bytes_sent = z80toVAX (sp->bytes_sent); sp->bytes_rcvd = z80toVAX (sp->bytes_rcvd); (void)gettimeofday (&t, (struct timezone *)0); cp = ctime (&t.tv_sec); cp[24] = '\0'; /* get rid of the embedded newline */ printf ("\n----------------------------------------------\n"); printf ("Front End Processor statistics (host time: %s)\n", cp); t.tv_sec -= sp->uptime; cp = ctime (&t.tv_sec); cp[24] = '\0'; printf ("FEP up %d seconds (since %s)\n", sp->uptime, cp); t.tv_sec += sp->uptime; t.tv_sec -= sp->elapsed; cp = ctime (&t.tv_sec); cp[24] = '\0'; printf ("%d seconds since last statistics (at %s)\n", sp->elapsed, cp); /* ---- debugging stuff printf ("cmnd = %x path = %x var = %x count = %x\n", sp->cmnd, sp->path, sp->var, sp->count); ---- */ printf ("\n%20s%10s\n", "SENT", "RCVD"); pr (frames); pr (bytes); pr (I_frames); pr (SABMs); pr (DISCs); pr (FRMRs); pr (RRs); pr (REJs); pr (RNRs); pr (UAs); pr (DMs); printf ("\n%d CRC errors; %d bad frames; %d frames retransmitted\n", sp->crc_errors, sp->bad_frames, sp->rexmitted); printf ("--------------- END OF STATISTICS -----------------\n\n"); } /* * This is disgustingly ugly. The whole interface between acpconfig * and the driver has gotten completely out of hand. Has to do with * the fact that we want this program to be compatible with both * ULTRIX and BSD and they have different include file structures AND * historically many of the structures weren't even IN include files! * * buf: * dda_state, dda_init, dda_flags, dda_firmrev */ fmtmode (buf) char *buf; { static char *brd_modes[] = { "DISABLED", "COMING UP", "UP", "GOING DOWN" }; printf ("\n>>> Driver status for %s (Interface is %s) <<<\n", name, brd_modes[*buf & 3]); buf++; printf ("\tMode 0x%x ", (u_char)*buf); if (*buf & 0x1) printf ("<DDN_STANDARD>\n"); if (*buf & 0x2) printf ("<DDN_BASIC>\n"); if (*buf & 0x4) printf ("<PDN>\n"); if (*buf & 0x40) printf ("\t<Packet Size Facility Negotiation Initiation Enabled>\n"); if (*buf & 0x80) printf ("\t<Window Size Facility Negotiation Initiation Enabled>\n"); buf++; if (*buf == 0) printf ("\tWarning, DDAF_OK is OFF <--------------\n"); else printf ("\tInterface on-line (DDAF_OK is ON)\n"); buf++; printf ("\tFirmware revision %d.%d installed\n", (*buf >> 4) & 0xF, *buf & 0xF); buf++; printf ("*** End of driver status information ***\n\n"); } fmtsilo (buf) unsigned char *buf; { int i, j; for (j = 0; j < 256; j += 16) { for (i = 0; i < 16; i++) printf("%02x ", buf[j+i]); for (i = 0; i < 16; i++) putchar(isalpha(buf[j+i]) ? buf[j+i] : '.'); printf("\n");; } } /* print out data from the histogram request */ double tval_dbl(tv) struct timeval *tv; { return((double)tv->tv_sec+(double)tv->tv_usec / (double)1000000.0); } hist_data_out(times) struct timeval times[]; { register int i; double percents[HISTSIZE]; double totaltime; char *p, *p1; totaltime = tval_dbl(times+H_END) - tval_dbl(times+H_START); for(i = 0; i <= H_LINK_UP; i++) percents[i] = tval_dbl(times+i) / totaltime; p1 = p = ctime(×[H_START].tv_sec); while(*p) { if(*p == '\n') *p = ' '; *p++; } printf("START: %s",p1); p1 = p = ctime(×[H_END].tv_sec); while(*p) { if(*p == '\n') *p = ' '; *p++; } printf("\t\tEND: %s\n",p1); printf("total time: %6.2f seconds",totaltime); printf("\ttime up: %ld seconds (%3.2f%%)\n",times[H_LINK_UP].tv_sec, percents[H_LINK_UP]*100.0); printf("idle circuit timeout: %ld seconds\n",times[H_TMO].tv_sec); for(i = 0; i < H_LINK_UP; i++) { if(percents[i] <= 0.0) continue; printf("%3d %6.2f\n",i,percents[i]*100.0); } } /* Revision History: 9-AUG-1987 Steph Price V2.3 Add new -f option for controlling the initiation of flow control parameter negotiation. The default in the driver is no flow control parameter negotiation initiation. To turn on packet or window size negotiation initiation, issue the new acpconfig commands: -f packet on -f window on To turn off initiation: -f packet off -f window off Note that these options are valid only on a per call basis. If a circuit is already open for the requested destination, the status of flow control parameter negotiation initiation can't be altered until the circuit is cleared either by timing out or by a reset. Add "external" argument to the -b option. Add new arguments to the -s option. They are as follows: -s standard (equivalent to -s 0) -s basic (equivalent to -s 1) -s pdn (equivalent to -s 2) SERVICE_VAL was modified to accomodate the new arguments. Previously the driver expected arguments of s, t, and u to be passed for the -s 0, -s 1, and -s 2 options. Since an argument of v is already in use, use of the -s0/standard option will result in the use of 'S' as an argument to the driver's ioctl routine. Similarly, 'T', 'U', and 'V' will be passed for the -s1/basic, -s2/pdn, and -s3/class_b_c options. Add the -o option to enable root to select extended clear and extended clear confirmation packets as the first step toward X.25 1984 compatability. Add the -l option to enable root to display the status of each active lcn. Modify reset case to check for returned value before printing a message saying that a reset is in progress. Fix bug in -n case. The interface was not given. 25-OCT-87 Stephanie Price Modified -l option to used /dev/kmem instead of /dev/mem. Removed mask of high order bit in klseek() routine. 6-NOV-87 Brad Engstrom Add -D flag 11-NOV-87 Brad Engstrom Add -h and -H histogram flags 18-NOV-87 Brad Engstrom Changed -A option handling so that acpconfig does not exit upon seeing an address already in use error. 18-DEC-87 Brad Engstrom Added -t options to set the idle circuit timeout value to a certain number of seconds. 21-APR-88 Brad Engstrom Added the -v dbgunit option to the -v flag to set the debug unit variable in the driver. 22-APR-88 Brad Engstrom Added the -c command to enable or disable driver console messages. Each use of the command for a particular message will toggle the message status. 26-APR-88 Brad Engstrom Modified the -n command so that a command of the form "-n 0" will print the number of circuits currently available. Also the -l command uses this information to print the number of circuits free. This allows the new driver to work with old firmware easier. 10-MAY-88 Brad Engstrom Made all references to the length of an X.25 address refer to theo constants MAXADDRLEN and MINADDRLEN which are defined in if_ddavar.h. 26-JAN-89 Steve Johnson Added -N option to support TRANSPAC net. Merged in extra TWG support. 15-FEB-89 Paul Traina Fixed bug with -N command parsing. Implemented an improved form of Brad's changes for Transpac. 17-FEB-89 Paul Traina Installed Multinet support. 10-MAR-89 Paul Traina Installed simulation support. 13-MAR-89 Paul Traina Installed support for undocumented -q 2 command. 31-MAY-89 Paul Traina Updated command parsing on -u fixed documentation. 20-JUN-89 Paul Traina Obsoleted -v debug and -v dbg_unit commands. New driver is *NOT* compatible with the old crufty debugging format. 26-JUN-89 Paul Traina Removed the tolower()'s on -u and -N arguments. Reinstalled Charles' changes to 3.1 acpconfig for -ln Fixed things so -h w/o an argument doesn't core. 19-Jul-89 Paul Traina Changed version date id due to incompatible changes in the dc structure located in if_ddavar.h 13-Nov-89 Paul Traina Changed query ioctl interface. Incompatible with old drivers. End of Revision History */