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