home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / files / telecomm / nhclb120 / nrcmd.c < prev    next >
C/C++ Source or Header  |  1993-09-26  |  26KB  |  1,280 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.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "ax25.h"
  11. #include "timer.h"
  12. #include "iface.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "netuser.h"
  17. #include "tcp.h"
  18. #include "ftp.h"
  19. #include "telnet.h"
  20. #include "finger.h"
  21. #include "ax_mbx.h"
  22. #include "cmdparse.h"
  23. #include "session.h"
  24. #include <ctype.h>
  25. #ifdef    UNIX
  26. #undef    toupper
  27. #undef    tolower
  28. #include <memory.h>
  29. #include <string.h>
  30. #endif
  31.  
  32. #undef NRDEBUG
  33. static int donodetick();
  34. static int doobsotick();
  35. static donfdump();
  36. static void donrdump();
  37. long atol();
  38. extern struct session *current;
  39.  
  40. char *Nr4states[] = {
  41.     "Disconnected",
  42.     "Conn Pending",
  43.     "Connected",
  44.     "Disc Pending"
  45. } ;
  46.  
  47. char *Nr4reasons[] = {
  48.     "Normal",
  49.     "By Peer",
  50.     "Timeout",
  51.     "Reset",
  52.     "Refused"
  53. } ;
  54.  
  55. static int dointerface(), dobcnodes(), donodetimer(), donrroute(),
  56.            donrttl(), doobsotimer(), donodefilter(), donrverbose(),
  57.            donrconnect(), donrreset(), donrwindow(), donrirtt(),
  58.            donracktime(), donrqlimit(), donrchoketime(), donrretries(),
  59.            donrstatus(), donrkick() ;
  60.  
  61. static struct cmds nrcmds[] = {
  62.     "acktime",    donracktime,    0,    NULLCHAR,    NULLCHAR,
  63.     "bcnodes",    dobcnodes,    2,    "netrom bcnodes <interface>", NULLCHAR,
  64.     
  65. /* Put connect before choketime to make it the default expansion of 'c' */
  66.  
  67.     "connect",    donrconnect,2,    "netrom connect <node>",    NULLCHAR,
  68.     "choketime",    donrchoketime,    0,    NULLCHAR,    NULLCHAR,
  69.     "interface",    dointerface,    4,
  70.         "netrom interface <interface> <alias> <quality>",    NULLCHAR,
  71.     "irtt",            donrirtt,        0,    NULLCHAR,    NULLCHAR,
  72.     "kick",            donrkick,        2,    "netrom kick <&nrcb>",    NULLCHAR,
  73.     "nodefilter",    donodefilter,    0,    NULLCHAR,    NULLCHAR,
  74.     "nodetimer",    donodetimer,    0,    NULLCHAR,    NULLCHAR,
  75.     "obsotimer",    doobsotimer,    0,    NULLCHAR,    NULLCHAR,
  76.     "qlimit",    donrqlimit,    0,    NULLCHAR,    NULLCHAR,
  77.     "reset",    donrreset,    2,    "netrom reset <&nrcb>",    NULLCHAR,
  78.     "retries",    donrretries,0,    NULLCHAR,    NULLCHAR,
  79.     "route",    donrroute,    0,    NULLCHAR,    NULLCHAR,
  80.     "status",    donrstatus,    0,    NULLCHAR,    NULLCHAR,
  81.     "ttl",        donrttl,    0,    NULLCHAR,    NULLCHAR,
  82.     "verbose",    donrverbose,0,    NULLCHAR,    NULLCHAR,
  83.     "window",    donrwindow,    0,    NULLCHAR,    NULLCHAR,
  84.     NULLCHAR,    NULLFP,        0,
  85.         "netrom subcommands: acktime bcnodes connect choketime interface irtt kick\n                    nodetimer nodefilter obsotimer qlimit reset retries route\n                    status ttl verbose window",
  86.         NULLCHAR
  87. } ;
  88.  
  89. static struct timer nodetimer ;    /* timer for nodes broadcasts */
  90. static struct timer obsotimer ;    /* timer for aging routes */
  91.  
  92. /* Command multiplexer */
  93. donetrom(argc,argv)
  94. int argc ;
  95. char *argv[] ;
  96. {
  97.     return subcmd(nrcmds,argc,argv) ;
  98. }
  99.  
  100. static int dorouteadd(), doroutedrop(), doroutedump(), dorouteinfo() ;
  101.  
  102. static struct cmds routecmds[] = {
  103.     "add",    dorouteadd,    6,
  104.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  105.         "add failed",
  106.     "drop",    doroutedrop, 4,
  107.         "netrom route drop <destination> <neighbor> <interface>",
  108.         "drop failed",
  109.     "info", dorouteinfo, 2,
  110.         "netrom route info <destination>", NULLCHAR,
  111.     NULLCHAR,    NULLFP,    0,
  112.         "netrom route subcommands: add drop info",
  113.         NULLCHAR
  114. } ;
  115.  
  116. /* Route command multiplexer */
  117. static
  118. donrroute(argc, argv)
  119. int argc ;
  120. char *argv[] ;
  121. {
  122.     if (argc < 2) {
  123.         doroutedump() ;
  124.         return 0 ;
  125.     }
  126.     return subcmd(routecmds,argc,argv) ;
  127. }
  128.  
  129. /* Dump a list of known routes */
  130. static
  131. doroutedump()
  132. {
  133.     register struct nrroute_tab *rp ;
  134.     register int i, column ;
  135.     char buf[32] ;
  136.     char *cp ;
  137.     int count = 0;
  138.     
  139.     column = 1 ;
  140.     
  141.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  142.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  143.             strcpy(buf,rp->alias) ;
  144.             /* remove trailing spaces */
  145.             if ((cp = index(buf,' ')) == NULLCHAR)
  146.                 cp = &buf[strlen(buf)] ;
  147.             if (cp != buf)        /* don't include colon for null alias */
  148.                 *cp++ = ':' ;
  149.             pax25(cp,&rp->call) ;
  150.             printf("%-16s  ",buf) ;
  151.             count++;
  152.             if (column++ == 4) {
  153.                 printf("\n") ;
  154.                 column = 1 ;
  155.             }
  156.         }
  157.  
  158.     if (column != 1)
  159.         printf("\n") ;
  160.     printf("Total station count = %d\n",count);
  161.         
  162.     return 0 ;
  163. }
  164.  
  165. /* print detailed information on an individual route */
  166. /*ARGSUSED*/
  167. static int
  168. dorouteinfo(argc,argv)
  169. int argc ;
  170. char *argv[] ;
  171. {
  172.     register struct nrroute_tab *rp ;
  173.     register struct nr_bind *bp ;
  174.     register struct nrnbr_tab *np ;
  175.     struct ax25_addr dest ;
  176.     char neighbor[60] ;
  177.  
  178.     if (setcall(&dest,argv[1]) == -1) {
  179.         printf ("bad destination name\n") ;
  180.         return -1 ;
  181.     }
  182.         
  183.     if ((rp = find_nrroute(&dest)) == NULLNRRTAB) {
  184.         printf("no such route\n") ;
  185.         return -1 ;
  186.     }
  187.  
  188.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  189.         np = bp->via ;
  190.         psax25(neighbor,np->call) ;
  191.         printf("%1s %3d  %3d  %-8s  %s\n",
  192.                 (bp->flags & NRB_PERMANENT ? "P" :
  193.                  bp->flags & NRB_RECORDED ? "R" : " "),
  194.                 bp->quality,bp->obsocnt,
  195.                 nrifaces[np->interface].interface->name,
  196.                 neighbor) ;
  197.     }
  198.     return 0 ;
  199. }
  200.         
  201. /* convert a null-terminated alias name to a blank-filled, upcased */
  202. /* version.  Return -1 on failure. */
  203. static int
  204. putalias(to,from,complain)
  205. register char *to, *from ;
  206. int complain ;
  207. {
  208.     int len, i ;
  209.     
  210.     if ((len = strlen(from)) > ALEN) {
  211.         if (complain)
  212.             printf ("alias too long - six characters max\n") ;
  213.         return -1 ;
  214.     }
  215.     
  216.     for (i = 0 ; i < ALEN ; i++) {
  217.         if (i < len) {
  218.             if (islower(*from))
  219.                 *to++ = toupper(*from++) ;
  220.             else
  221.                 *to++ = *from++ ;
  222.         }
  223.         else
  224.             *to++ = ' ' ;
  225.     }
  226.             
  227.     *to = '\0' ;
  228.     return 0 ;
  229. }
  230.  
  231. /* Add a route */
  232. static int
  233. dorouteadd(argc, argv)
  234. int argc ;
  235. char *argv[] ;
  236. {
  237.     char alias[7] ;
  238.     struct ax25_addr dest ;
  239.     unsigned quality ;
  240.     char neighbor[AXALEN * 3] ;
  241.     register int i ;
  242.     int naddr ;
  243.  
  244.     /* format alias (putalias prints error message if necessary) */
  245.     if (putalias(alias,argv[1],1) == -1)
  246.         return -1 ;
  247.  
  248.     /* format destination callsign */
  249.     if (setcall(&dest,argv[2]) == -1) {
  250.         printf("bad destination callsign\n") ;
  251.         return -1 ;
  252.     }
  253.  
  254.     /* find interface */
  255.     for (i = 0 ; i < nr_numiface ; i++)
  256.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  257.             break ;
  258.     if (i == nr_numiface) {
  259.         printf("Interface \"%s\" not found\n",argv[3]) ;
  260.         return -1 ;
  261.     }
  262.     
  263.     /* get and check quality value */
  264.     if ((quality = atoi(argv[4])) > 255) {
  265.         printf("maximum route quality is 255\n") ;
  266.         return -1 ;
  267.     }
  268.  
  269.     /* make sure no more than 2 digis */
  270.     naddr = argc - 5 ;
  271.     if (naddr > 3) {
  272.         printf("no more than 2 digipeaters for a net/rom neighbor\n") ;
  273.         return -1 ;
  274.     }
  275.     
  276.     /* format neighbor address string */
  277.     setpath(neighbor,&argv[5],naddr) ;
  278.  
  279.     return nr_routeadd(alias,&dest,(unsigned)i,quality,neighbor,1,0) ;
  280. }
  281.  
  282.  
  283. /* drop a route */
  284. /*ARGSUSED*/
  285. static
  286. doroutedrop(argc,argv)
  287. int argc ;
  288. char *argv[] ;
  289. {
  290.     struct ax25_addr dest, neighbor ;
  291.     register int i ;
  292.  
  293.     /* format destination and neighbor callsigns */
  294.     if (setcall(&dest,argv[1]) == -1) {
  295.         printf("bad destination callsign\n") ;
  296.         return -1 ;
  297.     }
  298.     if (setcall(&neighbor,argv[2]) == -1) {
  299.         printf("bad neighbor callsign\n") ;
  300.         return -1 ;
  301.     }
  302.  
  303.     /* find interface */
  304.     for (i = 0 ; i < nr_numiface ; i++)
  305.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  306.             break ;
  307.     if (i == nr_numiface) {
  308.         printf("Interface \"%s\" not found\n",argv[3]) ;
  309.         return -1 ;
  310.     }
  311.  
  312.     return nr_routedrop(&dest,&neighbor,(unsigned)i) ;
  313. }
  314.     
  315.     
  316. /* make an interface available to net/rom */
  317. /*ARGSUSED*/
  318. static int
  319. dointerface(argc,argv)
  320. int argc ;
  321. char *argv[] ;
  322. {
  323.     int i ;
  324.     register struct interface *ifp ;
  325.     extern struct interface *ifaces ;
  326.  
  327.     if (nr_interface == NULLIF) {
  328.         printf("Attach netrom interface first\n") ;
  329.         return 1 ;
  330.     }
  331.     
  332.     if (nr_numiface >= NRNUMIFACE) {
  333.         printf("Only %d net/rom interfaces available\n",NRNUMIFACE) ;
  334.         return 1 ;
  335.     }
  336.     
  337.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  338.         if(strcmp(argv[1],ifp->name) == 0)
  339.             break;
  340.     }
  341.     if(ifp == NULLIF){
  342.         printf("Interface \"%s\" unknown\n",argv[1]);
  343.         return 1;
  344.     }
  345.     for (i = 0 ; i < nr_numiface ; i++)
  346.         if (nrifaces[i].interface == ifp) {
  347.             printf("Interface \"%s\" is already registered\n",argv[1]) ;
  348.             return 1 ;
  349.         }
  350.         
  351.     nrifaces[nr_numiface].interface = ifp ;
  352.  
  353.     if (putalias(nrifaces[nr_numiface].alias,argv[2],1) == -1)
  354.         return 1 ;
  355.         
  356.     if ((nrifaces[nr_numiface].quality = atoi(argv[3])) > 255) {
  357.         printf("Quality cannot be greater than 255\n") ;
  358.         return 1 ;
  359.     }
  360.         
  361.     nr_numiface++ ;            /* accept this interface */
  362.     return 0 ;
  363. }
  364.  
  365. /* Broadcast nodes list on named interface. */
  366.  
  367. /*ARGSUSED*/
  368. static int
  369. dobcnodes(argc,argv)
  370. int argc ;
  371. char *argv[] ;
  372. {
  373.     register int i ;
  374.     for (i = 0 ; i < nr_numiface ; i++)
  375.         if (!strcmp(nrifaces[i].interface->name,argv[1]))
  376.             break ;
  377.     if (i == nr_numiface) {
  378.         printf("Interface \"%s\" not found\n",argv[1]) ;
  379.         return 1 ;
  380.     }
  381.         
  382.     nr_bcnodes((unsigned)i) ;
  383.     return 0 ;
  384. }
  385.  
  386. #define TICKSPERSEC    (1000L / MSPTICK)    /* Ticks per second */
  387.  
  388. /* Set outbound node broadcast interval */
  389. static int
  390. donodetimer(argc,argv)
  391. int argc;
  392. char *argv[];
  393. {
  394.     int donodetick();
  395.  
  396.     if(argc < 2){
  397.         printf("%lu/%lu\n",
  398.                 (nodetimer.start - nodetimer.count)/TICKSPERSEC,
  399.                 nodetimer.start/TICKSPERSEC);
  400.         return 0;
  401.     }
  402.     stop_timer(&nodetimer) ;    /* in case it's already running */
  403.     nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  404.     nodetimer.arg = NULLCHAR;        /* dummy value */
  405.     nodetimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  406.     start_timer(&nodetimer);        /* and fire it up */
  407.     return 0;
  408. }
  409.  
  410. static int
  411. donodetick()
  412. {
  413.     register int i ;
  414.  
  415.     for (i = 0 ; i < nr_numiface ; i++)
  416.         nr_bcnodes((unsigned)i) ;
  417.  
  418.     /* Restart timer */
  419.     start_timer(&nodetimer) ;
  420. }
  421.  
  422. /* Set timer for aging routes */
  423. static int
  424. doobsotimer(argc,argv)
  425. int argc;
  426. char *argv[];
  427. {
  428.     extern int doobsotick();
  429.  
  430.     if(argc < 2){
  431.         printf("%lu/%lu\n",(obsotimer.start - obsotimer.count)/TICKSPERSEC,
  432.         obsotimer.start/TICKSPERSEC);
  433.         return 0;
  434.     }
  435.     stop_timer(&obsotimer) ;    /* just in case it's already running */
  436.     obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  437.     obsotimer.arg = NULLCHAR;        /* dummy value */
  438.     obsotimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  439.     start_timer(&obsotimer);        /* and fire it up */
  440.     return 0;
  441. }
  442.  
  443.  
  444. /* Go through the routing table, reducing the obsolescence count of
  445.  * non-permanent routes, and purging them if the count reaches 0
  446.  */
  447. static int
  448. doobsotick()
  449. {
  450.     register struct nrnbr_tab *np ;
  451.     register struct nrroute_tab *rp, *rpnext ;
  452.     register struct nr_bind *bp, *bpnext ;
  453.     struct ax25_addr neighbor ;
  454.     int16 nrhash();
  455.     int i ;
  456.  
  457.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  458.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  459.             rpnext = rp->next ;     /* save in case we free this route */
  460.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  461.                 bpnext = bp->next ;    /* in case we free this binding */
  462.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  463.                     continue ;
  464.                 if (--bp->obsocnt == 0) {        /* time's up! */
  465.                     if (bp->next != NULLNRBIND)
  466.                         bp->next->prev = bp->prev ;
  467.                     if (bp->prev != NULLNRBIND)
  468.                         bp->prev->next = bp->next ;
  469.                     else
  470.                         rp->routes = bp->next ;
  471.                     rp->num_routes-- ;            /* one less binding */
  472.                     np = bp->via ;                /* find the neighbor */
  473.                     free((char *)bp) ;                    /* now we can free the bind */
  474.                     /* Check to see if we can free the neighbor */
  475.                     if (--np->refcnt == 0) {
  476.                         if (np->next != NULLNTAB)
  477.                             np->next->prev = np->prev ;
  478.                         if (np->prev != NULLNTAB)
  479.                             np->prev->next = np->next ;
  480.                         else {
  481.                             memcpy(neighbor.call,np->call,ALEN) ;
  482.                             neighbor.ssid = np->call[ALEN] ;
  483.                             nrnbr_tab[(int)nrhash(&neighbor)] = np->next ;
  484.                         }
  485.                         free((char *)np) ;    /* free the storage */
  486.                     }
  487.                 }
  488.             }
  489.             if (rp->num_routes == 0) {        /* did we free them all? */
  490.                 if (rp->next != NULLNRRTAB)
  491.                     rp->next->prev = rp->prev ;
  492.                 if (rp->prev != NULLNRRTAB)
  493.                     rp->prev->next = rp->next ;
  494.                 else
  495.                     nrroute_tab[i] = rp->next ;
  496.  
  497.                 free((char *)rp) ;
  498.             }
  499.         }
  500.     }
  501.  
  502.     start_timer(&obsotimer) ;
  503. }
  504.  
  505.  
  506. static int donfadd(), donfdrop(), donfmode() ;
  507.  
  508. static struct cmds nfcmds[] = {
  509.     "add",    donfadd,    3,
  510.         "netrom nodefilter add <neighbor> <interface>",
  511.         "add failed",
  512.     "drop",    donfdrop,    3,
  513.         "netrom nodefilter drop <neighbor> <interface>",
  514.         "drop failed",
  515.     "mode",    donfmode,    0,    NULLCHAR,    NULLCHAR,
  516.     NULLCHAR,    NULLFP,    0,
  517.         "nodefilter subcommands: add drop mode",
  518.         NULLCHAR
  519. } ;
  520.  
  521. /* nodefilter command multiplexer */
  522. static
  523. donodefilter(argc,argv)
  524. int argc ;
  525. char *argv[] ;
  526. {
  527.     if (argc < 2) {
  528.         donfdump() ;
  529.         return 0 ;
  530.     }
  531.     return subcmd(nfcmds,argc,argv) ;
  532. }
  533.  
  534. /* display a list of <callsign,interface> pairs from the filter
  535.  * list.
  536.  */
  537. static
  538. donfdump()
  539. {
  540.     int i, column = 1 ;
  541.     struct nrnf_tab *fp ;
  542.     char buf[16] ;
  543.  
  544.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  545.         for (fp = nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  546.             pax25(buf,&fp->neighbor) ;
  547.             printf("%-7s %-8s  ",
  548.                     buf,nrifaces[fp->interface].interface->name) ;
  549.             if (column++ == 4) {
  550.                 printf("\n") ;
  551.                 column = 1 ;
  552.             }
  553.         }
  554.  
  555.     if (column != 1)
  556.         printf("\n") ;
  557.  
  558.     return 0 ;
  559. }
  560.  
  561. /* add an entry to the filter table */
  562. /*ARGSUSED*/
  563. static
  564. donfadd(argc,argv)
  565. int argc ;
  566. char *argv[] ;
  567. {
  568.     struct ax25_addr neighbor ;
  569.     register int i ;
  570.  
  571.     /* format callsign */
  572.     if (setcall(&neighbor,argv[1]) == -1) {
  573.         printf("bad neighbor callsign\n") ;
  574.         return -1 ;
  575.     }
  576.  
  577.     /* find interface */
  578.     for (i = 0 ; i < nr_numiface ; i++)
  579.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  580.             break ;
  581.     if (i == nr_numiface) {
  582.         printf("Interface \"%s\" not found\n",argv[2]) ;
  583.         return -1 ;
  584.     }
  585.  
  586.     return nr_nfadd(&neighbor,(unsigned)i) ;
  587. }
  588.  
  589. /* drop an entry from the filter table */
  590. /*ARGSUSED*/
  591. static
  592. donfdrop(argc,argv)
  593. int argc ;
  594. char *argv[] ;
  595. {
  596.     struct ax25_addr neighbor ;
  597.     register int i ;
  598.  
  599.     /* format neighbor callsign */
  600.     if (setcall(&neighbor,argv[1]) == -1) {
  601.         printf("bad neighbor callsign\n") ;
  602.         return -1 ;
  603.     }
  604.  
  605.     /* find interface */
  606.     for (i = 0 ; i < nr_numiface ; i++)
  607.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  608.             break ;
  609.     if (i == nr_numiface) {
  610.         printf("Interface \"%s\" not found\n",argv[2]) ;
  611.         return -1 ;
  612.     }
  613.  
  614.     return nr_nfdrop(&neighbor,(unsigned)i) ;
  615. }
  616.  
  617. /* nodefilter mode subcommand */
  618. static
  619. donfmode(argc,argv)
  620. int argc ;
  621. char *argv[] ;
  622. {
  623.     if (argc < 2) {
  624.         printf("filter mode is ") ;
  625.         switch (nr_nfmode) {
  626.             case NRNF_NOFILTER:
  627.                 printf("none\n") ;
  628.                 break ;
  629.             case NRNF_ACCEPT:
  630.                 printf("accept\n") ;
  631.                 break ;
  632.             case NRNF_REJECT:
  633.                 printf("reject\n") ;
  634.                 break ;
  635.             default:
  636.                 printf("some strange, unknown value\n") ;
  637.         }
  638.         return 0 ;
  639.     }
  640.     
  641.     switch (argv[1][0]) {
  642.         case 'n':
  643.         case 'N':
  644.             nr_nfmode = NRNF_NOFILTER ;
  645.             break ;
  646.         case 'a':
  647.         case 'A':
  648.             nr_nfmode = NRNF_ACCEPT ;
  649.             break ;
  650.         case 'r':
  651.         case 'R':
  652.             nr_nfmode = NRNF_REJECT ;
  653.             break ;
  654.         default:
  655.             printf("modes are: none accept reject\n") ;
  656.             return -1 ;
  657.     }
  658.  
  659.     return 0 ;
  660. }
  661.  
  662.  
  663. /* netrom network packet time-to-live initializer */
  664. static
  665. donrttl(argc, argv)
  666. int argc ;
  667. char *argv[] ;
  668. {
  669.     int val ;
  670.  
  671.     if (argc < 2) {
  672.         printf("%d\n", nr_ttl) ;
  673.         return 0 ;
  674.     }
  675.  
  676.     val = atoi(argv[1]) ;
  677.  
  678.     if (val < 0 || val > 255) {
  679.         printf("ttl must be between 0 and 255\n") ;
  680.         return 1 ;
  681.     }
  682.  
  683.     nr_ttl = val ;
  684.  
  685.     return 0 ;
  686. }
  687.  
  688. /* verbose route broadcast */
  689. static
  690. donrverbose(argc,argv)
  691. int argc ;
  692. char *argv[] ;
  693. {
  694.     if (argc < 2) {
  695.         printf("verbose is %s\n", nr_verbose ? "yes" : "no" ) ;
  696.         return 0 ;
  697.     }
  698.     
  699.     switch (argv[1][0]) {
  700.         case 'n':
  701.         case 'N':
  702.             nr_verbose = 0 ;
  703.             break ;
  704.         case 'y':
  705.         case 'Y':
  706.             nr_verbose = 1 ;
  707.             break ;
  708.         default:
  709.             printf("use: netrom verbose [yes|no]\n") ;
  710.             return -1 ;
  711.     }
  712.  
  713.     return 0 ;
  714. }
  715.  
  716. /* Initiate a NET/ROM transport connection */
  717. /*ARGSUSED*/
  718. static int
  719. donrconnect(argc,argv)
  720. int argc ;
  721. char *argv[] ;
  722. {
  723.     struct ax25_addr node, *np ;
  724.     struct session *s ;
  725.     char alias[7] ;
  726.  
  727.     /* See if the requested destination could be an alias, and */
  728.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  729.     /* address. */
  730.     
  731.     if (putalias(alias,argv[1],0) != -1 &&
  732.         (np = find_nralias(alias)) != NULLAXADDR)
  733.           node = *np ;
  734.     else
  735.         setcall(&node,argv[1]) ;    /* parse ax25 callsign */
  736.  
  737.     /* Get a session descriptor */
  738.  
  739.     if ((s = newsession()) == NULLSESSION) {
  740.         printf("Too many sessions\n") ;
  741.         return 1 ;
  742.     }
  743.  
  744.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  745.         strcpy(s->name,argv[1]);
  746.     s->type = NRSESSION ;
  747.     s->parse = (int (*)())nr4_parse ;
  748.     current = s;
  749.  
  750.     s->cb.nr4_cb = open_nr4(&node,&mycall,nr4_rx,nr4_tx,nr4_state,(char *)s) ;
  751.     go() ;
  752.     return 0 ;
  753. }
  754.  
  755. /* Display changes in NET/ROM state */
  756. /*ARGSUSED*/
  757. void
  758. nr4_state(cb,old,new)
  759. struct nr4cb *cb ;
  760. int old,new;
  761. {
  762.     struct session *s;
  763.  
  764.     s = (struct session *)cb->puser;
  765.  
  766.     if(current != NULLSESSION && current->type == NRSESSION && current == s){
  767.         printf("%s",Nr4states[new]);
  768.         if(new == NR4STDISC) {
  769.             printf(" (%s)\n", Nr4reasons[cb->dreason]) ;
  770.             cmdmode();
  771.         } else
  772.             printf("\n") ;
  773.         fflush(stdout);
  774.     }
  775.     if(new == NR4STDISC){
  776.         cb->puser = NULLCHAR;
  777.         freesession(s);
  778.     }
  779. }
  780.  
  781. /* Handle typed characters on a NET/ROM connection */
  782. void
  783. nr4_parse(buf,cnt)
  784. char *buf;
  785. int16 cnt;
  786. {
  787.     struct mbuf *bp;
  788.     register char *cp;
  789.     int16 size, i ;
  790.     char c;
  791.  
  792.     if(current == NULLSESSION || current->type != NRSESSION)
  793.         return;    /* "can't happen" */
  794.  
  795.     /* If recording is on, record outgoing stuff too */
  796.     if(current->record != NULLFILE)
  797.         fwrite(buf,1,(int)cnt,current->record);
  798.  
  799.     /* Parse it out, splitting at transport frame boundaries */
  800.     
  801.     while (cnt != 0) {
  802. #ifdef NRDEBUG
  803.         printf("Once around the parse loop - cnt = %d\n", cnt) ;
  804. #endif
  805.         size = min(cnt, NR4MAXINFO) ;
  806.         if ((bp = alloc_mbuf(size)) == NULLBUF)
  807.             break ;
  808.         /* Copy keyboard buffer to output, stripping line feeds */
  809.         cp = bp->data ;
  810.         for (i = 0 ; i < size ; i++){
  811.             c = *buf++;
  812.             if(c != '\n'){
  813.                 *cp++ = c;
  814.                 bp->cnt++;
  815.             }
  816.         }
  817.         cnt -= size ;
  818.         send_nr4(current->cb.nr4_cb,bp);
  819.     }
  820. }
  821.  
  822. /* Handle new incoming terminal sessions
  823.  * This is the default state change upcall function, used when
  824.  * someone else connects to us
  825.  */
  826. /*ARGSUSED*/
  827. void
  828. nr4_incom(cb,oldstate,newstate)
  829. struct nr4cb *cb ;
  830. int oldstate ;
  831. int newstate ;
  832. {
  833.     void nr4_session(), mbx_nr4incom() ;
  834.  
  835.     if (newstate != NR4STCON)        /* why are you bothering us? */
  836.         return ;                    /* (shouldn't happen) */
  837.         
  838.     if (ax25mbox)
  839.         mbx_nr4incom(cb) ;
  840.     else
  841.         nr4_session(cb) ;
  842.     return ;
  843.  
  844. }
  845.  
  846. /* This function sets up a NET/ROM chat session */
  847. void
  848. nr4_session(cb)
  849. struct nr4cb *cb ;
  850. {
  851.     struct session *s;
  852.     char remote[10];
  853.  
  854.     pax25(remote,&cb->user);
  855.     if((s = newsession()) == NULLSESSION){
  856.         /* Out of sessions */
  857.         disc_nr4(cb);
  858.         return;
  859.     }
  860.     s->type = NRSESSION ;
  861.     s->name = malloc((int16)strlen(remote)+1);
  862.     s->cb.nr4_cb = cb ;
  863.     s->parse = (int (*)())nr4_parse;
  864.     strcpy(s->name,remote);
  865.     cb->r_upcall = nr4_rx;
  866.     cb->s_upcall = nr4_state;
  867.     cb->t_upcall = nr4_tx;
  868.     cb->puser = (char *)s;
  869. #if    (defined(MAC) || defined(AMIGA))
  870.     printf("\007Incoming NET/ROM session %lu from %s\n",s - sessions,remote);
  871. #else
  872.     printf("\007Incoming NET/ROM session %u from %s\n",s - sessions,remote);
  873. #endif
  874.     fflush(stdout);
  875. }
  876.  
  877. /* Handle incoming terminal traffic */
  878. void
  879. nr4_rx(cb,cnt)
  880. struct nr4cb *cb ;
  881. int16 cnt;
  882. {
  883.     register struct mbuf *bp;
  884.     char c;
  885.  
  886.     /* Hold output if we're not the current session */
  887.     if(mode != CONV_MODE || current == NULLSESSION
  888.      || current->type != NRSESSION || current->cb.nr4_cb != cb)
  889.         return;
  890.  
  891.     if((bp = recv_nr4(cb,cnt)) == NULLBUF)
  892.         return;
  893.  
  894.     /* Display received characters, translating CR's to CR/LF */
  895.     while(bp != NULLBUF){
  896.         while(bp->cnt-- != 0){
  897.             c = *bp->data++;
  898.             if(c == '\r')
  899.                 c = '\n';
  900.             putchar(c);
  901.             if(current->record){
  902. #ifndef UNIX
  903.                 if(c == '\n')
  904.                     fputc('\r',current->record);
  905. #endif
  906.                 fputc(c,current->record);
  907.             }
  908.         }
  909.         bp = free_mbuf(bp);
  910.     }
  911.     if(current->record)
  912.         fflush(current->record);
  913.     fflush(stdout);
  914. }
  915.  
  916. /* Handle transmit upcalls. Used only for file uploading */
  917. void
  918. nr4_tx(cb,cnt)
  919. struct nr4cb *cb ;
  920. int16 cnt;
  921. {
  922.     register char *cp;
  923.     struct session *s;
  924.     register struct mbuf *bp;
  925.     int16 size;
  926.     int c;
  927.  
  928.     if((s = (struct session *)cb->puser) == NULLSESSION
  929.      || s->upload == NULLFILE)
  930.         return;
  931.     while(cnt != 0){
  932.         size = min(cnt,NR4MAXINFO);
  933.         if((bp = alloc_mbuf(size)) == NULLBUF)
  934.             break;
  935.         cp = bp->data;
  936.  
  937.         /* Now send data characters, translating between local
  938.          * keyboard end-of-line sequences and the (unwritten)
  939.          * AX.25 convention, which is carriage-return only
  940.          */
  941.          
  942.         while(bp->cnt < size){
  943.             if((c = getc(s->upload)) == EOF)
  944.                 break;
  945. #ifdef    MSDOS
  946.             /* MS-DOS gives cr-lf */
  947.             if(c == '\n')
  948.                 continue;
  949. #endif
  950. #if    (defined(UNIX) || defined(MAC) || defined(AMIGA))
  951.             /* These give lf only */
  952.             if(c == '\n')
  953.                 c = '\r';
  954. #endif
  955.             *cp++ = c;
  956.             bp->cnt++;
  957.         }    
  958.         cnt -= bp->cnt;
  959.         
  960.         if (bp->cnt != 0)    /* might happen with a newline at EOF */
  961.             send_nr4(cb,bp);
  962.         else
  963.             free_p(bp) ;
  964.             
  965.         if (c == EOF)
  966.             break ;
  967.     }
  968.     if(cnt != 0){
  969.         /* Error or end-of-file */
  970.         fclose(s->upload);
  971.         s->upload = NULLFILE;
  972.         free(s->ufile);
  973.         s->ufile = NULLCHAR;
  974.     }
  975. }
  976.  
  977. /* Reset a net/rom connection abruptly */
  978.  
  979. /*ARGSUSED*/
  980. static int
  981. donrreset(argc,argv)
  982. int argc;
  983. char *argv[];
  984. {
  985.     struct nr4cb *cb ;
  986.     extern char notval[];
  987.  
  988.     cb = (struct nr4cb *)htol(argv[1]);
  989.     if(!nr4valcb(cb)){
  990.         printf(notval);
  991.         return 1;
  992.     }
  993.     reset_nr4(cb);
  994.     return 0;
  995. }
  996.  
  997. /* Force retransmission on a net/rom connection */
  998.  
  999. /*ARGSUSED*/
  1000. static int
  1001. donrkick(argc,argv)
  1002. int argc;
  1003. char *argv[];
  1004. {
  1005.     struct nr4cb *cb ;
  1006.     extern char notval[];
  1007.  
  1008.     cb = (struct nr4cb *)htol(argv[1]);
  1009.  
  1010.     if (kick_nr4(cb) == -1) {
  1011.         printf(notval);
  1012.         return 1;
  1013.     } else
  1014.         return 0;
  1015. }
  1016.  
  1017. /* netrom transport ACK delay timer */
  1018.  
  1019. static
  1020. donracktime(argc, argv)
  1021. int argc ;
  1022. char *argv[] ;
  1023. {
  1024.     long val ;
  1025.  
  1026.     if (argc < 2) {
  1027.         printf("%lu\n", Nr4acktime) ;
  1028.         return 0 ;
  1029.     }
  1030.  
  1031.     val = atol(argv[1]) ;
  1032.  
  1033.     Nr4acktime = val ;
  1034.  
  1035.     return 0 ;
  1036. }
  1037.  
  1038. /* netrom transport choke timeout */
  1039.  
  1040. static
  1041. donrchoketime(argc, argv)
  1042. int argc ;
  1043. char *argv[] ;
  1044. {
  1045.     long val ;
  1046.  
  1047.     if (argc < 2) {
  1048.         printf("%lu\n", Nr4choketime) ;
  1049.         return 0 ;
  1050.     }
  1051.  
  1052.     val = atol(argv[1]) ;
  1053.  
  1054.     Nr4choketime = val ;
  1055.  
  1056.     return 0 ;
  1057. }
  1058.  
  1059. /* netrom transport initial round trip time */
  1060.  
  1061. static
  1062. donrirtt(argc, argv)
  1063. int argc ;
  1064. char *argv[] ;
  1065. {
  1066.     long val ;
  1067.  
  1068.     if (argc < 2) {
  1069.         printf("%lu\n", Nr4irtt) ;
  1070.         return 0 ;
  1071.     }
  1072.  
  1073.     val = atol(argv[1]) ;
  1074.  
  1075.     Nr4irtt = val ;
  1076.  
  1077.     return 0 ;
  1078. }
  1079.  
  1080. /* netrom transport receive queue length limit.  This is the */
  1081. /* threshhold at which we will CHOKE the sender. */
  1082.  
  1083. static
  1084. donrqlimit(argc, argv)
  1085. int argc ;
  1086. char *argv[] ;
  1087. {
  1088.     unsigned val ;
  1089.  
  1090.     if (argc < 2) {
  1091.         printf("%u\n", Nr4qlimit) ;
  1092.         return 0 ;
  1093.     }
  1094.  
  1095.     val = atoi(argv[1]) ;
  1096.  
  1097.     if (val == 0) {
  1098.         printf("You cannot set the queue limit to 0\n") ;
  1099.         return 1 ;
  1100.     }
  1101.     
  1102.     Nr4qlimit = val ;
  1103.  
  1104.     return 0 ;
  1105. }
  1106.  
  1107. /* netrom transport maximum window.  This is the largest send and */
  1108. /* receive window we may negotiate */
  1109.  
  1110. static
  1111. donrwindow(argc, argv)
  1112. int argc ;
  1113. char *argv[] ;
  1114. {
  1115.     unsigned val ;
  1116.  
  1117.     if (argc < 2) {
  1118.         printf("%u\n", Nr4window) ;
  1119.         return 0 ;
  1120.     }
  1121.  
  1122.     val = atoi(argv[1]) ;
  1123.  
  1124.     if (val == 0 || val > NR4MAXWIN) {
  1125.         printf("Illegal NET/ROM window size.  Range is [1,%d]\n",
  1126.                NR4MAXWIN) ;
  1127.         return 1 ;
  1128.     }
  1129.     
  1130.     Nr4window = val ;
  1131.  
  1132.     return 0 ;
  1133. }
  1134.  
  1135. /* netrom transport maximum retries.  This is used in connect and */
  1136. /* disconnect attempts; I haven't decided what to do about actual */
  1137. /* data retries yet. */
  1138.  
  1139. static
  1140. donrretries(argc, argv)
  1141. int argc ;
  1142. char *argv[] ;
  1143. {
  1144.     unsigned val ;
  1145.  
  1146.     if (argc < 2) {
  1147.         printf("%u\n", Nr4retries) ;
  1148.         return 0 ;
  1149.     }
  1150.  
  1151.     val = atoi(argv[1]) ;
  1152.  
  1153.     if (val == 0) {
  1154.         printf("Impatient, aren't we?  Zero retries not possible\n") ;
  1155.         return 1 ;
  1156.     }
  1157.     
  1158.     Nr4retries = val ;
  1159.  
  1160.     return 0 ;
  1161. }
  1162.  
  1163. /* Display the status of NET/ROM connections */
  1164.  
  1165. static
  1166. donrstatus(argc, argv)
  1167. int argc ;
  1168. char *argv[] ;
  1169. {
  1170.     int i ;
  1171.     struct nr4cb *cb ;
  1172.     char luser[10], ruser[10], node[10] ;
  1173.     extern char notval[] ;
  1174.     void donrdump() ;
  1175.     
  1176.     if (argc < 2) {
  1177.         printf("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1178.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  1179.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1180.                 continue ;
  1181.             pax25(luser,&cb->luser) ;
  1182.             pax25(ruser,&cb->user) ;
  1183.             pax25(node,&cb->node) ;
  1184.             printf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1185.                    (long)cb, cb->nbuffered, len_q(cb->txq),
  1186.                    len_mbuf(cb->rxq), luser, ruser, node,
  1187.                    Nr4states[cb->state]) ;
  1188.         }
  1189.         return 0 ;
  1190.     }
  1191.  
  1192.     cb = (struct nr4cb *)htol(argv[1]) ;
  1193.     if (!nr4valcb(cb)) {
  1194.         printf(notval) ;
  1195.         return 1 ;
  1196.     }
  1197.  
  1198.     donrdump(cb) ;
  1199.     return 0 ;
  1200. }
  1201.  
  1202. /* Dump one control block */
  1203.  
  1204. static void
  1205. donrdump(cb)
  1206. struct nr4cb *cb ;
  1207. {
  1208.     char luser[10], ruser[10], node[10] ;
  1209.     unsigned seq ;
  1210.     struct nr4txbuf *b ;
  1211.     struct timer *t ;
  1212.  
  1213.     pax25(luser,&cb->luser) ;
  1214.     pax25(ruser,&cb->user) ;
  1215.     pax25(node, &cb->node) ;
  1216.  
  1217.     printf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1218.            luser, cb->mynum, cb->myid, ruser, node,
  1219.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1220.  
  1221.     printf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1222.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1223.            len_mbuf(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1224.  
  1225.     printf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1226.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1227.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1228.  
  1229.     printf("TACK: ") ;
  1230.     if (run_timer(&cb->tack))
  1231.         printf("%lu", (cb->tack.start - cb->tack.count) * MSPTICK) ;
  1232.     else
  1233.         printf("stop") ;
  1234.     printf("/%lu ms; ", cb->tack.start * MSPTICK) ;
  1235.  
  1236.     printf("TChoke: ") ;
  1237.     if (run_timer(&cb->tchoke))
  1238.         printf("%lu", (cb->tchoke.start - cb->tchoke.count) * MSPTICK) ;
  1239.     else
  1240.         printf("stop") ;
  1241.     printf("/%lu ms; ", cb->tchoke.start * MSPTICK) ;
  1242.  
  1243.     printf("TCD: ") ;
  1244.     if (run_timer(&cb->tcd))
  1245.         printf("%lu", (cb->tcd.start - cb->tcd.count) * MSPTICK) ;
  1246.     else
  1247.         printf("stop") ;
  1248.     printf("/%lu ms", cb->tcd.start * MSPTICK) ;
  1249.  
  1250.     if (run_timer(&cb->tcd))
  1251.         printf("; Tries: %u\n", cb->cdtries) ;
  1252.     else
  1253.         printf("\n") ;
  1254.  
  1255.     printf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1256.            cb->blevel, cb->srtt, cb->mdev) ;
  1257.  
  1258.     /* If we are connected and the send window is open, display */
  1259.     /* the status of all the buffers and their timers */
  1260.     
  1261.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1262.  
  1263.         printf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1264.  
  1265.         for (seq = cb->ackxpected ;
  1266.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1267.              seq = (seq + 1) & NR4SEQMASK) {
  1268.  
  1269.             b = &cb->txbufs[seq % cb->window] ;
  1270.             t = &b->tretry ;
  1271.  
  1272.             printf("            %3u   %3d  %5d  %lu/%lu\n",
  1273.                    seq, len_mbuf(b->data), b->retries + 1,
  1274.                    (t->start - t->count) * MSPTICK, t->start * MSPTICK) ;
  1275.         }
  1276.  
  1277.     }
  1278.  
  1279. }
  1280.