home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / packet / n17jsrc / ax25cmd.c < prev    next >
C/C++ Source or Header  |  1991-10-14  |  19KB  |  905 lines

  1. /* AX25 control commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  /* Mods by G1EMM */
  5.  /* Mods by N1BEE */
  6. /*
  7. ** FILE: ax25cmd.c
  8. **
  9. ** AX.25 command handler.
  10. **
  11. ** 09/24/90 Bob Applegate, wa2zzx
  12. **    Added BCTEXT, BC, and BCINTERVAL commands for broadcasting an id
  13. **    string using UI frames.
  14. **
  15. ** 27/09/91 Mike Bilow, N1BEE
  16. **    Added Filter command for axheard control
  17. */
  18.  
  19. #include <stdio.h>
  20. #include "global.h"
  21. #include "config.h"
  22. #include "mbuf.h"
  23. #include "timer.h"
  24. #include "proc.h"
  25. #include "iface.h"
  26. #include "ax25.h"
  27. #include "lapb.h"
  28. #include "cmdparse.h"
  29. #include "socket.h"
  30. #include "mailbox.h"
  31. #include "session.h"
  32. #include "tty.h"
  33. #include "nr4.h"
  34. #include "commands.h"
  35. #include "pktdrvr.h"
  36.  
  37. static int axheard __ARGS((struct iface *ifp));
  38. static void axflush __ARGS((struct iface *ifp));
  39. static int doaxfilter __ARGS((int argc,char *argv[],void *p));
  40. static int doaxflush __ARGS((int argc,char *argv[],void *p));
  41. static int doaxirtt __ARGS((int argc,char *argv[],void *p));
  42. static int doaxkick __ARGS((int argc,char *argv[],void *p));
  43. static int doaxreset __ARGS((int argc,char *argv[],void *p));
  44. static int doaxroute __ARGS((int argc,char *argv[],void *p));
  45. static int doaxstat __ARGS((int argc,char *argv[],void *p));
  46. static int doaxwindow __ARGS((int argc,char *argv[],void *p));
  47. static int dobc __ARGS((int argc,char *argv[],void *p));
  48. static int dobcint __ARGS((int argc,char *argv[],void *p));
  49. static int dobctext __ARGS((int argc,char *argv[],void *p));
  50. static int doblimit __ARGS((int argc,char *argv[],void *p));
  51. static int dodigipeat __ARGS((int argc,char *argv[],void *p));
  52. static int domaxframe __ARGS((int argc,char *argv[],void *p));
  53. static int domycall __ARGS((int argc,char *argv[],void *p));
  54. static int don2 __ARGS((int argc,char *argv[],void *p));
  55. static int dopaclen __ARGS((int argc,char *argv[],void *p));
  56. static int dopthresh __ARGS((int argc,char *argv[],void *p));
  57. static int dot3 __ARGS((int argc,char *argv[],void *p));
  58. static int doaxtype __ARGS((int argc,char *argv[],void *p));
  59. static int dot4 __ARGS((int argc,char *argv[],void *p));
  60. static int doversion __ARGS((int argc,char *argv[],void *p));
  61. static void ax_bc __ARGS((struct iface *axif));
  62. static int axdest __ARGS((struct iface *ifp));
  63.  
  64. extern int axheard_filter_flag;        /* in axheard.c */
  65.  
  66. /*
  67. ** Default broadcast 'to' address in shifted ASCII
  68. */
  69.  
  70. char ax_bcto[AXALEN] = {
  71.     'I'<<1, 'D'<<1, ' '<<1, ' '<<1, ' '<<1, ' '<<1, ('0'<<1) | E
  72. };
  73.  
  74. /*
  75. ** Defaults for IDing...
  76. */
  77.  
  78. char *axbctext = NULL;                /* Text to send */
  79. static struct timer Broadtimer;    /* timer for broadcasts */
  80.  
  81.  
  82. char *Ax25states[] = {
  83.     "",
  84.     "Disconnected",
  85.     "Listening",
  86.     "Conn pending",
  87.     "Disc pending",
  88.     "Connected",
  89.     "Recovery",
  90. };
  91.  
  92. /* Ascii explanations for the disconnect reasons listed in lapb.h under
  93.  * "reason" in ax25_cb
  94.  */
  95. char *Axreasons[] = {
  96.     "Normal",
  97.     "DM received",
  98.     "Timeout"
  99. };
  100.  
  101. static struct cmds Axcmds[] = {
  102.     "bc",        dobc,        0, 0, NULLCHAR,
  103.     "bcinterval",    dobcint,    0, 0, NULLCHAR,
  104.     "blimit",    doblimit,    0, 0, NULLCHAR,
  105.     "bctext",    dobctext,    0, 0, NULLCHAR,
  106.     "digipeat",    dodigipeat,    0, 0, NULLCHAR,
  107.     "filter",    doaxfilter,    0, 0, NULLCHAR,
  108.     "flush",    doaxflush,    0, 0, NULLCHAR,
  109.     "heard",    doaxheard,    0, 0, NULLCHAR,
  110.     "hearddest",    doaxdest,    0, 0, NULLCHAR,
  111.     "irtt",        doaxirtt,    0, 0, NULLCHAR,
  112.     "kick",        doaxkick,    0, 2, "ax25 kick <axcb>",
  113.     "maxframe",    domaxframe,    0, 0, NULLCHAR,
  114.     "mycall",    domycall,    0, 0, NULLCHAR,
  115.     "paclen",    dopaclen,    0, 0, NULLCHAR,
  116.     "pthresh",    dopthresh,    0, 0, NULLCHAR,
  117.     "reset",    doaxreset,    0, 2, "ax25 reset <axcb>",
  118.     "retry",    don2,        0, 0, NULLCHAR,
  119.     "route",    doaxroute,    0, 0, NULLCHAR,
  120.     "status",    doaxstat,    0, 0, NULLCHAR,
  121.     "t3",        dot3,        0, 0, NULLCHAR,
  122.     "t4",        dot4,        0, 0, NULLCHAR,
  123.     "timertype",    doaxtype,    0, 0, NULLCHAR,
  124.     "version",    doversion,    0, 0, NULLCHAR,
  125.     "window",    doaxwindow,    0, 0, NULLCHAR,
  126.     NULLCHAR,
  127. };
  128. /* Multiplexer for top-level ax25 command */
  129. int
  130. doax25(argc,argv,p)
  131. int argc;
  132. char *argv[];
  133. void *p;
  134. {
  135.     return subcmd(Axcmds,argc,argv,p);
  136. }
  137.  
  138.  
  139.  
  140. /*
  141. ** This function is called to send the current broadcast message
  142. ** and reset the timer.
  143. */
  144.  
  145. static int dobc(argc,argv,p)
  146. int argc;
  147. char *argv[];
  148. void *p;
  149. {
  150.     struct iface *ifa;
  151.  
  152.     if (argc < 2)
  153.     {
  154.         printf("you need to specify an interface\n");
  155.         return 1;
  156.     }
  157.  
  158.     ifa = Ifaces;
  159.     while (ifa != NULL && stricmp(ifa->name,argv[1]))
  160.         ifa = ifa->next;
  161.     if (ifa == NULL)
  162.         printf("unknown interface\n");
  163.     else if (ifa->type != CL_AX25)
  164.         printf("not an AX.25 interface\n");
  165.     else
  166.     {
  167.         ax_bc(ifa);
  168.         stop_timer(&Broadtimer) ;    /* in case it's already running */
  169.         start_timer(&Broadtimer);        /* and fire it up */
  170.     }
  171.     return 0;
  172. }
  173.  
  174.  
  175.  
  176. /*
  177. ** View/Change the message we broadcast.
  178. */
  179.  
  180. static int dobctext(argc,argv,p)
  181. int argc;
  182. char *argv[];
  183. void *p;
  184. {
  185.     if (argc < 2)
  186.         printf("Broadcast text: %s\n",axbctext);
  187.     else
  188.     {
  189.         if (axbctext != NULL) free(axbctext);
  190.         axbctext = malloc(strlen(argv[1]));
  191.         strcpy(axbctext,argv[1]);
  192.     }
  193.     return 0;
  194. }
  195.  
  196.  
  197.  
  198. #define TICKSPERSEC    (1000L / MSPTICK)    /* Ticks per second */
  199.  
  200. /*
  201. ** Examine/change the broadcast interval.
  202. */
  203.  
  204. static int dobcint(argc,argv,p)
  205. int argc;
  206. char *argv[];
  207. void *p;
  208. {
  209.     void dobroadtick();
  210.  
  211.     if(argc < 2)
  212.     {
  213.         tprintf("Broadcast timer %lu/%lu seconds\n",
  214.             read_timer(&Broadtimer)/1000L,
  215.             dur_timer(&Broadtimer)/1000L);
  216.         return 0;
  217.     }
  218.     stop_timer(&Broadtimer) ;    /* in case it's already running */
  219.     Broadtimer.func = (void (*)())dobroadtick;/* what to call on timeout */
  220.     Broadtimer.arg = NULLCHAR;        /* dummy value */
  221.     set_timer(&Broadtimer,atoi(argv[1])*1000L);    /* set timer duration */
  222.     start_timer(&Broadtimer);        /* and fire it up */
  223.     return 0;
  224. }
  225.  
  226. void
  227. dobroadtick()
  228. {
  229.     struct iface *ifa;
  230.  
  231.     ifa = Ifaces;
  232.  
  233.     while (ifa != NULL)
  234.     {
  235.         if (ifa->type == CL_AX25) ax_bc(ifa);
  236.         ifa = ifa->next;
  237.     }
  238.  
  239.     /* Restart timer */
  240.     start_timer(&Broadtimer) ;
  241. }
  242.  
  243.  
  244.  
  245. /*
  246. ** This is the low-level broadcast function.
  247. */
  248.  
  249. static void ax_bc(axif)
  250. struct iface *axif;
  251. {
  252.     struct mbuf *hbp;
  253.     int i;
  254.     
  255.     /* prepare the header */
  256.     i = strlen(axbctext);
  257.     if((hbp = alloc_mbuf(i)) == NULLBUF)
  258.         return;
  259.         
  260.     hbp->cnt = i;    
  261.     memcpy(hbp->data,axbctext,i);
  262.  
  263.     (*axif->output)(axif, ax_bcto, axif->hwaddr,
  264.         PID_NO_L3, hbp);    /* send it */
  265.  
  266.     /*
  267.     ** Call another function to reset the timer...
  268.     reset_bc_timer();
  269.     */
  270. }
  271.  
  272.  
  273. int
  274. doaxheard(argc,argv,p)
  275. int argc;
  276. char *argv[];
  277. void *p;
  278. {
  279.     struct iface *ifp;
  280.  
  281.     if(argc > 1){
  282.         if((ifp = if_lookup(argv[1])) == NULLIF){
  283.             tprintf("Interface %s unknown\n",argv[1]);
  284.             return 1;
  285.         }
  286.         if(ifp->output != ax_output){
  287.             tprintf("Interface %s not AX.25\n",argv[1]);
  288.             return 1;
  289.         }
  290.         axheard(ifp);
  291.         return 0;
  292.     }
  293.     for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  294.         if(ifp->output != ax_output)
  295.             continue;    /* Not an ax.25 interface */
  296.         if(axheard(ifp) == EOF)
  297.             break;
  298.     }
  299.     return 0;
  300. }
  301. static int
  302. axheard(ifp)
  303. struct iface *ifp;
  304. {
  305.     int i, col = 0;
  306.     struct lq *lp;
  307.     char tmp[AXBUF];
  308.  
  309.     if(ifp->hwaddr == NULLCHAR)
  310.         return 0;
  311.  
  312.     tprintf("Interface  Station   Time since send  Pkts sent\n");
  313.     tprintf("%-9s  %-9s   %12s    %7lu\n",ifp->name,pax25(tmp,ifp->hwaddr),
  314.      tformat(secclock() - ifp->lastsent),ifp->rawsndcnt);
  315.  
  316.     tprintf("Station   Time since heard Pkts rcvd : ");
  317.     tprintf("Station   Time since heard Pkts rcvd\n");
  318.     for(lp = Lq;lp != NULLLQ;lp = lp->next){
  319.         if(lp->iface != ifp)
  320.             continue;
  321.         if(col)
  322.             tprintf("  : ");
  323.         if(tprintf("%-9s   %12s    %7lu",pax25(tmp,lp->addr),
  324.          tformat(secclock() - lp->time),lp->currxcnt) == EOF)
  325.             return EOF;
  326.         if(col){
  327.             if(tprintf("\n") == EOF){
  328.                 return EOF;
  329.             } else {
  330.                 col = 0;
  331.             }
  332.         } else {
  333.             col = 1;
  334.         }
  335.     }
  336.     if(col)
  337.         tprintf("\n");
  338.     return 0;
  339. }
  340. int
  341. doaxdest(argc,argv,p)
  342. int argc;
  343. char *argv[];
  344. void *p;
  345. {
  346.     struct iface *ifp;
  347.  
  348.     if(argc > 1){
  349.         if((ifp = if_lookup(argv[1])) == NULLIF){
  350.             tprintf("Interface %s unknown\n",argv[1]);
  351.             return 1;
  352.         }
  353.         if(ifp->output != ax_output){
  354.             tprintf("Interface %s not AX.25\n",argv[1]);
  355.             return 1;
  356.         }
  357.         axdest(ifp);
  358.         return 0;
  359.     }
  360.     for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  361.         if(ifp->output != ax_output)
  362.             continue;    /* Not an ax.25 interface */
  363.         if(axdest(ifp) == EOF)
  364.             break;
  365.     }
  366.     return 0;
  367. }
  368. static int
  369. axdest(ifp)
  370. struct iface *ifp;
  371. {
  372.     struct ld *lp;
  373.     struct lq *lq;
  374.     char tmp[AXBUF];
  375.  
  376.     if(ifp->hwaddr == NULLCHAR)
  377.         return 0;
  378.     tprintf("%s:\n",ifp->name);
  379.     tprintf("Station   Last ref         Last heard           Pkts\n");
  380.     for(lp = Ld;lp != NULLLD;lp = lp->next){
  381.         if(lp->iface != ifp)
  382.             continue;
  383.  
  384.         tprintf("%-10s%-17s",
  385.          pax25(tmp,lp->addr),tformat(secclock() - lp->time));
  386.  
  387.         if(addreq(lp->addr,ifp->hwaddr)){
  388.             /* Special case; it's our address */
  389.             tprintf("%-17s",tformat(secclock() - ifp->lastsent));
  390.         } else if((lq = al_lookup(ifp,lp->addr,0)) == NULLLQ){
  391.             tprintf("%-17s","");
  392.         } else {
  393.             tprintf("%-17s",tformat(secclock() - lq->time));
  394.         }
  395.         if(tprintf("%8lu\n",lp->currxcnt) == EOF)
  396.             return EOF;
  397.     }
  398.     return 0;
  399. }
  400.  
  401. static int
  402. doaxfilter(argc,argv,p)
  403. int argc;
  404. char *argv[];
  405. void *p;
  406. {
  407.     if(argc >= 2){
  408.         setint(&axheard_filter_flag,"ax25 heard filter",argc,argv);
  409.     } else {
  410.         tprintf("Usage: ax25 filter <0|1|2|3>\n");
  411.         return 1;
  412.     }
  413.  
  414.     tprintf("Callsign loggin by source ");
  415.     if(axheard_filter_flag & AXHEARD_NOSRC)
  416.         tprintf("disabled, ");
  417.     else
  418.         tprintf("enabled, ");
  419.     tprintf("by destination ");
  420.     if(axheard_filter_flag & AXHEARD_NODST)
  421.         tprintf("disabled\n");
  422.     else
  423.         tprintf("enabled\n");
  424.     return 0;
  425. }
  426.  
  427. static int
  428. doaxflush(argc,argv,p)
  429. int argc;
  430. char *argv[];
  431. void *p;
  432. {
  433.     struct iface *ifp;
  434.  
  435.     for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  436.         if(ifp->output != ax_output)
  437.             continue;    /* Not an ax.25 interface */
  438.         axflush(ifp);
  439.     }
  440.     return 0;
  441. }
  442. static void
  443. axflush(ifp)
  444. struct iface *ifp;
  445. {
  446.     struct lq *lp,*lp1;
  447.     struct ld *ld,*ld1;
  448.  
  449.     ifp->rawsndcnt = 0;
  450.     for(lp = Lq;lp != NULLLQ;lp = lp1){
  451.         lp1 = lp->next;
  452.         free((char *)lp);
  453.     }
  454.     Lq = NULLLQ;
  455.     for(ld = Ld;ld != NULLLD;ld = ld1){
  456.         ld1 = ld->next;
  457.         free((char *)ld);
  458.     }
  459.     Ld = NULLLD;
  460. }
  461.  
  462. static
  463. doaxreset(argc,argv,p)
  464. int argc;
  465. char *argv[];
  466. void *p;
  467. {
  468.     struct ax25_cb *axp;
  469.  
  470.     axp = (struct ax25_cb *)ltop(htol(argv[1]));
  471.     if(!ax25val(axp)){
  472.         tprintf(Notval);
  473.         return 1;
  474.     }
  475.     reset_ax25(axp);
  476.     return 0;
  477. }
  478.  
  479. /* Display AX.25 link level control blocks */
  480. static
  481. doaxstat(argc,argv,p)
  482. int argc;
  483. char *argv[];
  484. void *p;
  485. {
  486.     register struct ax25_cb *axp;
  487.     char tmp[AXBUF];
  488.  
  489.     if(argc < 2){
  490.         tprintf("    &AXB Snd-Q   Rcv-Q   Remote    State\n");
  491.         for(axp = Ax25_cb;axp != NULLAX25; axp = axp->next){
  492.             if(tprintf("%8lx %-8d%-8d%-10s%s\n",
  493.                 ptol(axp),
  494.                 len_q(axp->txq),len_p(axp->rxq),
  495.                 pax25(tmp,axp->remote),
  496.                 Ax25states[axp->state]) == EOF)
  497.                     return 0;
  498.         }
  499.         return 0;
  500.     }
  501.     axp = (struct ax25_cb *)ltop(htol(argv[1]));
  502.     if(!ax25val(axp)){
  503.         tprintf(Notval);
  504.         return 1;
  505.     }
  506.     st_ax25(axp);
  507.     return 0;
  508. }
  509. /* Dump one control block */
  510. void
  511. st_ax25(axp)
  512. register struct ax25_cb *axp;
  513. {
  514.     char tmp[AXBUF];
  515.  
  516.     if(axp == NULLAX25)
  517.         return;
  518.     tprintf("    &AXB Remote   RB V(S) V(R) Unack P Retry State\n");
  519.  
  520.     tprintf("%8lx %-9s%c%c",ptol(axp),pax25(tmp,axp->remote),
  521.      axp->flags.rejsent ? 'R' : ' ',
  522.      axp->flags.remotebusy ? 'B' : ' ');
  523.     tprintf(" %4d %4d",axp->vs,axp->vr);
  524.     tprintf(" %02u/%02u %u",axp->unack,axp->maxframe,axp->proto);
  525.     tprintf(" %02u/%02u",axp->retries,axp->n2);
  526.     tprintf(" %s\n",Ax25states[axp->state]);
  527.     tprintf("srtt = %lu mdev = %lu ",axp->srt,axp->mdev);
  528.     tprintf("T1: ");
  529.     if(run_timer(&axp->t1))
  530.         tprintf("%lu",read_timer(&axp->t1));
  531.     else
  532.         tprintf("stop");
  533.     tprintf("/%lu ms; ",dur_timer(&axp->t1));
  534.  
  535.     tprintf("T3: ");
  536.     if(run_timer(&axp->t3))
  537.         tprintf("%lu",read_timer(&axp->t3));
  538.     else
  539.         tprintf("stop");
  540.     tprintf("/%lu ms; ",dur_timer(&axp->t3));
  541.  
  542.     tprintf("T4: ");
  543.     if(run_timer(&axp->t4))
  544.         tprintf("%lu",(read_timer(&axp->t4)));
  545.     else
  546.         tprintf("stop");
  547.     tprintf("/%lu sec\n",(dur_timer(&axp->t4)));
  548. }
  549.  
  550. /* Set limit on retransmission backoff */
  551. static
  552. doblimit(argc,argv,p)
  553. int argc;
  554. char *argv[];
  555. void *p;
  556. {
  557.     return setlong(&Blimit,"blimit",argc,argv);
  558. }
  559.  
  560. /* Display or change our AX.25 address */
  561. static
  562. domycall(argc,argv,p)
  563. int argc;
  564. char *argv[];
  565. void *p;
  566. {
  567.     char tmp[AXBUF];
  568.  
  569.     if(argc < 2){
  570.         tprintf("%s\n",pax25(tmp,Mycall));
  571.         return 0;
  572.     }
  573.     if(setcall(Mycall,argv[1]) == -1)
  574.         return -1;
  575.     return 0;
  576. }
  577.  
  578. /* Control AX.25 digipeating */
  579. static
  580. dodigipeat(argc,argv,p)
  581. int argc;
  582. char *argv[];
  583. void *p;
  584. {
  585.     return setbool(&Digipeat,"Digipeat",argc,argv);
  586. }
  587. static
  588. doversion(argc,argv,p)
  589. int argc;
  590. char *argv[];
  591. void *p;
  592. {
  593.     return setshort(&Axversion,"AX25 version",argc,argv);
  594. }
  595.  
  596. static
  597. doaxirtt(argc,argv,p)
  598. int argc;
  599. char *argv[];
  600. void *p;
  601. {
  602.     return setlong(&Axirtt,"Initial RTT (ms)",argc,argv);
  603. }
  604.  
  605. /* Set idle timer */
  606. static
  607. dot3(argc,argv,p)
  608. int argc;
  609. char *argv[];
  610. void *p;
  611. {
  612.     return setlong(&T3init,"Idle poll timer (ms)",argc,argv);
  613. }
  614.  
  615. /* Set link redundancy timer */
  616. static
  617. dot4(argc,argv,p)
  618. int argc;
  619. char *argv[];
  620. void *p;
  621. {
  622.     return setlong(&T4init,"Link redundancy timer (sec)",argc,argv);
  623. }
  624.  
  625. /* Set retry limit count */
  626. static
  627. don2(argc,argv,p)
  628. int argc;
  629. char *argv[];
  630. void *p;
  631. {
  632.     return setshort(&N2,"Retry limit",argc,argv);
  633. }
  634. /* Force a retransmission */
  635. static
  636. doaxkick(argc,argv,p)
  637. int argc;
  638. char *argv[];
  639. void *p;
  640. {
  641.     struct ax25_cb *axp;
  642.  
  643.     axp = (struct ax25_cb *)ltop(htol(argv[1]));
  644.     if(!ax25val(axp)){
  645.         tprintf(Notval);
  646.         return 1;
  647.     }
  648.     kick_ax25(axp);
  649.     return 0;
  650. }
  651. /* Set maximum number of frames that will be allowed in flight */
  652. static
  653. domaxframe(argc,argv,p)
  654. int argc;
  655. char *argv[];
  656. void *p;
  657. {
  658.     return setshort(&Maxframe,"Window size (frames)",argc,argv);
  659. }
  660.  
  661. /* Set maximum length of I-frame data field */
  662. static
  663. dopaclen(argc,argv,p)
  664. int argc;
  665. char *argv[];
  666. void *p;
  667. {
  668.     return setshort(&Paclen,"Max frame length (bytes)",argc,argv);
  669. }
  670. /* Set size of I-frame above which polls will be sent after a timeout */
  671. static
  672. dopthresh(argc,argv,p)
  673. int argc;
  674. char *argv[];
  675. void *p;
  676. {
  677.     return setshort(&Pthresh,"Poll threshold (bytes)",argc,argv);
  678. }
  679.  
  680. /* Set high water mark on receive queue that triggers RNR */
  681. static
  682. doaxwindow(argc,argv,p)
  683. int argc;
  684. char *argv[];
  685. void *p;
  686. {
  687.     return setshort(&Axwindow,"AX25 receive window (bytes)",argc,argv);
  688. }
  689. /* End of ax25 subcommands */
  690.  
  691. /* Initiate interactive AX.25 connect to remote station */
  692. int
  693. doconnect(argc,argv,p)
  694. int argc;
  695. char *argv[];
  696. void *p;
  697. {
  698.     struct sockaddr_ax fsocket;
  699.     struct session *sp;
  700.     struct iface *ifp;
  701.     int ndigis,i;
  702.     char digis[MAXDIGIS][AXALEN];
  703.     char target[AXALEN];
  704.  
  705.     if(((ifp = if_lookup(argv[1])) != NULLIF) && (ifp->type != CL_AX25)) {
  706.         tprintf("Iface %s not an AX25 type interface\n",argv[1]);
  707.         return 1;
  708.     }
  709.  
  710.     if(setcall(target,argv[2]) == -1){
  711.         tprintf("Bad callsign %s\n", argv[2]);
  712.         return 1;
  713.     }
  714.  
  715.     /* If digipeaters are given, put them in the routing table */
  716.     if(argc > 3){
  717.         if(setcall(target,argv[2]) == -1){
  718.             tprintf("Bad callsign %s\n", argv[2]);
  719.             return 1;
  720.         }
  721.         ndigis = argc - 3;
  722.         if(ndigis > MAXDIGIS){
  723.             tprintf("Too many digipeaters\n");
  724.             return 1;
  725.         }
  726.         for(i=0;i<ndigis;i++){
  727.             if(setcall(digis[i],argv[i+3]) == -1){
  728.                 tprintf("Bad digipeater %s\n",argv[i+3]);
  729.                 return 1;
  730.             }
  731.         }
  732.         if(ax_add(target,AX_LOCAL,digis,ndigis) == NULLAXR){
  733.             tprintf("Route add failed\n");
  734.             return 1;
  735.         }
  736.     }
  737.     /* Allocate a session descriptor */
  738.     if((sp = newsession(argv[2],AX25TNC,0)) == NULLSESSION){
  739.         tprintf("Too many sessions\n");
  740.         return 1;
  741.     }
  742.     if((sp->s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  743.         tprintf("Can't create socket\n");
  744.         freesession(sp);
  745.         keywait(NULLCHAR,1);
  746.         return 1;
  747.     }
  748.     fsocket.sax_family = AF_AX25;
  749.     setcall(fsocket.ax25_addr,argv[2]);
  750.     strncpy(fsocket.iface,argv[1],ILEN);
  751.     return tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_ax));
  752. }
  753.  
  754. /* Display and modify AX.25 routing table */
  755. static int
  756. doaxroute(argc,argv,p)
  757. int argc;
  758. char *argv[];
  759. void *p;
  760. {
  761.     char tmp[AXBUF];
  762.     int i,ndigis;
  763.     register struct ax_route *axr;
  764.     char target[AXALEN],digis[MAXDIGIS][AXALEN];
  765.  
  766.     if(argc < 2){
  767.         tprintf("Target    Type  Mode Digipeaters\n");
  768.         for(axr = Ax_routes;axr != NULLAXR;axr = axr->next){
  769.             tprintf("%-10s%-6s",pax25(tmp,axr->target),
  770.              axr->type == AX_LOCAL ? "Local":"Auto");
  771.             switch(axr->mode){
  772.             case AX_VC_MODE:
  773.                 tprintf(" VC ");
  774.                 break;
  775.             case AX_DATMODE:
  776.                 tprintf(" DG ");
  777.                 break;
  778.             case AX_DEFMODE:
  779.                 tprintf(" IF ");
  780.                 break;
  781.             default:
  782.                 tprintf(" ?? ");
  783.                 break;
  784.             }
  785.  
  786.             for(i=0;i<axr->ndigis;i++){
  787.                 tprintf(" %s",pax25(tmp,axr->digis[i]));
  788.             }
  789.             if(tprintf("\n") == EOF)
  790.                 return 0;
  791.         }
  792.         return 0;
  793.     }
  794.     if(argc < 3){
  795.         tprintf("Usage: ax25 route add <target> [digis...]\n");
  796.         tprintf("       ax25 route drop <target>\n");
  797.         tprintf("       ax25 route mode <target> [mode]\n");
  798.         return 1;
  799.     }
  800.     if(setcall(target,argv[2]) == -1){
  801.         tprintf("Bad target %s\n",argv[2]);
  802.         return 1;
  803.     }
  804.     switch(argv[1][0]){
  805.     case 'a':    /* Add route */
  806.         ndigis = argc - 3;
  807.         if(ndigis > MAXDIGIS){
  808.             tprintf("Too many digipeaters\n");
  809.             return 1;
  810.         }
  811.         for(i=0;i<ndigis;i++){
  812.             if(setcall(digis[i],argv[i+3]) == -1){
  813.                 tprintf("Bad digipeater %s\n",argv[i+3]);
  814.                 return 1;
  815.             }
  816.         }
  817.         if(ax_add(target,AX_LOCAL,digis,ndigis) == NULLAXR){
  818.             tprintf("Failed\n");
  819.             return 1;
  820.         }
  821.         break;
  822.     case 'd':    /* Drop route */
  823.         if(ax_drop(target) == -1){
  824.             tprintf("Not in table\n");
  825.             return 1;
  826.         }
  827.         break;
  828.     case 'm':    /* Alter route mode */
  829.         if(argc < 4){
  830.             tprintf("Usage: ax25 route mode <target> <mode>\n");
  831.             tprintf("Where mode is 'vc', 'datagram' or 'interface'\n");
  832.             return 1;
  833.         }
  834.         if((axr = ax_lookup(target)) == NULLAXR){
  835.             tprintf("Not in table\n");
  836.             return 1;
  837.         }
  838.         switch(argv[3][0]){
  839.         case 'i':    /* use default interface mode */
  840.             axr->mode = AX_DEFMODE;
  841.             break;
  842.         case 'v':    /* use virtual circuit mode */
  843.             axr->mode = AX_VC_MODE;
  844.             break;
  845.         case 'd':    /* use datagram mode */
  846.             axr->mode = AX_DATMODE;
  847.             break;
  848.         default:
  849.             tprintf("Unknown mode %s\n", argv[3]);
  850.             return 1;
  851.         }
  852.         break;
  853.     default:
  854.         tprintf("Unknown command %s\n",argv[1]);
  855.         return 1;
  856.     }
  857.     return 0;
  858. }
  859.  
  860. /* ax25 timers type - linear v exponential */
  861. static
  862. doaxtype(argc,argv,p)
  863. int argc ;
  864. char *argv[] ;
  865. void *p ;
  866. {
  867.     extern unsigned lapbtimertype;
  868.  
  869.     if (argc < 2) {
  870.         tprintf("AX25 timer type is ");
  871.         switch(lapbtimertype){
  872.         case 2:
  873.             tprintf("original\n");
  874.             break;
  875.         case 1:
  876.             tprintf("linear\n");
  877.             break;
  878.         case 0:
  879.             tprintf("exponential\n");
  880.             break;
  881.         }
  882.         return 0 ;
  883.     }
  884.     
  885.     switch (argv[1][0]) {
  886.         case 'o':
  887.         case 'O':
  888.             lapbtimertype = 2 ;
  889.             break ;
  890.         case 'l':
  891.         case 'L':
  892.             lapbtimertype = 1 ;
  893.             break ;
  894.         case 'e':
  895.         case 'E':
  896.             lapbtimertype = 0 ;
  897.             break ;
  898.         default:
  899.             tprintf("use: ax25 timertype [original|linear|exponential]\n") ;
  900.             return -1 ;
  901.     }
  902.  
  903.     return 0 ;
  904. }
  905.