home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / packet / n17jsrc / nrcmd.c < prev    next >
C/C++ Source or Header  |  1991-10-18  |  28KB  |  1,190 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5. /* Mods by G1EMM and PA0GRI */
  6.  
  7. #include <stdio.h>
  8. #include <ctype.h>
  9. #include <time.h>
  10. #include "config.h"
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "ax25.h"
  14. #include "mailbox.h"
  15. #include "netrom.h"
  16. #include "nr4.h"
  17. #include "timer.h"
  18. #include "iface.h"
  19. #include "pktdrvr.h"
  20. #include "lapb.h"
  21. #include "cmdparse.h"
  22. #include "session.h"
  23. #include "socket.h"
  24. #include "commands.h"
  25. #include "files.h"
  26.  
  27. char Nr4user[AXALEN];
  28.  
  29. char *Nr4states[] = {
  30.     "Disconnected",
  31.     "Conn Pending",
  32.     "Connected",
  33.     "Disc Pending",
  34.     "Listening"
  35. } ;
  36.  
  37. char *Nr4reasons[] = {
  38.     "Normal",
  39.     "By Peer",
  40.     "Timeout",
  41.     "Reset",
  42.     "Refused"
  43. } ;
  44. static int dobcnodes __ARGS((int argc,char *argv[],void *p));
  45. static int dointerface __ARGS((int argc,char *argv[],void *p));
  46. static int donfadd __ARGS((int argc,char *argv[],void *p));
  47. static int donfdrop __ARGS((int argc,char *argv[],void *p));
  48. static int donfdump __ARGS((void));
  49. static int donfmode __ARGS((int argc,char *argv[],void *p));
  50. static int donodefilter __ARGS((int argc,char *argv[],void *p));
  51. static int donodetimer __ARGS((int argc,char *argv[],void *p));
  52. static int donracktime __ARGS((int argc,char *argv[],void *p));
  53. static int donrchoketime __ARGS((int argc,char *argv[],void *p));
  54. static int donrconnect __ARGS((int argc,char *argv[],void *p));
  55. static int donrirtt __ARGS((int argc,char *argv[],void *p));
  56. static int donrkick __ARGS((int argc,char *argv[],void *p));
  57. static int dorouteadd __ARGS((int argc,char *argv[],void *p));
  58. static int doroutedrop __ARGS((int argc,char *argv[],void *p));
  59. static int donrqlimit __ARGS((int argc,char *argv[],void *p));
  60. static int donrreset __ARGS((int argc,char *argv[],void *p));
  61. static int donrretries __ARGS((int argc,char *argv[],void *p));
  62. static int donrroute __ARGS((int argc,char *argv[],void *p));
  63. static int donrstatus __ARGS((int argc,char *argv[],void *p));
  64. static int donrsave __ARGS((int argc,char *argv[],void *p));
  65. static int donrload __ARGS((int argc,char *argv[],void *p));
  66. static int donrttl __ARGS((int argc,char *argv[],void *p));
  67. static int donruser __ARGS((int argc,char *argv[],void *p));
  68. static int donrverbose __ARGS((int argc,char *argv[],void *p));
  69. static int donrwindow __ARGS((int argc,char *argv[],void *p));
  70. static void doobsotick __ARGS((void));
  71. static int doobsotimer __ARGS((int argc,char *argv[],void *p));
  72. static int dominquality __ARGS((int argc,char *argv[],void *p));
  73. static int donrtype __ARGS((int argc,char *argv[],void *p));
  74. static int donrpromisc __ARGS((int argc,char *argv[],void *p));
  75. static int donrderate __ARGS((int argc,char *argv[],void *p));
  76.  
  77. static struct cmds Nrcmds[] = {
  78.     "acktime",    donracktime,    0, 0,    NULLCHAR,
  79.     "bcnodes",    dobcnodes,    0, 2,    "netrom bcnodes <interface>",
  80.     "connect",    donrconnect, 1024, 2,    "netrom connect <node>",
  81.     "choketime",    donrchoketime,    0, 0,    NULLCHAR,
  82.     "derate",    donrderate,    0, 0,    NULLCHAR,
  83.     "interface",    dointerface,    0, 4,
  84.         "netrom interface <interface> <alias> <quality>",
  85.     "irtt",        donrirtt,    0, 0,    NULLCHAR,
  86.     "kick",        donrkick,    0, 2,    "netrom kick <&nrcb>",
  87.     "load",        donrload,    0, 0,    NULLCHAR,
  88.     "minquality",    dominquality,    0, 0,    NULLCHAR,
  89.     "nodefilter",    donodefilter,    0, 0,    NULLCHAR,
  90.     "nodetimer",    donodetimer,    0, 0,    NULLCHAR,
  91.     "obsotimer",    doobsotimer,    0, 0,    NULLCHAR,
  92.     "promiscuous",    donrpromisc,    0, 0,    NULLCHAR,
  93.     "qlimit",    donrqlimit,    0, 0,    NULLCHAR,
  94.     "reset",    donrreset,    0, 2,    "netrom reset <&nrcb>",
  95.     "retries",    donrretries,    0, 0,    NULLCHAR,
  96.     "route",    donrroute,    0, 0,    NULLCHAR,
  97.     "status",    donrstatus,    0, 0,    NULLCHAR,
  98.     "save",        donrsave,    0, 0,    NULLCHAR,
  99.     "timertype",    donrtype,    0, 0,    NULLCHAR,
  100.     "ttl",        donrttl,    0, 0,    NULLCHAR,
  101.     "user",        donruser,    0, 0,    NULLCHAR,
  102.     "verbose",    donrverbose,    0, 0,    NULLCHAR,
  103.     "window",    donrwindow,    0, 0,    NULLCHAR,
  104.     NULLCHAR,
  105. } ;
  106.  
  107. static struct timer Nodetimer ;    /* timer for nodes broadcasts */
  108. static struct timer Obsotimer ;    /* timer for aging routes */
  109.  
  110. /* Command multiplexer */
  111. int
  112. donetrom(argc,argv,p)
  113. int argc ;
  114. char *argv[] ;
  115. void *p;
  116. {
  117.     return subcmd(Nrcmds,argc,argv,p) ;
  118. }
  119.  
  120. static struct cmds Routecmds[] = {
  121.     "add",    dorouteadd,    0, 6,
  122.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  123.     "drop",    doroutedrop, 0, 4,
  124.         "netrom route drop <destination> <neighbor> <interface>",
  125.     "info", dorouteinfo, 0, 2,
  126.         "netrom route info <destination>",
  127.     NULLCHAR,
  128. } ;
  129.  
  130. /* Route command multiplexer */
  131. static int
  132. donrroute(argc, argv,p)
  133. int argc ;
  134. char *argv[] ;
  135. void *p;
  136. {
  137.     if(argc < 2) {
  138.         doroutedump() ;
  139.         return 0 ;
  140.     }
  141.     return subcmd(Routecmds,argc,argv,p) ;
  142. }
  143.  
  144. /* Dump a list of known routes */
  145. int
  146. doroutedump()
  147. {
  148.     register struct nrroute_tab *rp ;
  149.     register int i, column ;
  150.     char buf[16] ;
  151.     char *cp ;
  152.     
  153.     column = 1 ;
  154.     
  155.     for(i = 0 ; i < NRNUMCHAINS ; i++)
  156.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  157.             strcpy(buf,rp->alias) ;
  158.             /* remove trailing spaces */
  159.             if((cp = strchr(buf,' ')) == NULLCHAR)
  160.                 cp = &buf[strlen(buf)] ;
  161.             if(cp != buf)        /* don't include colon for null alias */
  162.                 *cp++ = ':' ;
  163.             pax25(cp,rp->call) ;
  164.             tprintf("%-16s  ",buf) ;
  165.             if(column++ == 4) {
  166.                 if(tprintf("\n") == EOF)
  167.                     return 0;
  168.                 column = 1 ;
  169.             }
  170.         }
  171.  
  172.     if(column != 1)
  173.         tprintf("\n") ;
  174.         
  175.     return 0 ;
  176. }
  177.  
  178. /* print detailed information on an individual route */
  179. int
  180. dorouteinfo(argc,argv,p)
  181. int argc ;
  182. char *argv[] ;
  183. void *p;
  184. {
  185.     register struct nrroute_tab *rp ;
  186.     register struct nr_bind *bp ;
  187.     register struct nrnbr_tab *np ;
  188.     char dest[AXALEN] ;
  189.     char neighbor[AXBUF] ;
  190.  
  191.     if(setcall(dest,argv[1]) == -1) {
  192.         tprintf("bad destination name\n") ;
  193.         return -1 ;
  194.     }
  195.         
  196.     if((rp = find_nrroute(dest)) == NULLNRRTAB) {
  197.         tprintf("no such route\n") ;
  198.         return -1 ;
  199.     }
  200.  
  201.     for(bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  202.         np = bp->via ;
  203.         if(tprintf("%1s %3d  %3d  %-8s  %s\n",
  204.          (bp->flags & NRB_PERMANENT ? "P" :
  205.          bp->flags & NRB_RECORDED ? "R" : " "),
  206.          bp->quality,bp->obsocnt,
  207.          Nrifaces[np->iface].iface->name,
  208.          pax25(neighbor,np->call)) == EOF)
  209.             break;
  210.     }
  211.     return 0 ;
  212. }
  213.         
  214. /* convert a null-terminated alias name to a blank-filled, upcased */
  215. /* version.  Return -1 on failure. */
  216. int
  217. putalias(to,from,complain)
  218. register char *to, *from ;
  219. int complain ;    
  220. {
  221.     int len, i ;
  222.     
  223.     if((len = strlen(from)) > ALEN) {
  224.         if(complain)
  225.             tprintf("alias too long - six characters max\n") ;
  226.         return -1 ;
  227.     }
  228.     
  229.     for(i = 0 ; i < ALEN ; i++) {
  230.         if(i < len) {
  231.             if(islower(*from))
  232.                 *to++ = toupper(*from++) ;
  233.             else
  234.                 *to++ = *from++ ;
  235.         }
  236.         else
  237.             *to++ = ' ' ;
  238.     }
  239.             
  240.     *to = '\0' ;
  241.     return 0 ;
  242. }
  243.  
  244. /* Add a route */
  245. static int
  246. dorouteadd(argc, argv,p)
  247. int argc ;
  248. char *argv[] ;
  249. void *p;
  250. {
  251.     char alias[AXALEN] ;
  252.     char dest[AXALEN] ;
  253.     unsigned quality ;
  254.     char neighbor[AXALEN] ;
  255.     register int i ;
  256.     int naddr ;
  257.  
  258.     /* format alias (putalias prints error message if necessary) */
  259.     if(putalias(alias,argv[1],1) == -1)
  260.         return -1 ;
  261.  
  262.     /* format destination callsign */
  263.     if(setcall(dest,argv[2]) == -1) {
  264.         tprintf("bad destination callsign\n") ;
  265.         return -1 ;
  266.     }
  267.  
  268.     /* find interface */
  269.     for(i = 0 ; i < Nr_numiface ; i++)
  270.         if(!strcmp(Nrifaces[i].iface->name,argv[3]))
  271.             break ;
  272.     if(i == Nr_numiface) {
  273.         tprintf("Interface \"%s\" not found\n",argv[3]) ;
  274.         return -1 ;
  275.     }
  276.     
  277.     /* get and check quality value */
  278.     if((quality = atoi(argv[4])) > 255) {
  279.         tprintf("maximum route quality is 255\n") ;
  280.         return -1 ;
  281.     }
  282.  
  283.     /* Change from 871225 -- no digis in net/rom table */
  284.     naddr = argc - 5 ;
  285.     if(naddr > 1) {
  286.         tprintf("Use the ax25 route command to specify digipeaters\n") ;
  287.         return -1 ;
  288.     }
  289.     
  290.     /* format neighbor address string */
  291.     setcall(neighbor,argv[5]) ;
  292.  
  293.     return nr_routeadd(alias,dest,i,quality,neighbor,1,0) ;
  294. }
  295.  
  296.  
  297. /* drop a route */
  298. static int
  299. doroutedrop(argc,argv,p)
  300. int argc ;
  301. char *argv[] ;
  302. void *p;
  303. {
  304.     char dest[AXALEN], neighbor[AXALEN] ;
  305.     register int i ;
  306.  
  307.     /* format destination and neighbor callsigns */
  308.     if(setcall(dest,argv[1]) == -1) {
  309.         tprintf("bad destination callsign\n") ;
  310.         return -1 ;
  311.     }
  312.     if(setcall(neighbor,argv[2]) == -1) {
  313.         tprintf("bad neighbor callsign\n") ;
  314.         return -1 ;
  315.     }
  316.  
  317.     /* find interface */
  318.     for(i = 0 ; i < Nr_numiface ; i++)
  319.         if(!strcmp(Nrifaces[i].iface->name,argv[3]))
  320.             break ;
  321.     if(i == Nr_numiface) {
  322.         tprintf("Interface \"%s\" not found\n",argv[3]) ;
  323.         return -1 ;
  324.     }
  325.  
  326.     return nr_routedrop(dest,neighbor,i) ;
  327. }
  328.     
  329.     
  330. /* make an interface available to net/rom */
  331. static int
  332. dointerface(argc,argv,p)
  333. int argc ;
  334. char *argv[] ;
  335. void *p;
  336. {
  337.     int i ;
  338.     register struct iface *ifp ;
  339.  
  340.     if(Nr_iface == NULLIF) {
  341.         tprintf("Attach netrom interface first\n") ;
  342.         return 1 ;
  343.     }
  344.     
  345.     if(Nr_numiface >= NRNUMIFACE) {
  346.         tprintf("Only %d net/rom interfaces available\n",NRNUMIFACE) ;
  347.         return 1 ;
  348.     }
  349.     
  350.     if((ifp = if_lookup(argv[1])) == NULLIF){
  351.         tprintf("Interface \"%s\" unknown\n",argv[1]);
  352.         return 1;
  353.     }
  354.     if( ifp->type != CL_AX25){
  355.         tprintf("Interface %s is not NETROM compatible\n",argv[1]);
  356.         return 1;
  357.     }
  358.     for(i = 0 ; i < Nr_numiface ; i++)
  359.         if(Nrifaces[i].iface == ifp) {
  360.             tprintf("Interface \"%s\" is already registered\n",argv[1]) ;
  361.             return 1 ;
  362.         }
  363.         
  364.     Nrifaces[Nr_numiface].iface = ifp ;
  365.  
  366.     if(putalias(Nrifaces[Nr_numiface].alias,argv[2],1) == -1)
  367.         return 1 ;
  368.         
  369.     if((Nrifaces[Nr_numiface].quality = atoi(argv[3])) > 255) {
  370.         tprintf("Quality cannot be greater than 255\n") ;
  371.         return 1 ;
  372.     }
  373.         
  374.     Nr_numiface++ ;            /* accept this interface */
  375.     return 0 ;
  376. }
  377.  
  378. /* Broadcast nodes list on named interface. */
  379. static int
  380. dobcnodes(argc,argv,p)
  381. int argc ;
  382. char *argv[] ;
  383. void *p;
  384. {
  385.     register int i,j;
  386.  
  387.     for(i = 0 ; i < Nr_numiface ; i++)
  388.         if(!strcmp(Nrifaces[i].iface->name,argv[1]))
  389.             break ;
  390.     if(i == Nr_numiface) {
  391.         tprintf("Interface \"%s\" not found\n",argv[1]) ;
  392.         return 1 ;
  393.     }
  394.         
  395.     nr_bcnodes(i) ;
  396.     return 0;
  397. }
  398.  
  399. /* Set outbound node broadcast interval */
  400. static int
  401. donodetimer(argc,argv,p)
  402. int argc;
  403. char *argv[];
  404. void *p;
  405. {
  406.     if(argc < 2){
  407.         tprintf("Nodetimer %lu/%lu seconds\n",
  408.             read_timer(&Nodetimer)/1000L,
  409.             dur_timer(&Nodetimer)/1000L);
  410.         return 0;
  411.     }
  412.     stop_timer(&Nodetimer) ;    /* in case it's already running */
  413.     Nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  414.     Nodetimer.arg = NULLCHAR;        /* dummy value */
  415.     set_timer(&Nodetimer,atoi(argv[1])*1000L);    /* set timer duration */
  416.     start_timer(&Nodetimer);        /* and fire it up */
  417.     return 0;
  418. }
  419.  
  420. void
  421. donodetick()
  422. {
  423.     register int i ;
  424.  
  425.     for(i = 0 ; i < Nr_numiface ; i++)
  426.         nr_bcnodes(i) ;
  427.  
  428.     /* Restart timer */
  429.     start_timer(&Nodetimer) ;
  430. }
  431.  
  432. /* Set timer for aging routes */
  433. static int
  434. doobsotimer(argc,argv,p)
  435. int argc;
  436. char *argv[];
  437. void *p;
  438. {
  439.     if(argc < 2){
  440.         tprintf("Obsotimer %lu/%lu seconds\n",
  441.             read_timer(&Obsotimer)/1000L,
  442.             dur_timer(&Obsotimer)/1000L);
  443.         return 0;
  444.     }
  445.     stop_timer(&Obsotimer) ;    /* just in case it's already running */
  446.     Obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  447.     Obsotimer.arg = NULLCHAR;        /* dummy value */
  448.     set_timer(&Obsotimer,atoi(argv[1])*1000L);    /* set timer duration */
  449.     start_timer(&Obsotimer);        /* and fire it up */
  450.     return 0;
  451. }
  452.  
  453.  
  454. /* Go through the routing table, reducing the obsolescence count of
  455.  * non-permanent routes, and purging them if the count reaches 0
  456.  */
  457. static void
  458. doobsotick()
  459. {
  460.     register struct nrnbr_tab *np ;
  461.     register struct nrroute_tab *rp, *rpnext ;
  462.     register struct nr_bind *bp, *bpnext ;
  463.     int i ;
  464.  
  465.     for(i = 0 ; i < NRNUMCHAINS ; i++) {
  466.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  467.             rpnext = rp->next ;     /* save in case we free this route */
  468.             for(bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  469.                 bpnext = bp->next ;    /* in case we free this binding */
  470.                 if(bp->flags & NRB_PERMANENT)    /* don't age these */
  471.                     continue ;
  472.                 if(--bp->obsocnt == 0) {        /* time's up! */
  473.                     if(bp->next != NULLNRBIND)
  474.                         bp->next->prev = bp->prev ;
  475.                     if(bp->prev != NULLNRBIND)
  476.                         bp->prev->next = bp->next ;
  477.                     else
  478.                         rp->routes = bp->next ;
  479.                     rp->num_routes-- ;            /* one less binding */
  480.                     np = bp->via ;                /* find the neighbor */
  481.                     free((char *)bp) ;                /* now we can free the bind */
  482.                     /* Check to see if we can free the neighbor */
  483.                     if(--np->refcnt == 0) {
  484.                         if(np->next != NULLNTAB)
  485.                             np->next->prev = np->prev ;
  486.                         if(np->prev != NULLNTAB)
  487.                             np->prev->next = np->next ;
  488.                         else {
  489.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  490.                         }
  491.                         free((char *)np) ;    /* free the storage */
  492.                     }
  493.                 }
  494.             }
  495.             if(rp->num_routes == 0) {        /* did we free them all? */
  496.                 if(rp->next != NULLNRRTAB)
  497.                     rp->next->prev = rp->prev ;
  498.                 if(rp->prev != NULLNRRTAB)
  499.                     rp->prev->next = rp->next ;
  500.                 else
  501.                     Nrroute_tab[i] = rp->next ;
  502.  
  503.                 free((char *)rp) ;
  504.             }
  505.         }
  506.     }
  507.  
  508.     start_timer(&Obsotimer) ;
  509. }
  510.  
  511.  
  512. static struct cmds Nfcmds[] = {
  513.     "add",    donfadd,    0, 3,
  514.         "netrom nodefilter add <neighbor> <interface> [quality]",
  515.     "drop",    donfdrop,    0, 3,
  516.         "netrom nodefilter drop <neighbor> <interface>",
  517.     "mode",    donfmode,    0, 0,    NULLCHAR,
  518.     NULLCHAR,    NULLFP,    0, 0,
  519.         "nodefilter subcommands: add drop mode",
  520. } ;
  521.  
  522. /* nodefilter command multiplexer */
  523. static int
  524. donodefilter(argc,argv,p)
  525. int argc ;
  526. char *argv[] ;
  527. void *p;
  528. {
  529.     if(argc < 2) {
  530.         donfdump() ;
  531.         return 0 ;
  532.     }
  533.     return subcmd(Nfcmds,argc,argv,p) ;
  534. }
  535.  
  536. /* display a list of <callsign,interface> pairs from the filter
  537.  * list.
  538.  */
  539. static int
  540. donfdump()
  541. {
  542.     int i, column = 1 ;
  543.     struct nrnf_tab *fp ;
  544.     char buf[16] ;
  545.  
  546.     for(i = 0 ; i < NRNUMCHAINS ; i++)
  547.         for(fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  548.             pax25(buf,fp->neighbor) ;
  549.             tprintf("%-7s  %-8s  %-3d   ",
  550.              buf,Nrifaces[fp->iface].iface->name, fp->quality) ;
  551.             if(column++ == 3) {
  552.                 if(tprintf("\n") == EOF)
  553.                     return 0;
  554.                 column = 1 ;
  555.             }
  556.         }
  557.  
  558.     if(column != 1)
  559.         tprintf("\n") ;
  560.  
  561.     return 0 ;
  562. }
  563.  
  564. /* add an entry to the filter table */
  565. static int
  566. donfadd(argc,argv,p)
  567. int argc ;
  568. char *argv[] ;
  569. void *p;
  570. {
  571.     unsigned qual;
  572.     char neighbor[AXALEN] ;
  573.     register int i ;
  574.  
  575.     /* format callsign */
  576.     if(setcall(neighbor,argv[1]) == -1) {
  577.         tprintf("bad neighbor callsign\n") ;
  578.         return -1 ;
  579.     }
  580.  
  581.     /* find interface */
  582.     for(i = 0 ; i < Nr_numiface ; i++)
  583.         if(!strcmp(Nrifaces[i].iface->name,argv[2]))
  584.             break ;
  585.     if(i == Nr_numiface) {
  586.         tprintf("Interface \"%s\" not found\n",argv[2]) ;
  587.         return -1 ;
  588.     }
  589.  
  590.     qual = Nrifaces[i].quality;    /* set default quality */
  591.  
  592.     if(argc >= 4)
  593.         qual = atoi(argv[3]);
  594.  
  595.     return nr_nfadd(neighbor,i,qual) ;
  596. }
  597.  
  598. /* drop an entry from the filter table */
  599. static int
  600. donfdrop(argc,argv,p)
  601. int argc ;
  602. char *argv[] ;
  603. void *p;
  604. {
  605.     char neighbor[AXALEN] ;
  606.     register int i ;
  607.  
  608.     /* format neighbor callsign */
  609.     if(setcall(neighbor,argv[1]) == -1) {
  610.         tprintf("bad neighbor callsign\n") ;
  611.         return -1 ;
  612.     }
  613.  
  614.     /* find interface */
  615.     for(i = 0 ; i < Nr_numiface ; i++)
  616.         if(!strcmp(Nrifaces[i].iface->name,argv[2]))
  617.             break ;
  618.     if(i == Nr_numiface) {
  619.         tprintf("Interface \"%s\" not found\n",argv[2]) ;
  620.         return -1 ;
  621.     }
  622.  
  623.     return nr_nfdrop(neighbor,i) ;
  624. }
  625.  
  626. /* nodefilter mode subcommand */
  627. static int
  628. donfmode(argc,argv,p)
  629. int argc ;
  630. char *argv[] ;
  631. void *p;
  632. {
  633.     if(argc < 2) {
  634.         tprintf("filter mode is ") ;
  635.         switch(Nr_nfmode) {
  636.             case NRNF_NOFILTER:
  637.                 tprintf("none\n") ;
  638.                 break ;
  639.             case NRNF_ACCEPT:
  640.                 tprintf("accept\n") ;
  641.                 break ;
  642.             case NRNF_REJECT:
  643.                 tprintf("reject\n") ;
  644.                 break ;
  645.             default:
  646.                 tprintf("some strange, unknown value\n") ;
  647.         }
  648.         return 0 ;
  649.     }
  650.     
  651.     switch(argv[1][0]) {
  652.         case 'n':
  653.         case 'N':
  654.             Nr_nfmode = NRNF_NOFILTER ;
  655.             break ;
  656.         case 'a':
  657.         case 'A':
  658.             Nr_nfmode = NRNF_ACCEPT ;
  659.             break ;
  660.         case 'r':
  661.         case 'R':
  662.             Nr_nfmode = NRNF_REJECT ;
  663.             break ;
  664.         default:
  665.             tprintf("modes are: none accept reject\n") ;
  666.             return -1 ;
  667.     }
  668.  
  669.     return 0 ;
  670. }
  671.  
  672. /* netrom network packet time-to-live initializer */
  673. static int
  674. donrttl(argc, argv,p)
  675. int argc ;
  676. char *argv[] ;
  677. void *p;
  678. {
  679.     return setshort(&Nr_ttl,"Time to live",argc,argv);
  680. }
  681.  
  682. /* verbose route broadcast */
  683. static int
  684. donrverbose(argc,argv,p)
  685. int argc ;
  686. char *argv[] ;
  687. void *p;
  688. {
  689.     return setbool(&Nr_verbose,"Verbose flag",argc,argv);
  690. }
  691. /* allow automatic derating of netrom routes on link failure */
  692. static int
  693. donrderate(argc,argv,p)
  694. int argc ;
  695. char *argv[] ;
  696. void *p;
  697. {
  698.     extern int Nr_derate;
  699.  
  700.     return setbool(&Nr_derate,"Derate flag",argc,argv);
  701. }
  702.  
  703. /* promiscuous acceptance of broadcasts */
  704. static int
  705. donrpromisc(argc,argv,p)
  706. int argc ;
  707. char *argv[] ;
  708. void *p;
  709. {
  710.     extern int Nr_promisc;
  711.  
  712.     return setbool(&Nr_promisc,"Promiscuous flag",argc,argv);
  713. }
  714.  
  715. /* Initiate a NET/ROM transport connection */
  716. static int
  717. donrconnect(argc,argv,p)
  718. int argc ;
  719. char *argv[] ;
  720. void *p;
  721. {
  722.     char *np ;
  723.     struct sockaddr_nr lsocket, fsocket;
  724.     char alias[AXBUF];
  725.     struct session *sp;
  726.  
  727.     /* Get a session descriptor */
  728.     if((sp = newsession(argv[1],NRSESSION,0)) == NULLSESSION) {
  729.         tprintf("Too many sessions\n") ;
  730.         return 1 ;
  731.     }
  732.  
  733.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  734.         tprintf("Can't create socket\n");
  735.         keywait(NULLCHAR,1);
  736.         freesession(sp);
  737.         return 1;
  738.     }
  739.     lsocket.nr_family = AF_NETROM;
  740.     /* Set up our local username, bind would use Mycall instead */
  741.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  742.     /* Putting anything else than Mycall here will not work */
  743.     memcpy(lsocket.nr_addr.node,Mycall,AXALEN);
  744.     bind(sp->s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  745.  
  746.     /* See if the requested destination could be an alias, and */
  747.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  748.     /* address. */
  749.     
  750.     if(putalias(alias,argv[1],0) != -1 &&
  751.         (np = find_nralias(alias)) != NULLCHAR) {
  752.         memcpy(fsocket.nr_addr.user,np,AXALEN) ;
  753.         memcpy(fsocket.nr_addr.node,np,AXALEN) ;
  754.     } else {    /* parse ax25 callsign */
  755.         /* Only the user callsign of the remote station is never used by */
  756.         /* NET/ROM, but it is needed for the psocket() call. */
  757.         setcall(fsocket.nr_addr.user,argv[1]);
  758.         setcall(fsocket.nr_addr.node,argv[1]);
  759.     }
  760.     fsocket.nr_family = AF_NETROM;
  761.     pax25(alias,fsocket.nr_addr.node);
  762.     return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_nr));
  763. }
  764.  
  765. /* Reset a net/rom connection abruptly */
  766. static int
  767. donrreset(argc,argv,p)
  768. int argc;
  769. char *argv[];
  770. void *p;
  771. {
  772.     struct nr4cb *cb ;
  773.  
  774.     cb = (struct nr4cb *)htol(argv[1]);
  775.     if(!nr4valcb(cb)){
  776.         tprintf(Notval);
  777.         return 1;
  778.     }
  779.     reset_nr4(cb);
  780.     return 0;
  781. }
  782.  
  783. /* Force retransmission on a net/rom connection */
  784.  
  785. static int
  786. donrkick(argc,argv,p)
  787. int argc;
  788. char *argv[];
  789. void *p;
  790. {
  791.     struct nr4cb *cb ;
  792.  
  793.     cb = (struct nr4cb *)htol(argv[1]);
  794.  
  795.     if(kick_nr4(cb) == -1) {
  796.         tprintf(Notval);
  797.         return 1;
  798.     } else
  799.         return 0;
  800. }
  801.  
  802. /* netrom transport ACK delay timer */
  803. static int
  804. donracktime(argc, argv,p)
  805. int argc ;
  806. char *argv[] ;
  807. void *p;
  808. {
  809.     return setlong(&Nr4acktime,"Ack delay time (ms)",argc,argv);
  810. }
  811.  
  812. /* netrom transport choke timeout */
  813. static int
  814. donrchoketime(argc, argv,p)
  815. int argc ;
  816. char *argv[] ;
  817. void *p;
  818. {
  819.     return setlong(&Nr4choketime,"Choke timeout (ms)",argc,argv);
  820. }
  821.  
  822. /* netrom transport initial round trip time */
  823.  
  824. static int
  825. donrirtt(argc, argv,p)
  826. int argc ;
  827. char *argv[] ;
  828. void *p;
  829. {
  830.     return setlong(&Nr4irtt,"Initial RTT (ms)",argc,argv);
  831. }
  832.  
  833. /* netrom transport receive queue length limit.  This is the */
  834. /* threshhold at which we will CHOKE the sender. */
  835.  
  836. static int
  837. donrqlimit(argc, argv,p)
  838. int argc ;
  839. char *argv[] ;
  840. void *p;
  841. {
  842.     return setshort(&Nr4qlimit,"Queue limit (bytes)",argc,argv);
  843. }
  844.  
  845. /* Display or change our NET/ROM username */
  846. static int
  847. donruser(argc,argv,p)
  848. int argc;
  849. char *argv[];
  850. void *p;
  851. {
  852.     char buf[AXBUF];
  853.  
  854.     if(argc < 2){
  855.         pax25(buf,Nr4user);
  856.         tprintf("%s\n",buf);
  857.         return 0;
  858.     }
  859.     if(setcall(Nr4user,argv[1]) == -1)
  860.         return -1;
  861.     Nr4user[ALEN] |= E;
  862.     return 0;
  863. }
  864.  
  865. /* netrom transport maximum window.  This is the largest send and */
  866. /* receive window we may negotiate */
  867.  
  868. static int
  869. donrwindow(argc, argv,p)
  870. int argc ;
  871. char *argv[] ;
  872. void *p;
  873. {
  874.     return setshort(&Nr4window,"Window (frames)",argc,argv);
  875. }
  876.  
  877. /* netrom transport maximum retries.  This is used in connect and */
  878. /* disconnect attempts; I haven't decided what to do about actual */
  879. /* data retries yet. */
  880.  
  881. static int
  882. donrretries(argc, argv,p)
  883. int argc ;
  884. char *argv[] ;
  885. void *p;
  886. {
  887.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  888. }
  889.  
  890. /* Display the status of NET/ROM connections */
  891.  
  892. static int
  893. donrstatus(argc, argv,p)
  894. int argc ;
  895. char *argv[] ;
  896. void *p;
  897. {
  898.     int i ;
  899.     struct nr4cb *cb ;
  900.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  901.     
  902.     if(argc < 2) {
  903.         tprintf("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  904.         for(i = 0 ; i < NR4MAXCIRC ; i++) {
  905.             if((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  906.                 continue ;
  907.             pax25(luser,cb->local.user) ;
  908.             pax25(ruser,cb->remote.user) ;
  909.             pax25(node,cb->remote.node) ;
  910.             if(tprintf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  911.              ptol(cb), cb->nbuffered, len_q(cb->txq),
  912.              len_p(cb->rxq), luser, ruser, node,
  913.              Nr4states[cb->state]) == EOF)
  914.                 break;
  915.         }
  916.         return 0 ;
  917.     }
  918.  
  919.     cb = (struct nr4cb *)htol(argv[1]) ;
  920.     if(!nr4valcb(cb)) {
  921.         tprintf(Notval) ;
  922.         return 1 ;
  923.     }
  924.  
  925.     donrdump(cb) ;
  926.     return 0 ;
  927. }
  928.  
  929. /* Dump one control block */
  930.  
  931. void
  932. donrdump(cb)
  933. struct nr4cb *cb ;
  934. {
  935.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  936.     unsigned seq ;
  937.     struct nr4txbuf *b ;
  938.     struct timer *t ;
  939.  
  940.     pax25(luser,cb->local.user) ;
  941.     pax25(ruser,cb->remote.user) ;
  942.     pax25(node,cb->remote.node) ;
  943.  
  944.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  945.            luser, cb->mynum, cb->myid, ruser, node,
  946.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  947.  
  948.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  949.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  950.            len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  951.  
  952.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  953.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  954.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  955.  
  956.     tprintf("TACK: ") ;
  957.     if(run_timer(&cb->tack))
  958.         tprintf("%lu", read_timer(&cb->tack)) ;
  959.     else
  960.         tprintf("stop") ;
  961.     tprintf("/%lu ms; ", dur_timer(&cb->tack)) ;
  962.  
  963.     tprintf("TChoke: ") ;
  964.     if(run_timer(&cb->tchoke))
  965.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  966.     else
  967.         tprintf("stop") ;
  968.     tprintf("/%lu ms; ", dur_timer(&cb->tchoke)) ;
  969.  
  970.     tprintf("TCD: ") ;
  971.     if(run_timer(&cb->tcd))
  972.         tprintf("%lu", read_timer(&cb->tcd)) ;
  973.     else
  974.         tprintf("stop") ;
  975.     tprintf("/%lu ms", dur_timer(&cb->tcd)) ;
  976.  
  977.     if(run_timer(&cb->tcd))
  978.         tprintf("; Tries: %u\n", cb->cdtries) ;
  979.     else
  980.         tprintf("\n") ;
  981.  
  982.     tprintf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  983.            cb->blevel, cb->srtt, cb->mdev) ;
  984.  
  985.     /* If we are connected and the send window is open, display */
  986.     /* the status of all the buffers and their timers */
  987.     
  988.     if(cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  989.  
  990.         tprintf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  991.  
  992.         for(seq = cb->ackxpected ;
  993.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  994.              seq = (seq + 1) & NR4SEQMASK) {
  995.  
  996.             b = &cb->txbufs[seq % cb->window] ;
  997.             t = &b->tretry ;
  998.  
  999.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  1000.              seq, len_p(b->data), b->retries + 1,
  1001.              read_timer(t), dur_timer(t))
  1002.              == EOF)
  1003.                 break;
  1004.         }
  1005.  
  1006.     }
  1007.  
  1008. }
  1009.  
  1010. /* netrom timers type - linear v exponential */
  1011. static
  1012. donrtype(argc,argv,p)
  1013. int argc ;
  1014. char *argv[] ;
  1015. void *p ;
  1016. {
  1017.     extern unsigned Nr_timertype;
  1018.  
  1019.     if(argc < 2) {
  1020.         tprintf("Netrom timer type is %s\n", Nr_timertype ? "linear" : "exponential" ) ;
  1021.         return 0 ;
  1022.     }
  1023.     
  1024.     switch(argv[1][0]) {
  1025.         case 'l':
  1026.         case 'L':
  1027.             Nr_timertype = 1 ;
  1028.             break ;
  1029.         case 'e':
  1030.         case 'E':
  1031.             Nr_timertype = 0 ;
  1032.             break ;
  1033.         default:
  1034.             tprintf("use: netrom timertype [linear|exponential]\n") ;
  1035.             return -1 ;
  1036.     }
  1037.  
  1038.     return 0 ;
  1039. }
  1040.  
  1041. static
  1042. dominquality(argc,argv,p)
  1043. int argc ;
  1044. char *argv[] ;
  1045. void *p ;
  1046. {
  1047.     unsigned val ;
  1048.     extern unsigned Nr_autofloor;
  1049.  
  1050.     if(argc < 2) {
  1051.         tprintf("%u\n", Nr_autofloor) ;
  1052.         return 0 ;
  1053.     }
  1054.  
  1055.     val = atoi(argv[1]) ;
  1056.  
  1057.     if(val == 0 || val > 255 ) {
  1058.         tprintf("The minimum acceptable quality must be 1 to 255\n") ;
  1059.         return 1 ;
  1060.     }
  1061.     
  1062.     Nr_autofloor = val ;
  1063.  
  1064.     return 0 ;
  1065. }
  1066. int
  1067. donrload(argc,argv,p)
  1068. int argc ;
  1069. char *argv[] ;
  1070. void *p;
  1071. {
  1072.     char buff[255];
  1073.     FILE *fn;
  1074.     time_t now, prev;
  1075.     long t1,t2;
  1076.     int quality,obso,i,j;
  1077.     char alias[12],dest[12],iface[12],neighbor[12],type[3],*ptr;
  1078.     
  1079.     time(&now);
  1080.     if((fn = fopen(Netromfile,READ_TEXT)) == NULLFILE){
  1081.         tprintf("Can't open netrom save file!\n");
  1082.         return 1;
  1083.     }
  1084.  
  1085.     fgets(buff,255,fn);    /* read the timestamp */
  1086.     if(feof(fn)){
  1087.         fclose(fn);
  1088.         return 1;
  1089.     }
  1090.     if((strncmp(buff,"time = ",7))!= 0){
  1091.         tprintf("Wrong node file content\n");
  1092.         fclose(fn);
  1093.         return 1;
  1094.     }
  1095.     sscanf(buff,"time =%ld",&prev);
  1096.     tprintf("now = %ld , prev = %ld\n",now,prev);
  1097.     if(prev >= now){
  1098.         tprintf("You traveled back in time!!\n");
  1099.         fclose(fn);
  1100.         return 1;
  1101.     }
  1102.     t1 = now - prev;
  1103.     t2 = dur_timer(&Obsotimer)/1000L;
  1104.     j = t1 / t2;        /* recalculate obsolete count */
  1105.     tprintf("%ld seconds are past ( %d obsolete scans)\n",t1,j);
  1106.  
  1107.     fgets(buff,255,fn);
  1108.     while(!feof(fn)){
  1109.         if((ptr = strchr(buff,':')) == 0){
  1110.             sscanf(buff,"%s%s%i%i%s%s"
  1111.                 ,dest,type,&quality,&obso,iface,neighbor);
  1112.             alias[0] = '\0';
  1113.         } else {    
  1114.             *ptr = ' ';
  1115.             sscanf(buff,"%s%s%s%i%i%s%s"
  1116.                 ,alias,dest,type,&quality,&obso,iface,neighbor);
  1117.         }
  1118.         /* find interface */
  1119.         for(i = 0 ; i < Nr_numiface ; i++)
  1120.             if(!strcmp(Nrifaces[i].iface->name,iface))
  1121.                 break ;
  1122.         if(i == Nr_numiface) {
  1123.             tprintf("Interface \"%s\" not found\n",iface) ;
  1124.         }
  1125.     
  1126.         /* get and check quality value */
  1127.         if(quality  > 255) {
  1128.             tprintf("maximum route quality is 255\n") ;
  1129.         }
  1130.  
  1131. /*        nr_routeadd(alias,dest,i,quality,neighbor,1,0) ; */
  1132.         fgets(buff,255,fn);
  1133.     }
  1134.     fclose(fn);
  1135.     return 0;
  1136. }
  1137.  
  1138. int
  1139. donrsave(argc,argv,p)
  1140. int argc ;
  1141. char *argv[] ;
  1142. void *p;
  1143. {
  1144.     register struct nrroute_tab *rp ;
  1145.     register struct nr_bind *bp ;
  1146.     register struct nrnbr_tab *np ;
  1147.     char dest[AXALEN] ;
  1148.     char neighbor[AXBUF] ;
  1149.     register int i;
  1150.     char buf[16] ;
  1151.     char *cp ;
  1152.     FILE *fn;
  1153.     time_t now;
  1154.     
  1155. #ifdef __TURBOC__
  1156.     if((fn = fopen(Netromfile,"wt+")) == NULLFILE){
  1157. #else
  1158.     if((fn = fopen(Netromfile,"w+")) == NULLFILE){
  1159. #endif
  1160.         tprintf("Can't write netrom save file!\n");
  1161.         return 1;
  1162.     }
  1163.     time(&now);
  1164.     fprintf(fn,"time = %ld\n",now);
  1165.     for(i = 0 ; i < NRNUMCHAINS ; i++){
  1166.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1167.             strcpy(buf,rp->alias) ;
  1168.             /* remove trailing spaces */
  1169.             if((cp = strchr(buf,' ')) == NULLCHAR)
  1170.                 cp = &buf[strlen(buf)] ;
  1171.             if(cp != buf)        /* don't include colon for null alias */
  1172.                 *cp++ = ':' ;
  1173.             for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1174.                 pax25(cp,rp->call) ;
  1175.                 fprintf(fn,"%-16s  ",buf) ;
  1176.                 np = bp->via ;
  1177.                 if(fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1178.                       (bp->flags & NRB_PERMANENT ? "P" :
  1179.                       bp->flags & NRB_RECORDED ? "R" : "X"),
  1180.                       bp->quality,bp->obsocnt,
  1181.                       Nrifaces[np->iface].iface->name,
  1182.                       pax25(neighbor,np->call)) == EOF)
  1183.                    break;
  1184.             }
  1185.         }
  1186.     }
  1187.     fclose(fn);
  1188.     return 0;
  1189. }
  1190.