home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / k95source / ckoslp.c < prev    next >
C/C++ Source or Header  |  2020-01-01  |  48KB  |  1,193 lines

  1. /* C K O S L P -- Kermit interface to the IBM SLIP driver */
  2.  
  3. /*
  4.   Authors: Jeffrey Altman (jaltman@secure-endpoints.com),
  5.              Secure Endpoints Inc., New York City.
  6.            David Bolen (db3l@ans.net)
  7.  
  8.   Copyright (C) 1985, 2004, Trustees of Columbia University in the City of New
  9.   York.
  10. */
  11.  
  12. #include "ckcdeb.h"
  13. #ifndef NT
  14. #define INCL_ERRORS
  15. #define INCL_DOSMISC
  16. #define INCL_DOSPROCESS
  17. #define INCL_DOSSEMAPHORES
  18. #define  INCL_DOSNMPIPES
  19. #include <os2.h>
  20. #undef COMMENT
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <ctype.h>
  27.  
  28. #include "ckoslp.h"
  29.  
  30. /*--------------------------------------------------------------------------*/
  31. /* Definitions used for interface information                               */
  32. /*--------------------------------------------------------------------------*/
  33.  
  34. /* VJ Compression Options */
  35. #define slc_NOCOMPRESSION       0       /* No compression at all            */
  36. #define slc_COMPRESSION         1       /* Always send compression          */
  37. #define slc_AUTOCOMPRESSION     2       /* Enable compression when received */
  38.  
  39.  
  40. /*--------------------------------------------------------------------------*/
  41. /* Interface structure (used to return interface configuration information) */
  42. /*--------------------------------------------------------------------------*/
  43. typedef struct slcS_INTERFACE_ {
  44.                                         /* -- INET Attachment Information -- */
  45.  
  46.    char           if_name[4];           /* sl?   (?=0-9)                     */
  47.    unsigned short if_mtu;               /* MTU for interface                 */
  48.  
  49.    unsigned short if_rtt;               /* Estimated rtt, rttvar and rttmin  */
  50.    unsigned short if_rttvar;            /*   for routes making use of this   */
  51.    unsigned short if_rttmin;            /*   interface (in ms)               */
  52.  
  53.    unsigned short if_sendpipe;          /* Maximum send/recv pipes (socket   */
  54.    unsigned short if_recvpipe;          /*   buffers and TCP windows)        */
  55.    unsigned short if_ssthresh;          /* Slow-start threshold (segments)   */
  56.  
  57.    unsigned short if_maxqueue;          /* Maximum interface queue size      */
  58.    unsigned short if_maxfastq;          /* Maximum fast queue size           */
  59.  
  60.                                         /* -- Other Interface Settings  --   */
  61.  
  62.    int allowfastq,                      /* Should fast queueing be used      */
  63.        compression;                     /* VJ compression options            */
  64.    char *device;                        /* OS/2 device for interface         */
  65.  
  66.                                         /* -- Interface Command Scripts --   */
  67.    char *attachcmd,
  68.         *attachparms;                   /* and their parameters              */
  69.  
  70.  
  71.    struct slcS_INTERFACE_ *next;        /* Pointer to next parsed interface  */
  72.  
  73. } slcS_INTERFACE, *slcPS_INTERFACE;
  74.  
  75.  
  76. /*--------------------------------------------------------------------------*/
  77. /* Function prototypes.                                                     */
  78. /*--------------------------------------------------------------------------*/
  79.  
  80. /*--------------------------------------------------*/
  81. /*                Parsing Functions                 */
  82. /*--------------------------------------------------*/
  83.  
  84. int slcParseConfiguration (char *Filename, slcPS_INTERFACE *Interfaces);
  85. int slcFreeConfiguration  (slcPS_INTERFACE *Interfaces);
  86.  
  87. /*
  88.  *  Variables
  89.  */
  90.  
  91. /* Semaphores and Pipe for communicating with SLIP.EXE */
  92. HEV hevSlipMonitor = 0,
  93.     hevSlipPause = 0,
  94.     hevSlipPaused = 0,
  95.     hevSlipContinue = 0;
  96. HPIPE hpipeSlip = 0 ;
  97.  
  98. PSZ
  99. SlipCfgFile( void )
  100. {
  101.     static PSZ slipcfgfile = 0 ;       /* Config file name */
  102.     char * etc ;
  103.  
  104.     if ( slipcfgfile )
  105.         return slipcfgfile ;
  106.  
  107.     if ( ( etc = getenv( "ETC" ) ) == NULL ) {
  108.         slipcfgfile = "" ;
  109.         return slipcfgfile ;
  110.         }
  111.  
  112.     slipcfgfile = malloc( strlen( etc ) + 10 ) ;
  113.     strcpy( slipcfgfile, etc ) ;
  114.     strcat( slipcfgfile, "\\slip.cfg" ) ;
  115.     return slipcfgfile ;
  116. }
  117.  
  118. PSZ
  119. PPPCfgFile( void )
  120. {
  121.     static PSZ pppcfgfile = 0 ;       /* Config file name */
  122.     char * etc ;
  123.  
  124.     if ( pppcfgfile )
  125.         return pppcfgfile ;
  126.  
  127.     if ( ( etc = getenv( "ETC" ) ) == NULL ) {
  128.         pppcfgfile = "" ;
  129.         return pppcfgfile ;
  130.         }
  131.  
  132.     pppcfgfile = malloc( strlen( etc ) + 10 ) ;
  133.     strcpy( pppcfgfile, etc ) ;
  134.     strcat( pppcfgfile, "\\ppp.cfg" ) ;
  135.     return pppcfgfile ;
  136. }
  137.  
  138. APIRET
  139. SlipOpen( char * device )
  140. {
  141.     APIRET rc ;
  142.     ULONG action, actual ;
  143.     char  interface[4] ;
  144.     slcPS_INTERFACE pInterfaces = 0,
  145.         pInterface              = 0 ; /* Ptr to S_INTERFACE structure */
  146.  
  147.     if ( rc = slcParseConfiguration ( SlipCfgFile(), &pInterfaces ) ) {
  148.         printf("Unable to parse %s\n",SlipCfgFile() );
  149.         return rc ;
  150.         }
  151.  
  152.     /* Find the proper interface to use */
  153.     interface[0] = '\0' ;
  154.     pInterface = pInterfaces ;
  155.     do
  156.         {
  157.         if ( !strcmp( strlwr(pInterface->device), device ) ) {
  158.             strcpy( interface, pInterface->if_name ) ;
  159.             break;
  160.             }
  161.         pInterface = pInterface->next ;
  162.         }
  163.     while ( pInterface != NULL );
  164.  
  165.     if ( interface[0] == '\0' ) {
  166.         printf("%s is not listed in %s\n",device,SlipCfgFile());
  167.         slcFreeConfiguration( &pInterfaces ) ;
  168.         return 1 ;
  169.         }
  170.  
  171.     if (!(rc = DosOpenEventSem( "\\sem32\\slip\\monitor",
  172.         &hevSlipMonitor )))
  173.         if(!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\pause",
  174.             &hevSlipPause )))
  175.             if(!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\paused",
  176.                 &hevSlipPaused)))
  177.                 if (!(rc = DosOpenEventSem( "\\sem32\\slip\\com\\continue",
  178.                     &hevSlipContinue)))
  179.                     rc = DosOpen( "\\pipe\\slip", &hpipeSlip, &action, 0,
  180.                         FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
  181.                         OPEN_SHARE_DENYNONE, NULL ) ;
  182.  
  183.     if ( !rc ) {
  184.         int PauseCount = 0 ;
  185.         DosWrite( hpipeSlip, interface, 4, &actual ) ;
  186.         do {
  187.             if (PauseCount)
  188.                 msleep(500);
  189.             PauseCount++ ;
  190.             rc = DosPostEventSem( hevSlipPause ) ;
  191.         } while ( PauseCount <= 10 && rc == ERROR_ALREADY_POSTED ) ;
  192.  
  193.         if (!rc)
  194.             rc =DosWaitEventSem( hevSlipPaused, SEM_INDEFINITE_WAIT ) ;
  195.         }
  196.  
  197.     slcFreeConfiguration( &pInterfaces ) ;
  198.     return rc ;
  199. }
  200.  
  201. APIRET
  202. PPPOpen( char * device )
  203. {
  204.     extern int ttppp;
  205.     APIRET rc ;
  206.     ULONG action, actual ;
  207.     UCHAR MonitorSem[32] ;
  208.     UCHAR PauseSem[32];
  209.     UCHAR PausedSem[32];
  210.     UCHAR ContinueSem[32];
  211.     char  interface[8] ;
  212.     slcPS_INTERFACE pInterfaces = 0,
  213.         pInterface              = 0 ; /* Ptr to S_INTERFACE structure */
  214.  
  215.     sprintf(interface, "ppp%d", ttppp-1 );
  216.  
  217.     /* Create the Sem strings to use */
  218.     sprintf(MonitorSem, "\\sem32\\ppp%d\\monitor", ttppp-1);
  219.     sprintf(PauseSem, "\\sem32\\ppp%d\\pause", ttppp-1);
  220.     sprintf(PausedSem, "\\sem32\\ppp%d\\paused", ttppp-1);
  221.     sprintf(ContinueSem, "\\sem32\\ppp%d\\continue", ttppp-1);
  222.  
  223.     /* Find the proper interface to use */
  224.     if (!(rc = DosOpenEventSem( MonitorSem, &hevSlipMonitor )))
  225.         if(!(rc = DosOpenEventSem( PauseSem, &hevSlipPause )))
  226.             if(!(rc = DosOpenEventSem( PausedSem, &hevSlipPaused)))
  227.                 if (!(rc = DosOpenEventSem( ContinueSem, &hevSlipContinue)))
  228.                     rc = DosOpen( "\\pipe\\ppp", &hpipeSlip, &action, 0,
  229.                         FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
  230.                         OPEN_SHARE_DENYNONE, NULL ) ;
  231.  
  232.     if ( !rc ) {
  233.         int PauseCount = 0 ;
  234.         DosWrite( hpipeSlip, interface, 4, &actual ) ;
  235.         do {
  236.             if (PauseCount)
  237.                 msleep(500);
  238.             PauseCount++ ;
  239.             rc = DosPostEventSem( hevSlipPause ) ;
  240.         } while ( PauseCount <= 10 && rc == ERROR_ALREADY_POSTED ) ;
  241.  
  242.         if (!rc)
  243.             rc =DosWaitEventSem( hevSlipPaused, SEM_INDEFINITE_WAIT ) ;
  244.         }
  245.     return rc ;
  246. }
  247.  
  248. void
  249. PPPSlipClose( void )
  250. {
  251.    if ( hevSlipMonitor )
  252.       {
  253.         DosPostEventSem( hevSlipContinue ) ;   /* give the port back */
  254.                                                /* to the slip driver */
  255.         DosCloseEventSem( hevSlipContinue ) ;
  256.         DosCloseEventSem( hevSlipPaused ) ;
  257.         DosCloseEventSem( hevSlipPause ) ;
  258.         DosCloseEventSem( hevSlipMonitor ) ;
  259.         hevSlipMonitor = 0 ;
  260.         hevSlipPaused = 0 ;
  261.         hevSlipPause = 0 ;
  262.         hevSlipContinue = 0 ;
  263.       }
  264.  
  265.     if ( hpipeSlip ) {
  266.         DosClose( hpipeSlip ) ;
  267.         hpipeSlip = 0 ;
  268.         }
  269.  
  270. }
  271.  
  272.  
  273. /*==========================================================================*/
  274. /*                                                                          */
  275. /*            --------------------------------------------------            */
  276. /*                                                                          */
  277. /*                          PRIVATE DATA/FUNCTIONS                          */
  278. /*                                                                          */
  279. /*            --------------------------------------------------            */
  280. /*                                                                          */
  281. /*==========================================================================*/
  282.  
  283. /*--------------------------------------------------------------------------*/
  284. /* Macro/Constant definitions                                               */
  285. /*--------------------------------------------------------------------------*/
  286. #define _slcC_BUFSIZE     512   /* Maximum "chunks" used for config file    */
  287. #define _slcC_ERRSIZE     256   /* Maximum size for a single error message  */
  288. #define _slcC_TOKSIZE      64   /* Maximum size for "tokens" in config file */
  289.  
  290. #define _slcC_TOKEN_NONE    0   /* Token types */
  291. #define _slcC_TOKEN_TOOLONG 1
  292. #define _slcC_TOKEN_ERROR   1   /* < this indicates an error token */
  293.  
  294. #define _slcC_TOKEN_EOF     10  /* Success tokens */
  295. #define _slcC_TOKEN_TEXT    11
  296. #define _slcC_TOKEN_EQUAL   12
  297. #define _slcC_TOKEN_LBRACE  13
  298. #define _slcC_TOKEN_RBRACE  14
  299.  
  300. #define _slcC_TOKENTBL_TERM 1000  /* Must be > max entries in any table */
  301.  
  302. /*--------------------------------------------------------------------------*/
  303. /* Structure declarations                                                   */
  304. /*--------------------------------------------------------------------------*/
  305. typedef struct _slcS_TOKEN_ {
  306.    int type, length;              /* Type of token and text length         */
  307.    char text[_slcC_TOKSIZE+1];    /* Remember room for terminating NULL    */
  308. } _slcS_TOKEN, *_slcPS_TOKEN;
  309.  
  310. typedef struct _slcS_TOKENTBL_ {  /* Map of text tokens to cmd/parm values */
  311.    int  command;                  /* Really an _slcE* type                 */
  312.    char *name;                    /* Actual text of the cmd/element/value  */
  313.    int  valuetype,                /* For parms, >0 means need value.  1 is */
  314.         minimum, maximum;         /*   string, 2=number what range is ok   */
  315. } _slcS_TOKENTBL, *_slcPS_TOKENTBL;
  316.  
  317.  
  318. /*--------------------------------------------------------------------------*/
  319. /* Declarations for commands/elements and values allowed within the         */
  320. /* configuration file.                                                      */
  321. /*--------------------------------------------------------------------------*/
  322.  
  323. /*--------------------------------------------------*/
  324. /*          Configuration file commands             */
  325. /*--------------------------------------------------*/
  326. #define _slcA_CMD_INTERFACE     "interface"
  327.  
  328. typedef enum {cmd_interface} _slcE_CMD;
  329.  
  330. /*--------------------------------------------------*/
  331. /*          "Interface" command parameters          */
  332. /*--------------------------------------------------*/
  333. #define _slcA_INTF_DEVICE         "device"
  334. #define _slcA_INTF_MTU            "mtu"
  335. #define _slcA_INTF_RTT            "rtt"
  336. #define _slcA_INTF_RTTVAR         "rttvar"
  337. #define _slcA_INTF_RTTMIN         "rttmin"
  338. #define _slcA_INTF_SENDPIPE       "sendpipe"
  339. #define _slcA_INTF_RECVPIPE       "recvpipe"
  340. #define _slcA_INTF_SSTHRESH       "ssthresh"
  341. #define _slcA_INTF_QUEUESIZE      "queuesize"
  342. #define _slcA_INTF_FASTQUEUESIZE  "fastqueuesize"
  343. #define _slcA_INTF_FASTQUEUE      "fastqueue"
  344. #define _slcA_INTF_NOFASTQUEUE    "nofastqueue"
  345. #define _slcA_INTF_COMPRESSION    "compression"
  346. #define _slcA_INTF_ATTACHCMD      "attachcmd"
  347. #define _slcA_INTF_ATTACHPARMS    "attachparms"
  348.  
  349. typedef enum {intf_device, intf_mtu, intf_rtt, intf_rttvar, intf_rttmin,
  350.               intf_sendpipe, intf_recvpipe, intf_ssthresh,
  351.               intf_queuesize, intf_fastqueuesize, intf_fastqueue,
  352.               intf_nofastqueue, intf_compression, intf_attachcmd,
  353.               intf_attachparms} _slcE_INTF;
  354.  
  355.  
  356. /*--------------------------------------------------------------------------*/
  357. /* Module-global data                                                       */
  358. /*--------------------------------------------------------------------------*/
  359.  
  360. /*--------------------------------------------------*/
  361. /*                Token error table                 */
  362. /*--------------------------------------------------*/
  363. char *_slc_TokenErrorTable[] = {   /* WARNING: Keep in same order as codes */
  364.    "No token", "Token too long" };
  365.  
  366.  
  367. /*--------------------------------------------------*/
  368. /*      Token tables for commands/parameters        */
  369. /*--------------------------------------------------*/
  370. _slcS_TOKENTBL _slc_CmdTable[] = {
  371.    {cmd_interface,       _slcA_CMD_INTERFACE,0},
  372.    {_slcC_TOKENTBL_TERM, "",0} };
  373.  
  374. _slcS_TOKENTBL _slc_IntfTable[] = {
  375.    {intf_device,        _slcA_INTF_DEVICE,1},
  376.    {intf_mtu,           _slcA_INTF_MTU,2,64,2048},
  377.    {intf_rtt,           _slcA_INTF_RTT,2,0,65536},
  378.    {intf_rttvar,        _slcA_INTF_RTTVAR,2,0,65536},
  379.    {intf_rttmin,        _slcA_INTF_RTTMIN,3,0,65536},
  380.    {intf_sendpipe,      _slcA_INTF_SENDPIPE,2,0,65536},
  381.    {intf_recvpipe,      _slcA_INTF_RECVPIPE,2,0,65536},
  382.    {intf_ssthresh,      _slcA_INTF_SSTHRESH,2,0,65536},
  383.    {intf_queuesize,     _slcA_INTF_QUEUESIZE,2,4,52},
  384.    {intf_fastqueuesize, _slcA_INTF_FASTQUEUESIZE,2,4,52},
  385.    {intf_fastqueue,     _slcA_INTF_FASTQUEUE,0},
  386.    {intf_nofastqueue,   _slcA_INTF_NOFASTQUEUE,0},
  387.    {intf_compression,   _slcA_INTF_COMPRESSION,1},
  388.    {intf_attachcmd,     _slcA_INTF_ATTACHCMD,1},
  389.    {intf_attachparms,   _slcA_INTF_ATTACHPARMS,1},
  390.    {_slcC_TOKENTBL_TERM,""} };
  391.  
  392.  
  393. /*--------------------------------------------------------------------------*/
  394. /*     int _slcGetCh (FILE *RuleFile; int SkipWS, MergeWS, *Line, *Pos)     */
  395. /*..........................................................................*/
  396. /*                                                                          */
  397. /* Retrieves the next "character" from the rule file, fetching new lines    */
  398. /* from the file as necessary.  If MergeWS is 1, then any whitespace (tabs, */
  399. /* spaces or newlines) is always returned as a space.  If SkipWS is 1, then */
  400. /* any grouping of whitespace is returned as a single space character (or   */
  401. /* whatever WS character is first in the group if MergeWS is 0).            */
  402. /*                                                                          */
  403. /* Comments are set via the # character and can appear anywhere within a    */
  404. /* line.  Any text following the # will be ignored.                         */
  405. /*                                                                          */
  406. /* Parsing state information is returned in one or both of the Line and Pos */
  407. /* parameters (if they are non-NULL).  Line represents the line number in   */
  408. /* the file and Pos the position within the line (both origin 1) of the     */
  409. /* character being returned by this function.                               */
  410. /*                                                                          */
  411. /* The function returns EOF when end of file is reached.                    */
  412. /*                                                                          */
  413. /* To avoid having to export parsing state information from this function,  */
  414. /* a special calling convention of RuleFile==NULL is used in order to       */
  415. /* initializing the internal buffer and counters for a new file.            */
  416. /*                                                                          */
  417. /*--------------------------------------------------------------------------*/
  418. int _slcGetCh (FILE *RuleFile, int SkipWS, int MergeWS,
  419.                int *Line, int *Pos)
  420. {
  421.    static char buffer[_slcC_BUFSIZE], *curch;
  422.    static int full_line,        /* Does buffer represent a full line    */
  423.               in_comment,       /* Current buffer holds partial comment */
  424.               curline,          /* Current line/position information    */
  425.               curpos;
  426.  
  427.    int done, result;
  428.    char *ch;
  429.  
  430.    /* Special argument of RuleFile==NULL means initialize */
  431.    if (RuleFile == NULL) {
  432.       curline   = curpos = in_comment = 0;
  433.       buffer[0] = '\0';
  434.       curch     = buffer;
  435.       full_line = 0;
  436.       return(0);
  437.    }
  438.  
  439.    /* Run until we have a suitable character to return */
  440.    done   = 0;
  441.    result = EOF;
  442.    while (!done) {
  443.       /*--------------------------------------------------*/
  444.       /* 1. If we need a new line from the file go get it */
  445.       /*--------------------------------------------------*/
  446.       if (*curch == '\0') {
  447.          buffer[_slcC_BUFSIZE-2] = '\0';        /* For quick full_line check */
  448.          /* For now a read error and EOF are both returned as EOF, */
  449.          /* so I just check for NULL and don't bother with feof()  */
  450.          if (fgets(buffer,_slcC_BUFSIZE,RuleFile) == NULL) {
  451.             result = EOF;
  452.             break;      /* EOF - get out of here */
  453.          } else {
  454.             /* Reset current character pointer */
  455.             curch = buffer;
  456.             /* If last line was full, bump linecount, and init pos count */
  457.             if (full_line) {
  458.                curline++;
  459.                curpos = 0;
  460.             }
  461.             /* Then decide if we got a whole line this time.  By checking */
  462.             /* the next to last character (initialized above), we avoid   */
  463.             /* the need to call strlen for each line read.                */
  464.             full_line = (buffer[_slcC_BUFSIZE-2] == '\0' ||
  465.                          buffer[_slcC_BUFSIZE-2] == '\n');
  466.             /* Early-out.  If already in comment (true if a line with # is */
  467.             /* >_slcC_BUFSIZE characters), just ignore this line entirely, */
  468.             /* resetting in_comment only if we got all of rest of line.    */
  469.             if (in_comment) {
  470.                if (full_line) in_comment = 0;
  471.                /* Nullify line - don't worry about WS - the leading # on */
  472.                /* this comment would already have been treated as a ' '. */
  473.                buffer[0] = '\0';
  474.             } else {
  475.                /* Otherwise, check for \n or #.  If found, convert to space */
  476.                /* and terminate the string at that point.  We need a space  */
  477.                /* to insure parsing "aa\n\nbb" separates "aa" and "bb".     */
  478.                ch = buffer;
  479.                while (*ch) {
  480.                   if (*ch == '#' || *ch == '\n') {
  481.                      /* Might need to set flag for long comments */
  482.                      if (*ch == '#' && !full_line) in_comment = 1;
  483.                      *ch++ = ' ';
  484.                      *ch = '\0';
  485.                      break;
  486.                   } else {
  487.                      ch++;
  488.                   }
  489.                }
  490.             } /* \n and # scan */
  491.          } /* if got good line */
  492.  
  493.          continue;      /* back and keep trying */
  494.       }
  495.  
  496.       /*--------------------------------------------------*/
  497.       /* 2. Now we have a null terminated buffer.  If on  */
  498.       /*    WS find first non-WS, otherwise bump curch    */
  499.       /*    by 1.  Then if SkipWS always return non-WS,   */
  500.       /*    otherwise return space if we started on a WS. */
  501.       /*    Note that we only set result if it isn't set  */
  502.       /*    already since this may run several times in   */
  503.       /*    order to skip over lines of whitespace.       */
  504.       /*--------------------------------------------------*/
  505.       if (result == EOF) {
  506.          result = *curch;
  507.          if (MergeWS && isspace(result)) result = ' ';
  508.          /* If caller wants, store line/position information for this char */
  509.          /* (remembering that we are origin 0, but returning origin 1)     */
  510.          if (Line != NULL) *Line = curline+1;
  511.          if (Pos  != NULL) *Pos  = curpos+1;
  512.       }
  513.       if (isspace(result) && SkipWS) {
  514.          /* Find first non-WS */
  515.          while (*curch && isspace(*curch)) {
  516.             /* Account for tabs here - assume standard expansion of 8 */
  517.             if (*curch == '\t') {
  518.                curpos = ((curpos / 8)+1) * 8;
  519.             } else {
  520.                curpos++;
  521.             }
  522.             curch++;
  523.          }
  524.          done = (*curch);       /* We're only done if we didn't run out */
  525.       } else {
  526.          curch++;
  527.          curpos++;
  528.          done = 1;
  529.       }
  530.    } /* while !done */
  531.  
  532.    return(result);
  533. }
  534.  
  535.  
  536. /*--------------------------------------------------------------------------*/
  537. /*  int _slcGetToken (FILE *RuleFile; _slcPS_TOKEN Token; int *Line, *Pos)  */
  538. /*..........................................................................*/
  539. /*                                                                          */
  540. /* Grabs the next "token" from the specified file, identifies it, and       */
  541. /* returns it in the supplied token structure.  The maximum number of       */
  542. /* characters in a token cannot exceed _slcC_TOKSIZE.                       */
  543. /*                                                                          */
  544. /* The rules for breaking apart tokens is pretty simple.  The following     */
  545. /* characters are treated specially:                                        */
  546. /*      WS | ,  Separates tokens                                            */
  547. /*      =       Special token - separates a rule element from its value.    */
  548. /*      {       Special token - begins a list of rule elements.             */
  549. /*      }       Special token - terminates a list of rule elements.         */
  550. /* The text that created the special tokens is still stored in Token.text.  */
  551. /*                                                                          */
  552. /* Any of these characters may be quoted with the use of the \ character    */
  553. /* (\\ for \ itself), or may be enclosed within double quotes (") to quote  */
  554. /* an entire string.  Note that the \ character is processed even inside    */
  555. /* quotes, so it must be doubled to yield itself or can also be used to     */
  556. /* quote a quote, so to speak.                                              */
  557. /*                                                                          */
  558. /* If either of the Line or Pos parameters is non-NULL, then the file line  */
  559. /* and character position of the start of the returned token are stored in  */
  560. /* the address(es) they point to.                                           */
  561. /*                                                                          */
  562. /*--------------------------------------------------------------------------*/
  563. #define _slc_ADDCHAR(token,ch)  if (chcount<_slcC_TOKSIZE) { \
  564.                                    token->text[chcount++] = ch; \
  565.                                    line = pos = NULL; \
  566.                                 } else { \
  567.                                    token->type = _slcC_TOKEN_TOOLONG; \
  568.                                    break; \
  569.                                 }
  570.  
  571. int _slcGetToken (FILE *RuleFile, _slcPS_TOKEN Token, int *Line, int *Pos)
  572. {
  573.    static int lastch=EOF;
  574.    char *curch;
  575.    int ch, chcount=0, intoken=1, skipws=1, inbslash=0, inquote=0;
  576.    int *line, *pos;
  577.  
  578.    curch = Token->text;
  579.    line  = Line;
  580.    pos   = Pos;
  581.    while (intoken) {
  582.       if (lastch != EOF) {
  583.          ch = lastch;
  584.          lastch = EOF;
  585.       } else {
  586.          ch = _slcGetCh(RuleFile,skipws,skipws,line,pos);
  587.       }
  588.  
  589.       /* Handle special quoting stuff first */
  590.       if (inbslash) {           /* \ always quotes next character, even \   */
  591.          /* NEED EOF CHECK */
  592.          _slc_ADDCHAR(Token,ch);
  593.          inbslash = 0;
  594.          skipws = !inquote;
  595.          continue;
  596.       }
  597.       if (ch == '\\') {         /* Prepare to quote next character          */
  598.          inbslash = 1;
  599.          skipws   = 0;
  600.          continue;
  601.       }
  602.       if (inquote) {            /* Unless terminating ", just add next char */
  603.          /* NEED EOF CHECK */
  604.          if (ch == '"') {
  605.             inquote = 0;
  606.             skipws  = 1;
  607.          } else {
  608.             _slc_ADDCHAR(Token,ch);
  609.          }
  610.          continue;
  611.       }
  612.  
  613.       /* Then normal character processing */
  614.       switch (ch) {
  615.          case EOF:      /* We've hit end of input file */
  616.             if (chcount > 0) {
  617.                Token->type = _slcC_TOKEN_TEXT;
  618.                lastch = ch;     /* this avoids calling GetCh again */
  619.             } else {
  620.                Token->type = _slcC_TOKEN_EOF;
  621.             }
  622.             intoken = 0;
  623.             break;
  624.          case ' ':      /* Whitespace */
  625.          case ',':      /* Or comma   */
  626.             if (chcount > 0) {
  627.                Token->type = _slcC_TOKEN_TEXT;
  628.                intoken = 0;
  629.             }
  630.             break;
  631.          case '"':      /* Start quoting */
  632.             inquote = 1;
  633.             skipws  = 0;
  634.             break;
  635.          case '{':      /* Start of rule elements */
  636.             if (chcount > 0) {
  637.                Token->type = _slcC_TOKEN_TEXT;
  638.                lastch = ch;
  639.             } else {
  640.                Token->type = _slcC_TOKEN_LBRACE;
  641.                Token->text[0] = ch;
  642.                chcount++;
  643.             }
  644.             intoken = 0;
  645.             break;
  646.          case '}':      /* End of rule elements */
  647.             if (chcount > 0) {
  648.                Token->type = _slcC_TOKEN_TEXT;
  649.                lastch = ch;
  650.             } else {
  651.                Token->type = _slcC_TOKEN_RBRACE;
  652.                Token->text[0] = ch;
  653.                chcount++;
  654.             }
  655.             intoken = 0;
  656.             break;
  657.          case '=':      /* Rule element/value separator */
  658.             if (chcount > 0) {
  659.                Token->type = _slcC_TOKEN_TEXT;
  660.                lastch = ch;
  661.             } else {
  662.                Token->type = _slcC_TOKEN_EQUAL;
  663.                Token->text[0] = ch;
  664.                chcount++;
  665.             }
  666.             intoken = 0;
  667.             break;
  668.          default:       /* Normal character for token */
  669.             _slc_ADDCHAR(Token,ch);
  670.             break;
  671.       } /* switch (ch) */
  672.    } /* while in token */
  673.  
  674.    /* Terminate any stuff put into the text field */
  675.    Token->length        = chcount;
  676.    Token->text[chcount] = '\0';
  677.  
  678.    return(0);
  679. }
  680.  
  681.  
  682. /*--------------------------------------------------------------------------*/
  683. /*   int _slcMatchToken (_slcPS_TOKEN Token; _slcS_TOKENTBL TokenTable[])   */
  684. /*..........................................................................*/
  685. /*                                                                          */
  686. /* Function to attempt to locate the supplied text token in the token table */
  687. /* supplied by the TokenTable parameter.  If a match is found, the index    */
  688. /* of the token table entry is returned (0-n), otherwise -1.                */
  689. /*                                                                          */
  690. /* (Note - this needs to be improved in the future to accept any number of  */
  691. /*  token table parameters - and probably return a pointer to the correct   */
  692. /*  entry rather than an index into the table)                              */
  693. /*                                                                          */
  694. /*--------------------------------------------------------------------------*/
  695. int _slcMatchToken (_slcPS_TOKEN Token, _slcS_TOKENTBL TokenTable[])
  696. {
  697.    char tokentext[_slcC_TOKSIZE+1], *src, *dest;
  698.    int index;
  699.  
  700.    /* Copy over token text, lowercasing it for simpler comparison */
  701.    dest = tokentext;
  702.    src  = Token->text;
  703.    while (*dest++ = tolower(*src++))
  704.       ;
  705.  
  706.    /* Now run through table for comparision */
  707.    index = 0;
  708.    while (TokenTable[index].command != _slcC_TOKENTBL_TERM) {
  709.       if (strcmp(TokenTable[index].name,tokentext) == 0) break;
  710.       index++;
  711.    }
  712.    if (TokenTable[index].command == _slcC_TOKENTBL_TERM) index = -1;
  713.  
  714.    return(index);
  715. }
  716.  
  717.  
  718. /*--------------------------------------------------------------------------*/
  719. /*          int _slcErrorMessage (char *Filename; int Line, Pos;            */
  720. /*                                char *MsgFormat, ...)                     */
  721. /*..........................................................................*/
  722. /*                                                                          */
  723. /* Routine for displaying an error message for the specified Filename,      */
  724. /* using the same semantics as printf.  If the supplied Line/Pos parameters */
  725. /* are >0, they are used automatically as a standard preface to the error   */
  726. /* message.                                                                 */
  727. /*                                                                          */
  728. /* Since this function actually processes the output string, the maximum    */
  729. /* size of the resulting message is _slcC_ERRSIZE characters.               */
  730. /*                                                                          */
  731. /* (Right now this goes to stderr)                                          */
  732. /*                                                                          */
  733. /*--------------------------------------------------------------------------*/
  734. int _slcErrorMessage (char *Filename, int Line, int Pos,
  735.                       char *MsgFormat, ...)
  736. {
  737.    char errmsg[_slcC_ERRSIZE], syslogmsg[_slcC_ERRSIZE];
  738.    va_list args;
  739.  
  740.    sprintf(errmsg,"SL-Config: Error Parsing File \"%s\"",Filename);
  741.    if (Line > 0 || Pos > 0) {
  742.       strcat(errmsg," (");
  743.    }
  744.    if (Line > 0) {
  745.       sprintf(&errmsg[strlen(errmsg)],"Line=%d",Line);
  746.    }
  747.    if (Line > 0 && Pos > 0) {
  748.       strcat(errmsg,", ");
  749.    }
  750.    if (Pos > 0) {
  751.       sprintf(&errmsg[strlen(errmsg)],"Position=%d",Pos);
  752.    }
  753.    if (Line > 0 || Pos > 0) {
  754.       strcat(errmsg,")");
  755.    }
  756.    fprintf(stderr,"%s\n",errmsg);
  757.    va_start(args,MsgFormat);
  758.    vsprintf(errmsg,MsgFormat,args);
  759.    fprintf(stderr,"SL-Config: %s\n",errmsg);
  760.     return(0);
  761. }
  762.  
  763.  
  764. /*--------------------------------------------------------------------------*/
  765. /*      int _slcSetIntfParm (slcPS_INTERFACE Interface,                     */
  766. /*                           _slcPS_TOKENTBL Parameter,                     */
  767. /*                           _slcPS_TOKEN Value)                            */
  768. /*..........................................................................*/
  769. /*                                                                          */
  770. /*                                                                          */
  771. /*--------------------------------------------------------------------------*/
  772. int _slcSetIntfParm (slcPS_INTERFACE Interface, _slcPS_TOKENTBL Parameter,
  773.                      _slcPS_TOKEN Value)
  774. {
  775.    int result = 0, index, value;
  776.  
  777.    switch (Parameter->valuetype) {
  778.       case 0:
  779.          /* No value arguments - just set appropriate flags */
  780.          switch (Parameter->command) {
  781.             case intf_nofastqueue:
  782.                Interface->allowfastq = 0;
  783.                break;
  784.             case intf_fastqueue:
  785.                Interface->allowfastq = 1;
  786.                break;
  787.             default:
  788.                /* Should never happen */
  789.                result = 4;
  790.                break;
  791.          }
  792.          break;
  793.  
  794.       case 1:
  795.          /* String parameter */
  796.          switch (Parameter->command) {
  797.             case intf_device:
  798.                if (Interface->device) {
  799.                   free(Interface->device);
  800.                }
  801.                Interface->device = strdup(Value->text);
  802.                if (Interface->device == NULL) {
  803.                   result = 3;
  804.                }
  805.                break;
  806.             case intf_compression:
  807.                if (!stricmp("on",Value->text)) {
  808.                   Interface->compression = slc_COMPRESSION;
  809.                   if (Interface->if_mtu == 0) {
  810.                      /* Set mtu (since not set already) to smaller chunks */
  811.                      Interface->if_mtu = 296;
  812.                   }
  813.                } else if (!stricmp("off",Value->text)) {
  814.                   Interface->compression = slc_NOCOMPRESSION;
  815.                } else if (!stricmp("auto",Value->text)) {
  816.                   Interface->compression = slc_AUTOCOMPRESSION;
  817.                } else {
  818.                   result = 1;
  819.                }
  820.                break;
  821.             case intf_attachcmd:
  822.                if (Interface->attachcmd) {
  823.                   free(Interface->attachcmd);
  824.                }
  825.                Interface->attachcmd = strdup(Value->text);
  826.                if (Interface->attachcmd == NULL) {
  827.                   result = 3;
  828.                }
  829.                break;
  830.             case intf_attachparms:
  831.                if (Interface->attachparms) {
  832.                   free(Interface->attachparms);
  833.                }
  834.                Interface->attachparms = strdup(Value->text);
  835.                if (Interface->attachparms == NULL) {
  836.                   result = 3;
  837.                }
  838.                break;
  839.          }
  840.          break;
  841.  
  842.       case 2:
  843.          /* Numeric argument with valid range */
  844.          for (index=0; index < Value->length && !result; index++) {
  845.             if (!isdigit(Value->text[index])) {
  846.                result = 1;
  847.             }
  848.          }
  849.          if (result)
  850.             break;
  851.          value = atoi(Value->text);
  852.          if (value < Parameter->minimum || value > Parameter->maximum) {
  853.             result = 2;
  854.          }
  855.          if (result)
  856.             break;
  857.          /* Store resulting value into interface structure */
  858.          switch (Parameter->command) {
  859.             case intf_mtu:
  860.                Interface->if_mtu = value;
  861.                break;
  862.             case intf_rtt:
  863.                Interface->if_rtt = value;
  864.                break;
  865.             case intf_rttvar:
  866.                Interface->if_rttvar = value;
  867.                break;
  868.             case intf_rttmin:
  869.                Interface->if_rttmin = value;
  870.                break;
  871.             case intf_sendpipe:
  872.                Interface->if_sendpipe = value;
  873.                break;
  874.             case intf_recvpipe:
  875.                Interface->if_recvpipe = value;
  876.                break;
  877.             case intf_ssthresh:
  878.                Interface->if_ssthresh = value;
  879.                break;
  880.             case intf_queuesize:
  881.                Interface->if_maxqueue = value;
  882.                break;
  883.             case intf_fastqueuesize:
  884.                Interface->if_maxfastq = value;
  885.                break;
  886.             default:
  887.                /* Should never happen */
  888.                result = 4;
  889.                break;
  890.          }
  891.    }
  892.  
  893.    return(result);
  894. }
  895.  
  896.  
  897.  
  898. /*==========================================================================*/
  899. /*                                                                          */
  900. /*            --------------------------------------------------            */
  901. /*                                                                          */
  902. /*                             PUBLIC FUNCTIONS                             */
  903. /*                                                                          */
  904. /*            --------------------------------------------------            */
  905. /*                                                                          */
  906. /*==========================================================================*/
  907.  
  908.  
  909.  
  910. /*--------------------------------------------------------------------------*/
  911. /* int slcParseConfiguration (char *Filename; slcPS_INTERFACE *Interfaces)  */
  912. /*..........................................................................*/
  913. /*                                                                          */
  914. /* Parses a SLIP configuration file, building a linked list of interface    */
  915. /* structures to hold the interface configuration information.              */
  916. /*                                                                          */
  917. /*                                                                          */
  918. /* This function is currently geared to process files of the form:          */
  919. /*                                                                          */
  920. /*      interface sl# | default {                                           */
  921. /*              parameter=value [,] parameter=value [,]  ...                */
  922. /*      }                                                                   */
  923. /*                                                                          */
  924. /*                                                                          */
  925. /*--------------------------------------------------------------------------*/
  926. #define _slc_ERRMSG     _slcErrorMessage
  927. #define _slc_ERRHDR     Filename,line,pos
  928. #define _slc_NEXT_TOKEN _slcGetToken(configfile,&token,&line,&pos)
  929.  
  930. int slcParseConfiguration (char *Filename, slcPS_INTERFACE *Interfaces)
  931. {
  932.    int             result=0;
  933.    _slcS_TOKEN     token;
  934.    slcS_INTERFACE  intf_default;
  935.    slcPS_INTERFACE curinterface, lastinterface=NULL;
  936.    FILE            *configfile;
  937.    int             done=0, allowvalue=0, wantvalue=0, invalue=0,
  938.                    index, line, pos, parameter, rc;
  939.    int             curcommand;
  940.  
  941.  
  942.    /* Clear default structure */
  943.    memset(&intf_default,'\0',sizeof(intf_default));
  944.    /* And then insert fundamental defaults */
  945.    intf_default.if_recvpipe = 4096;
  946.    intf_default.if_maxqueue = 12;
  947.    intf_default.if_maxfastq = 24;
  948.    intf_default.allowfastq  = 1;
  949.    intf_default.compression = slc_NOCOMPRESSION;
  950.  
  951.    if ((configfile = fopen(Filename,"r")) == NULL) {
  952.       result = 1;
  953.    } else {
  954.       /* Make sure any previous parses are flushed */
  955.       _slcGetCh(NULL,0,0,0,0);
  956.  
  957.       /* Main rule processing loop - handle a command at a time */
  958.       while (!done) {
  959.          /* Fetch next token */
  960.          _slc_NEXT_TOKEN;
  961.  
  962.          /* If EOF here, then we're done */
  963.          if (token.type == _slcC_TOKEN_EOF) {
  964.             done = 1;
  965.             break;
  966.          }
  967.  
  968.          /* If not text or text but not in command table, generate error */
  969.          if (token.type != _slcC_TOKEN_TEXT ||
  970.              (index = _slcMatchToken(&token,_slc_CmdTable)) < 0) {
  971.             _slc_ERRMSG(_slc_ERRHDR,"Invalid command encountered - \"%s\"",
  972.                         token.text);
  973.             result = done = 1;
  974.             break;
  975.          }
  976.  
  977.          /* We have an interface command (eventually, this will have to */
  978.          /* handle more than just an interface command.                 */
  979.  
  980.          /* Grab next token - should be "sl#" (#=0-9) or "default" */
  981.          _slc_NEXT_TOKEN;
  982.          if (token.type != _slcC_TOKEN_TEXT) {
  983.             _slc_ERRMSG(_slc_ERRHDR,"Missing interface name");
  984.             result = done = 1;
  985.             break;
  986.          } else {
  987.             if (token.length == 3 &&
  988.                 tolower(token.text[0]) == 's' &&
  989.                 tolower(token.text[1]) == 'l' &&
  990.                 token.text[2] == '0') {   /* currently only 'sl0' allowed */
  991.                /* Normal "sl#" interface - lowercase interface name  */
  992.                /* and then make sure that we haven't already used it */
  993.                strlwr(token.text);
  994.                curinterface = *Interfaces;
  995.                while (curinterface) {
  996.                   if (!strcmp(curinterface->if_name,token.text)) {
  997.                      _slc_ERRMSG(_slc_ERRHDR,"Duplicate interface \"%s\"",
  998.                                  token.text);
  999.                      result = done = 1;
  1000.                      break;
  1001.                   }
  1002.                   curinterface = curinterface->next;
  1003.                }
  1004.                /* Unique - allocate room for new interface */
  1005.                if (lastinterface == NULL) {
  1006.                   lastinterface = (slcPS_INTERFACE)
  1007.                                  calloc(1,sizeof(slcS_INTERFACE));
  1008.                   curinterface = *Interfaces = lastinterface;
  1009.                } else {
  1010.                   lastinterface->next = (slcPS_INTERFACE)
  1011.                                         calloc(1,sizeof(slcS_INTERFACE));
  1012.                   curinterface = lastinterface = lastinterface->next;
  1013.                }
  1014.                if (curinterface == NULL) {
  1015.                   _slc_ERRMSG(_slc_ERRHDR,
  1016.                               "Error allocating space for new interface");
  1017.                   result = done = 1;
  1018.                   break;
  1019.                }
  1020.  
  1021.                /* Copy over default block for initial values */
  1022.                memcpy(curinterface,&intf_default,sizeof(intf_default));
  1023.  
  1024.                /* Update interface name and insert default device name */
  1025.                strcpy(curinterface->if_name,token.text);
  1026.                curinterface->device = malloc(5);
  1027.                strcpy(curinterface->device,"com");
  1028.                curinterface->device[3] = token.text[2]+1;
  1029.                curinterface->device[4] = '\0';
  1030.             } else if (!stricmp(token.text,"default")) {
  1031.                /* Default interface */
  1032.                curinterface = &intf_default;
  1033.             } else {
  1034.                _slc_ERRMSG(_slc_ERRHDR,"Invalid interface \"%s\" "
  1035.                           "(use sl0 or 'default')", token.text);
  1036.                result = done = 1;
  1037.                break;
  1038.             }
  1039.          }
  1040.  
  1041.          /* This is a kludge - TBD: work on control flow in here */
  1042.          if (done) break;
  1043.  
  1044.          /* Process any parameters for this interface - First, make */
  1045.          /* sure that the next parseable element is the brace ({).  */
  1046.          _slc_NEXT_TOKEN;
  1047.          if (token.type != _slcC_TOKEN_LBRACE) {
  1048.             _slc_ERRMSG(_slc_ERRHDR,"Expecting {, read \"%s\"",token.text);
  1049.             result = 1;
  1050.             break;
  1051.          }
  1052.  
  1053.          /* Ok - we're into the elements - go until right brace (EOF=error) */
  1054.          do {
  1055.             _slc_NEXT_TOKEN;
  1056.             switch (token.type) {
  1057.                case _slcC_TOKEN_TEXT:
  1058.                   /* This is either element name or value, according to */
  1059.                   /* wantvalue variable - verify in either case.        */
  1060.                   if (wantvalue) {
  1061.                      if (rc = _slcSetIntfParm(curinterface,
  1062.                                               &_slc_IntfTable[parameter],
  1063.                                               &token)) {
  1064.                         switch (rc) {
  1065.                            case 1:
  1066.                               _slc_ERRMSG(_slc_ERRHDR,
  1067.                                           "Invalid parameter value \"%s\"",
  1068.                                           token.text);
  1069.                               break;
  1070.                            case 2:
  1071.                               _slc_ERRMSG(_slc_ERRHDR,"Parameter value (%s) "
  1072.                                           "out of range (%d-%d)",token.text,
  1073.                                           _slc_IntfTable[parameter].minimum,
  1074.                                           _slc_IntfTable[parameter].maximum);
  1075.                               break;
  1076.                            case 3:
  1077.                               _slc_ERRMSG(_slc_ERRHDR,"Memory allocation "
  1078.                                           "failure while parsing parameter");
  1079.                               break;
  1080.                            case 4:
  1081.                               _slc_ERRMSG(_slc_ERRHDR,"Internal error - "
  1082.                                           "unknown parameter");
  1083.                               break;
  1084.                            default:
  1085.                               _slc_ERRMSG(_slc_ERRHDR,"Internal error - "
  1086.                                           "unknown result (%d) from "
  1087.                                           "_slcSetIntfParm",rc);
  1088.                               break;
  1089.                         }
  1090.                         result = done = 1;
  1091.                      }
  1092.                      invalue = 1;
  1093.                   } else {
  1094.                      if ((parameter = _slcMatchToken(&token,
  1095.                                                      _slc_IntfTable)) < 0) {
  1096.                         _slc_ERRMSG(_slc_ERRHDR,"Invalid parameter \"%s\"",
  1097.                                     token.text);
  1098.                         result = done = 1;
  1099.                      } else {
  1100.                         allowvalue = _slc_IntfTable[parameter].valuetype > 0;
  1101.                         if (!allowvalue) {
  1102.                            _slcSetIntfParm(curinterface,
  1103.                                            &_slc_IntfTable[parameter],NULL);
  1104.                         }
  1105.                      }
  1106.                      invalue = 0;
  1107.                   }
  1108.                   wantvalue = 0;
  1109.                   break;
  1110.                case _slcC_TOKEN_EQUAL:
  1111.                   /* this is only valid if we don't yet want a value */
  1112.                   /* and we're allowed a value.                      */
  1113.                   if (wantvalue) {
  1114.                      _slc_ERRMSG(_slc_ERRHDR,
  1115.                                  "Expecting parameter, read \"%s\"",
  1116.                                  token.text);
  1117.                      result = done = 1;
  1118.                   } else if (!allowvalue) {
  1119.                      _slc_ERRMSG(_slc_ERRHDR,
  1120.                                  "Parameter \"%s\" does not require a value",
  1121.                                  _slc_IntfTable[parameter].name);
  1122.                      result = done = 1;
  1123.                   } else {
  1124.                      wantvalue = 1;
  1125.                   }
  1126.                   break;
  1127.                case _slcC_TOKEN_RBRACE:
  1128.                   /* Error if we are waiting for a value */
  1129.                   if (wantvalue) {
  1130.                      _slc_ERRMSG(_slc_ERRHDR,
  1131.                                  "Expecting parameter value, read \"%s\"",
  1132.                                  token.text);
  1133.                      result = done = 1;
  1134.                   } else {
  1135.                      invalue = 0;
  1136.                   }
  1137.                   break;
  1138.                case _slcC_TOKEN_EOF:
  1139.                   _slc_ERRMSG(_slc_ERRHDR,"Expecting }%s, got End-Of-File",
  1140.                               wantvalue ? "" : " or =");
  1141.                   result = done = 1;
  1142.                   break;
  1143.                default:
  1144.                   if (token.type <= _slcC_TOKEN_ERROR) {
  1145.                      _slc_ERRMSG(_slc_ERRHDR,
  1146.                                  "Tokenize error %d (%s) while reading file.",
  1147.                                  token.type,_slc_TokenErrorTable[token.type]);
  1148.                   } else {
  1149.                      _slc_ERRMSG(_slc_ERRHDR,"Expecting }%s, read \"%s\"",
  1150.                                  wantvalue ? "" : " or =",token.text);
  1151.                   }
  1152.                   result = done = 1;
  1153.                   break;
  1154.             } /* switch token.type */
  1155.          } while (token.type != _slcC_TOKEN_RBRACE && !done);
  1156.  
  1157.          if (curinterface->if_mtu == 0) {
  1158.             curinterface->if_mtu = 1006;  /* Default if not set otherwise */
  1159.          }
  1160.       } /* while !done */
  1161.       fclose(configfile);
  1162.    } /* if file ok */
  1163.  
  1164.    return(result);
  1165. }
  1166.  
  1167.  
  1168. /*--------------------------------------------------------------------------*/
  1169. /*      int slcFreeConfiguration (slcPS_INTERFACE *Interfaces)              */
  1170. /*..........................................................................*/
  1171. /*                                                                          */
  1172. /* Frees up a previously parsed interface configuration.                    */
  1173. /*                                                                          */
  1174. /*--------------------------------------------------------------------------*/
  1175. int slcFreeConfiguration (slcPS_INTERFACE *Interfaces)
  1176. {
  1177.    slcPS_INTERFACE curptr, delptr;
  1178.  
  1179.    curptr = *Interfaces;
  1180.    while (curptr) {
  1181.       if (curptr->device) {
  1182.          free(curptr->device);
  1183.       }
  1184.       delptr = curptr;
  1185.       curptr = curptr->next;
  1186.       free(delptr);
  1187.    }
  1188.    *Interfaces = NULL;
  1189.     return(0);
  1190. }
  1191. #endif /* NT */
  1192.  
  1193.