"Fossies" - the Fresh Open Source Software Archive

Member "sredird-2.2.2/sredird.c" (12 Aug 2005, 61169 Bytes) of package /linux/privat/old/sredird-2.2.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sredird.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2         sredird: RFC 2217 compliant serial port redirector
    3         Version 2.2.1, 20 February 2004
    4         Copyright (C) 1999 - 2003 InfoTecna s.r.l.
    5         Copyright (C) 2001, 2002 Trustees of Columbia University
    6         in the City of New York
    7 
    8         This program is free software; you can redistribute it and/or modify
    9         it under the terms of the GNU General Public License as published by
   10         the Free Software Foundation; either version 2 of the License, or
   11         (at your option) any later version.
   12 
   13         This program is distributed in the hope that it will be useful,
   14         but WITHOUT ANY WARRANTY; without even the implied warranty of
   15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
   16         GNU General Public License for more details.
   17 
   18         You should have received a copy of the GNU General Public License
   19         along with this program; if not, write to the Free Software
   20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   21 
   22         To contact the authors:
   23 
   24             Denis Sbragion
   25             InfoTecna
   26             Tel, Fax: +39 0362 805396
   27             URL: http://www.infotecna.it
   28             E-Mail: d.sbragion@infotecna.it
   29 
   30             Jeffrey Altman
   31             The Kermit Project
   32             Columbia University
   33             URL: http://www.kermit-project.org/
   34             E-mail: jaltman@columbia.edu
   35 
   36         Current design issues:
   37 
   38             . does not properly check implement BREAK handling. Need to figure
   39                 out how to turn a BREAK on and then off based upon receipt of
   40                 COM-PORT Subnegotiations
   41 
   42             . does not properly use select to handle input, output and
   43                 errors on all devices.
   44 
   45             . Lack of login processing
   46 
   47             . Lack of Telnet START_TLS to protect the data stream
   48 
   49             . Lack of Telnet AUTHENTICATION
   50 
   51             . LineState processing is not implemented
   52 
   53             . The code probably won't compile on most versions of Unix due to the
   54                 highly platform dependent nature of the serial apis.
   55 
   56         Fixed in 2.0.0:
   57 
   58             . Telnet DO ECHO should not be refused.  The modem handles the echoing
   59                 if necessary.
   60 
   61             . Cisco IOS returns 0 to the client when INBOUND flow control is SET but
   62                 not supported seperately from OUTBOUND.
   63 
   64             . Track the state of the telnet negotiations
   65 
   66             . Add support for BINARY mode translations
   67 
   68      Fixed in 2.1.0:
   69 
   70             . GetPortFlowControl should return 1 to indicate NO FLOW CONTROL 
   71                 instead of 0.    
   72     
   73             . The Cisco IOS hack should become activated only if set by command-
   74                 line option [-i].
   75             
   76             . Changed the order of checks in the EscWriteChar function for slightly
   77                 better performance
   78 
   79      Fixed in 2.2.0:
   80 
   81             Mario Viara
   82 
   83             Email: mario@viara.info
   84 
   85             . Fixed set port data size now work with 5 6 7 8 bits.
   86             . Add version in get signature.
   87 
   88             Russell Coker <russell@coker.com.au> 
   89 
   90             . Many minor changes and code cleanup
   91             
   92             For other important changes from Russell Coker see the README file.
   93                 
   94 */
   95 
   96 /* Return NoError, which is 0, on success */
   97 
   98 /* Standard library includes */
   99 #include <stdio.h>
  100 #include <stdlib.h>
  101 #include <string.h>
  102 #include <unistd.h>
  103 #include <errno.h>
  104 #include <time.h>
  105 #include <sys/time.h>
  106 #include <sys/times.h>
  107 #include <sys/types.h>
  108 #include <sys/ioctl.h>
  109 #include <signal.h>
  110 #include <fcntl.h>
  111 #include <syslog.h>
  112 #include <termios.h>
  113 #include <termio.h>
  114 #include <sys/socket.h>
  115 #include <netinet/in.h>
  116 #include <netinet/ip.h>
  117 #include <netinet/tcp.h>
  118 
  119 /* Version id */
  120 #define VersionId "2.2.2"
  121 #define SRedirdVersionId "Version " VersionId ", 20 February 2004"
  122 
  123 /* Locking constants */
  124 #define LockOk 0
  125 #define Locked 1
  126 #define LockKo 2
  127 
  128 /* Error conditions constants */
  129 #define NoError 0
  130 #define Error 1
  131 #define OpenError -1
  132 
  133 /* Maximum length of temporary strings */
  134 #define TmpStrLen 512
  135 
  136 /* Buffer size */
  137 #define BufferSize 2048
  138 
  139 /* File mode and file length for HDB (ASCII) stile lock file */
  140 #define LockFileMode 0644
  141 #define HDBHeaderLen 11
  142 
  143 /* Base Telnet protocol constants (STD 8) */
  144 #define TNSE ((unsigned char) 240)
  145 #define TNNOP ((unsigned char) 241)
  146 #define TNSB ((unsigned char) 250)
  147 #define TNWILL ((unsigned char) 251)
  148 #define TNWONT ((unsigned char) 252)
  149 #define TNDO ((unsigned char) 253)
  150 #define TNDONT ((unsigned char) 254)
  151 #define TNIAC ((unsigned char) 255)
  152 
  153 /* Base Telnet protocol options constants (STD 27, STD 28, STD 29) */
  154 #define TN_TRANSMIT_BINARY ((unsigned char) 0)
  155 #define TN_ECHO ((unsigned char) 1)
  156 #define TN_SUPPRESS_GO_AHEAD ((unsigned char) 3)
  157 
  158 /* Base Telnet Com Port Control (CPC) protocol constants (RFC 2217) */
  159 #define TNCOM_PORT_OPTION ((unsigned char) 44)
  160 
  161 /* CPC Client to Access Server constants */
  162 #define TNCAS_SIGNATURE ((unsigned char) 0)
  163 #define TNCAS_SET_BAUDRATE ((unsigned char) 1)
  164 #define TNCAS_SET_DATASIZE ((unsigned char) 2)
  165 #define TNCAS_SET_PARITY ((unsigned char) 3)
  166 #define TNCAS_SET_STOPSIZE ((unsigned char) 4)
  167 #define TNCAS_SET_CONTROL ((unsigned char) 5)
  168 #define TNCAS_NOTIFY_LINESTATE ((unsigned char) 6)
  169 #define TNCAS_NOTIFY_MODEMSTATE ((unsigned char) 7)
  170 #define TNCAS_FLOWCONTROL_SUSPEND ((unsigned char) 8)
  171 #define TNCAS_FLOWCONTROL_RESUME ((unsigned char) 9)
  172 #define TNCAS_SET_LINESTATE_MASK ((unsigned char) 10)
  173 #define TNCAS_SET_MODEMSTATE_MASK ((unsigned char) 11)
  174 #define TNCAS_PURGE_DATA ((unsigned char) 12)
  175 
  176 /* CPC Access Server to Client constants */
  177 #define TNASC_SIGNATURE ((unsigned char) 100)
  178 #define TNASC_SET_BAUDRATE ((unsigned char) 101)
  179 #define TNASC_SET_DATASIZE ((unsigned char) 102)
  180 #define TNASC_SET_PARITY ((unsigned char) 103)
  181 #define TNASC_SET_STOPSIZE ((unsigned char) 104)
  182 #define TNASC_SET_CONTROL ((unsigned char) 105)
  183 #define TNASC_NOTIFY_LINESTATE ((unsigned char) 106)
  184 #define TNASC_NOTIFY_MODEMSTATE ((unsigned char) 107)
  185 #define TNASC_FLOWCONTROL_SUSPEND ((unsigned char) 108)
  186 #define TNASC_FLOWCONTROL_RESUME ((unsigned char) 109)
  187 #define TNASC_SET_LINESTATE_MASK ((unsigned char) 110)
  188 #define TNASC_SET_MODEMSTATE_MASK ((unsigned char) 111)
  189 #define TNASC_PURGE_DATA ((unsigned char) 112)
  190 
  191 /* Modem state effective change mask */
  192 #define ModemStateECMask ((unsigned char) 255)
  193 
  194 #define LineStateECMask ((unsigned char) 255)
  195 
  196 /* Default modem state polling in milliseconds (100 msec should be enough) */
  197 #define ModemStatePolling 100
  198 
  199 /* Standard boolean definition */
  200 typedef enum { False, True } Boolean;
  201 
  202 /* Cisco IOS bug compatibility */
  203 Boolean CiscoIOSCompatible = False;
  204 
  205 /* Buffer structure */
  206 typedef
  207     struct
  208         {
  209             unsigned char Buffer[BufferSize];
  210             unsigned int RdPos;
  211             unsigned int WrPos;
  212         }
  213     BufferType;
  214 
  215 /* Complete lock file pathname */
  216 static char * LockFileName;
  217 
  218 /* Complete device file pathname */
  219 static char * DeviceName;
  220 
  221 /* True when the device has been opened */
  222 Boolean DeviceOpened = False;
  223 
  224 /* Device file descriptor */
  225 int DeviceFd;
  226 
  227 /* Com Port Control enabled flag */
  228 Boolean TCPCEnabled = False;
  229 
  230 /* True after retrieving the initial settings from the serial port */
  231 Boolean InitPortRetrieved = False;
  232 
  233 /* Initial serial port settings */
  234 struct termios InitialPortSettings;
  235 
  236 /* Maximum log level to log in the system log */
  237 static int MaxLogLevel = LOG_DEBUG + 1;
  238 
  239 /* Status enumeration for IAC escaping and interpretation */
  240 typedef enum { IACNormal, IACReceived, IACComReceiving } IACState;
  241 
  242 /* Effective status for IAC escaping and interpretation */
  243 static IACState IACEscape = IACNormal;
  244 
  245 /* Same as above during signature reception */
  246 static IACState IACSigEscape;
  247 
  248 /* Current IAC command begin received */
  249 static unsigned char IACCommand[TmpStrLen];
  250 
  251 /* Position of insertion into IACCommand[] */
  252 static size_t IACPos;
  253 
  254 /* Modem state mask set by the client */
  255 static unsigned char ModemStateMask = ((unsigned char) 255);
  256 
  257 /* Line state mask set by the client */
  258 static unsigned char LineStateMask = ((unsigned char) 0);
  259 
  260 #ifdef COMMENT
  261 /* Current status of the line control lines */
  262 static unsigned char LineState = ((unsigned char) 0);
  263 #endif
  264 
  265 /* Current status of the modem control lines */
  266 static unsigned char ModemState = ((unsigned char) 0);
  267 
  268 /* Break state flag */
  269 Boolean BreakSignaled = False;
  270 
  271 /* Input flow control flag */
  272 Boolean InputFlow = True;
  273 
  274 /* Telnet State Machine */
  275 static
  276     struct _tnstate
  277         {
  278             Boolean sent_will;
  279             Boolean sent_do;
  280             Boolean sent_wont;
  281             Boolean sent_dont;
  282             Boolean is_will;
  283             Boolean is_do;
  284         }
  285     tnstate[256];
  286 
  287 /* Function prototypes */
  288 
  289 /* initialize Telnet State Machine */
  290 void InitTelnetStateMachine(void);
  291 
  292 /* Initialize a buffer for operation */
  293 void InitBuffer(BufferType * B);
  294 
  295 /* Check if the buffer is empty */
  296 Boolean IsBufferEmpty(BufferType * B);
  297 
  298 /* Check if the buffer is full */
  299 Boolean IsBufferFull(BufferType * B);
  300 
  301 /* Add a byte to a buffer */
  302 void AddToBuffer(BufferType * B, unsigned char C);
  303 
  304 /* Get a byte from a buffer */
  305 unsigned char GetFromBuffer(BufferType * B);
  306 
  307 /* Generic log function with log level control. Uses the same log levels
  308 of the syslog(3) system call */
  309 void LogMsg(int LogLevel, const char * const Msg);
  310 
  311 /* Try to lock the file given in LockFile as pid LockPid using the classical
  312 HDB (ASCII) file locking scheme */
  313 int HDBLockFile(char * LockFile, pid_t LockPid);
  314 
  315 /* Remove the lock file created with HDBLockFile */
  316 void HDBUnlockFile(char * LockFile, pid_t LockPid);
  317 
  318 /* Function executed when the program exits */
  319 void ExitFunction(void);
  320 
  321 /* Function called on many signals */
  322 void SignalFunction(int unused);
  323 
  324 /* Function called on break signal */
  325 void BreakFunction(int unused);
  326 
  327 /* Retrieves the port speed from PortFd */
  328 unsigned long int GetPortSpeed(int PortFd);
  329 
  330 /* Retrieves the data size from PortFd */
  331 unsigned char GetPortDataSize(int PortFd);
  332 
  333 /* Retrieves the parity settings from PortFd */
  334 unsigned char GetPortParity(int PortFd);
  335 
  336 /* Retrieves the stop bits size from PortFd */
  337 unsigned char GetPortStopSize(int PortFd);
  338 
  339 /* Retrieves the flow control status, including DTR and RTS status,
  340 from PortFd */
  341 unsigned char GetPortFlowControl(int PortFd, unsigned char Which);
  342 
  343 /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */
  344 unsigned char GetModemState(int PortFd,unsigned char PMState);
  345 
  346 /* Set the serial port data size */
  347 void SetPortDataSize(int PortFd, unsigned char DataSize);
  348 
  349 /* Set the serial port parity */
  350 void SetPortParity(int PortFd, unsigned char Parity);
  351 
  352 /* Set the serial port stop bits size */
  353 void SetPortStopSize(int PortFd, unsigned char StopSize);
  354 
  355 /* Set the port flow control and DTR and RTS status */
  356 void SetPortFlowControl(int PortFd,unsigned char How);
  357 
  358 /* Set the serial port speed */
  359 void SetPortSpeed(int PortFd, unsigned long BaudRate);
  360 
  361 /* Send the signature Sig to the client */
  362 void SendSignature(BufferType * B, char * Sig);
  363 
  364 /* Write a char to SockFd performing IAC escaping */
  365 void EscWriteChar(BufferType * B, unsigned char C);
  366 
  367 /* Redirect char C to PortFd checking for IAC escape sequences */
  368 void EscRedirectChar(BufferType * SockB, BufferType * DevB, int PortFd, unsigned char C);
  369 
  370 /* Send the specific telnet option to SockFd using Command as command */
  371 void SendTelnetOption(BufferType * B, unsigned char Command, char Option);
  372 
  373 /* Send a string to SockFd performing IAC escaping */
  374 void SendStr(BufferType * B, char * Str);
  375 
  376 /* Send the baud rate BR to SockFd */
  377 void SendBaudRate(BufferType * B, unsigned long int BR);
  378 
  379 /* Send the flow control command Command */
  380 void SendCPCFlowCommand(BufferType * B, unsigned char Command);
  381 
  382 /* Send the CPC command Command using Parm as parameter */
  383 void SendCPCByteCommand(BufferType * B, unsigned char Command, unsigned char Parm);
  384 
  385 /* Handling of COM Port Control specific commands */
  386 void HandleCPCCommand(BufferType * B, int PortFd, unsigned char * Command, size_t CSize);
  387 
  388 /* Common telnet IAC commands handling */
  389 void HandleIACCommand(BufferType * B, int PortFd, unsigned char * Command, size_t CSize);
  390 
  391 /* Write a buffer to SockFd with IAC escaping */
  392 void EscWriteBuffer(BufferType * B, unsigned char * Buffer, unsigned int BSize);
  393 
  394 /* initialize Telnet State Machine */
  395 void InitTelnetStateMachine(void)
  396     {
  397         int i;
  398         for (i = 0;i < 256;i++)
  399             {
  400                 tnstate[i].sent_do = False;
  401                 tnstate[i].sent_will = False;
  402                 tnstate[i].sent_wont = False;
  403                 tnstate[i].sent_dont = False;
  404                 tnstate[i].is_do = False;
  405                 tnstate[i].is_will = False;
  406             }
  407     }
  408 
  409 /* Initialize a buffer for operation */
  410 void InitBuffer(BufferType * B)
  411     {
  412         /* Set the initial buffer positions */
  413         B->RdPos = 0;
  414         B->WrPos = 0;
  415     }
  416 
  417 /* Check if the buffer is empty */
  418 Boolean IsBufferEmpty(BufferType * B)
  419     {
  420         return((Boolean) B->RdPos == B->WrPos);
  421     }
  422 
  423 /* Check if the buffer is full */
  424 Boolean IsBufferFull(BufferType * B)
  425     {
  426         /* We consider the buffer to be filled when there are 100 bytes left
  427             This is so even a full buffer can safely have escaped characters
  428             added to it.
  429         */
  430         return((Boolean) B->WrPos == (B->RdPos + BufferSize - 101) % BufferSize);
  431     }
  432 
  433 /* Add a byte to a buffer */
  434 void AddToBuffer(BufferType * B, unsigned char C)
  435     {
  436         B->Buffer[B->WrPos] = C;
  437         B->WrPos = (B->WrPos + 1) % BufferSize;
  438     }
  439 
  440 void PushToBuffer(BufferType * B, unsigned char C)
  441     {
  442         if (B->RdPos > 0) 
  443             B->RdPos--; 
  444         else 
  445             B->RdPos = BufferSize - 1; 
  446          
  447         B->Buffer[B->RdPos] = C;
  448     }
  449 
  450 /* Get a byte from a buffer */
  451 unsigned char GetFromBuffer(BufferType * B)
  452     {
  453         unsigned char C = B->Buffer[B->RdPos];
  454         B->RdPos = (B->RdPos + 1) % BufferSize;
  455         return(C);
  456     }
  457 
  458 /* Generic log function with log level control. Uses the same log levels
  459 of the syslog(3) system call */
  460 void LogMsg(int LogLevel, const char * const Msg)
  461     {
  462         if (LogLevel <= MaxLogLevel)
  463             syslog(LogLevel,"%s",Msg);
  464     }
  465 
  466 /* Try to lock the file given in LockFile as pid LockPid using the classical
  467 HDB (ASCII) file locking scheme */
  468 int HDBLockFile(char * LockFile, pid_t LockPid)
  469     {
  470         pid_t Pid;
  471         int FileDes;
  472         int N;
  473         char HDBBuffer[HDBHeaderLen + 1];
  474         char LogStr[TmpStrLen];
  475 
  476         /* Try to create the lock file */
  477         while ((FileDes = open(LockFile,O_CREAT | O_WRONLY | O_EXCL,LockFileMode)) == OpenError)
  478             {
  479                 /* Check the kind of error */
  480                 if ((errno == EEXIST) && ((FileDes = open(LockFile,O_RDONLY,0)) != OpenError))
  481                     {
  482                         /* Read the HDB header from the existing lockfile */
  483                         N = read(FileDes,HDBBuffer,HDBHeaderLen);
  484                         close(FileDes);
  485 
  486                         /* Check if the header has been read */
  487                         if (N <= 0)
  488                             {
  489                                 /* Emtpy lock file or error: may be another application
  490                                 was writing its pid in it */
  491                                 snprintf(LogStr,TmpStrLen - 1,"Can't read pid from lock file %s.",LockFile);
  492                                 LogStr[TmpStrLen - 1] = '\0';
  493                                 LogMsg(LOG_NOTICE,LogStr);
  494 
  495                                 /* Lock process failed */
  496                                 return(LockKo);
  497                             }
  498 
  499                         /* Gets the pid of the locking process */
  500                         HDBBuffer[N] = '\0';
  501                         Pid = atoi(HDBBuffer);
  502 
  503                         /* Check if it is our pid */
  504                         if (Pid == LockPid)
  505                             {
  506                                 /* File already locked by us */
  507                                 snprintf(LogStr,TmpStrLen - 1,"Read our pid from lock %s.",LockFile);
  508                                 LogStr[TmpStrLen - 1] = '\0';
  509                                 LogMsg(LOG_DEBUG,LogStr);
  510 
  511                                 /* Lock process succeded */
  512                                 return(LockOk);
  513                             }
  514 
  515                         /* Check if hte HDB header is valid and if the locking process
  516                             is still alive */
  517                         if ((Pid == 0) || ((kill(Pid,0) != 0) && (errno == ESRCH)))
  518                             /* Invalid lock, remove it */
  519                             if (unlink(LockFile) == NoError)
  520                                 {
  521                                     snprintf(LogStr,TmpStrLen - 1,"Removed stale lock %s (pid %d).",
  522                                         LockFile,Pid);
  523                                      LogStr[TmpStrLen - 1] = '\0';
  524                                     LogMsg(LOG_NOTICE,LogStr);
  525                                 }
  526                             else
  527                                 {
  528                                     snprintf(LogStr,TmpStrLen - 1,"Couldn't remove stale lock %s (pid %d).",
  529                                          LockFile,Pid);
  530                                     LogStr[TmpStrLen - 1] = '\0';
  531                                     LogMsg(LOG_ERR,LogStr);
  532                                     return(LockKo);
  533                                 }
  534                         else
  535                             {
  536                                 /* The lock file is owned by another valid process */
  537                                 snprintf(LogStr,TmpStrLen - 1,"Lock %s is owned by pid %d.",LockFile,Pid);
  538                                 LogStr[TmpStrLen - 1] = '\0';
  539                                 LogMsg(LOG_INFO,LogStr);
  540 
  541                                 /* Lock process failed */
  542                                 return(Locked);
  543                             }
  544                     }
  545                 else
  546                     {
  547                         /* Lock file creation problem */
  548                         snprintf(LogStr,TmpStrLen - 1,"Can't create lock file %s.",LockFile);
  549                         LogStr[TmpStrLen - 1] = '\0';
  550                         LogMsg(LOG_ERR,LogStr);
  551 
  552                         /* Lock process failed */
  553                         return(LockKo);
  554                     }
  555             }
  556 
  557         /* Prepare the HDB buffer with our pid */
  558         sprintf(HDBBuffer,"%10d\n",(int) LockPid);
  559         
  560         /* Fill the lock file with the HDB buffer */
  561         if (write(FileDes,HDBBuffer,HDBHeaderLen) != HDBHeaderLen)
  562             {
  563                 /* Lock file creation problem, remove it */
  564                 close(FileDes);
  565                 snprintf(LogStr,TmpStrLen - 1,"Can't write HDB header to lock file %s.",LockFile);
  566                 LogStr[TmpStrLen - 1] = '\0';
  567                 LogMsg(LOG_ERR,LogStr);
  568                 unlink(LockFile);
  569 
  570                 /* Lock process failed */
  571                 return(LockKo);
  572             }
  573 
  574         /* Closes the lock file */
  575         close(FileDes);
  576 
  577         /* Lock process succeded */
  578         return(LockOk);
  579     }
  580 
  581 /* Remove the lock file created with HDBLockFile */
  582 void HDBUnlockFile(char * LockFile, pid_t LockPid)
  583     {
  584         char LogStr[TmpStrLen];
  585 
  586         /* Check if the lock file is still owned by us */
  587         if (HDBLockFile(LockFile,LockPid) == LockOk)
  588             {
  589                 /* Remove the lock file */
  590                 unlink(LockFile);
  591                 snprintf(LogStr,TmpStrLen - 1,"Unlocked lock file %s.",LockFile);
  592                 LogStr[TmpStrLen - 1] = '\0';
  593                 LogMsg(LOG_NOTICE,LogStr);
  594             }
  595     }
  596 
  597 /* Function executed when the program exits */
  598 void ExitFunction(void)
  599     {
  600         /* Restores initial port settings */
  601         if (InitPortRetrieved == True)
  602             tcsetattr(DeviceFd,TCSANOW,&InitialPortSettings);
  603 
  604         /* Closes the device */
  605         if (DeviceOpened == True)
  606             close(DeviceFd);
  607 
  608         /* Closes the sockets */
  609         close(STDIN_FILENO);
  610         close(STDOUT_FILENO);
  611 
  612         /* Removes the lock file */
  613         HDBUnlockFile(LockFileName,getpid());
  614 
  615         /* Program termination notification */
  616         LogMsg(LOG_NOTICE,"SRedird stopped.");
  617 
  618         /* Closes the log */
  619         closelog();
  620     }
  621 
  622 /* Function called on many signals */
  623 void SignalFunction(int unused)
  624     {
  625         /* Just to avoid compilation warnings */
  626         /* There's no performance penalty in doing this 
  627         because this function is almost never called */
  628         unused = unused;
  629         
  630         /* Same as the exit function */
  631         ExitFunction();
  632     }
  633 
  634 /* Function called on break signal */
  635 /* Unimplemented yet */
  636 void BreakFunction(int unused)
  637     {
  638 #ifndef COMMENT
  639         /* Just to avoid compilation warnings */
  640         /* There's no performance penalty in doing this 
  641         because this function is almost never called */
  642         unused = unused;
  643 
  644         /* Same as the exit function */
  645         ExitFunction();
  646 #else /* COMMENT */
  647 
  648         unsigned char LineState;
  649 
  650         if (BreakSignaled == True)
  651             {
  652                 BreakSignaled = False;
  653                 LineState = 0;
  654             }
  655         else
  656             {
  657                 BreakSignaled = True;
  658                 LineState = 16;
  659             }
  660 
  661         /* Notify client of break change */
  662         if ((LineStateMask & (unsigned char) 16) != 0)
  663             {
  664                 LogMsg(LOG_DEBUG,"Notifying break change.");
  665                 SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_LINESTATE,LineState);
  666             }
  667 #endif /* COMMENT */
  668     }
  669 
  670 /* Retrieves the port speed from PortFd */
  671 unsigned long int GetPortSpeed(int PortFd)
  672     {
  673         struct termios PortSettings;
  674         speed_t Speed;
  675 
  676         tcgetattr(PortFd,&PortSettings);
  677         Speed = cfgetospeed(&PortSettings);
  678 
  679         switch (Speed)
  680             {
  681                 case B50:
  682                     return(50UL);
  683                 case B75:
  684                     return(75UL);
  685                 case B110:
  686                     return(110UL);
  687                 case B134:
  688                     return(134UL);
  689                 case B150:
  690                     return(150UL);
  691                 case B200:
  692                     return(200UL);
  693                 case B300:
  694                     return(300UL);
  695                 case B600:
  696                     return(600UL);
  697                 case B1200:
  698                     return(1200UL);
  699                 case B1800:
  700                     return(1800UL);
  701                 case B2400:
  702                     return(2400UL);
  703                 case B4800:
  704                     return(4800UL);
  705                 case B9600:
  706                     return(9600UL);
  707                 case B19200:
  708                     return(19200UL);
  709                 case B38400:
  710                     return(38400UL);
  711                 case B57600:
  712                     return(57600UL);
  713                 case B115200:
  714                     return(115200UL);
  715                 case B230400:
  716                     return(230400UL);
  717                 case B460800:
  718                     return(460800UL);
  719                 default:
  720                     return(0UL);
  721             }
  722     }
  723 
  724 /* Retrieves the data size from PortFd */
  725 unsigned char GetPortDataSize(int PortFd)
  726     {
  727         struct termios PortSettings;
  728         tcflag_t DataSize;
  729 
  730         tcgetattr(PortFd,&PortSettings);
  731         DataSize = PortSettings.c_cflag & CSIZE;
  732 
  733         switch (DataSize)
  734             {
  735                 case CS5:
  736                     return((unsigned char) 5);
  737                 case CS6:
  738                     return((unsigned char) 6);
  739                 case CS7:
  740                     return((unsigned char) 7);
  741                 case CS8:
  742                     return((unsigned char) 8);
  743                 default:
  744                     return((unsigned char) 0);
  745             }
  746     }
  747 
  748 /* Retrieves the parity settings from PortFd */
  749 unsigned char GetPortParity(int PortFd)
  750     {
  751         struct termios PortSettings;
  752 
  753         tcgetattr(PortFd,&PortSettings);
  754 
  755         if ((PortSettings.c_cflag & PARENB) == 0)
  756             return((unsigned char) 1);
  757 
  758         if ((PortSettings.c_cflag & PARENB) != 0 &&
  759             (PortSettings.c_cflag & PARODD) != 0)
  760             return((unsigned char) 2);
  761 
  762         return((unsigned char) 3);
  763     }
  764 
  765 /* Retrieves the stop bits size from PortFd */
  766 unsigned char GetPortStopSize(int PortFd)
  767     {
  768         struct termios PortSettings;
  769 
  770         tcgetattr(PortFd,&PortSettings);
  771 
  772         if ((PortSettings.c_cflag & CSTOPB) == 0)
  773             return((unsigned char) 1);
  774         else
  775             return((unsigned char) 2);
  776     }
  777 
  778 /* Retrieves the flow control status, including DTR and RTS status,
  779 from PortFd */
  780 unsigned char GetPortFlowControl(int PortFd, unsigned char Which)
  781     {
  782         struct termios PortSettings;
  783         int MLines;
  784 
  785         /* Gets the basic informations from the port */
  786         tcgetattr(PortFd,&PortSettings);
  787         ioctl(PortFd,TIOCMGET,&MLines);
  788 
  789         /* Check wich kind of information is requested */
  790         switch (Which)
  791             {
  792                 /* Com Port Flow Control Setting (outbound/both) */
  793                 case 0:
  794                     if (PortSettings.c_iflag & IXON)
  795                         return((unsigned char) 2);
  796                     if (PortSettings.c_cflag & CRTSCTS)
  797                         return((unsigned char) 3);
  798                     return((unsigned char) 1);
  799                 break;
  800 
  801                 /* BREAK State  */
  802                 case 4:
  803                     if (BreakSignaled == True)
  804                         return((unsigned char) 5);
  805                     else
  806                         return((unsigned char) 6);
  807                 break;
  808 
  809                 /* DTR Signal State */
  810                 case 7:
  811                     if (MLines & TIOCM_DTR)
  812                         return((unsigned char) 8);
  813                     else
  814                         return((unsigned char) 9);
  815                 break;
  816 
  817                 /* RTS Signal State */
  818                 case 10:
  819                     if (MLines & TIOCM_RTS)
  820                         return((unsigned char) 11);
  821                     else
  822                         return((unsigned char) 12);
  823                 break;
  824 
  825                 /* Com Port Flow Control Setting (inbound) */
  826                 case 13:
  827                     if (PortSettings.c_iflag & IXOFF)
  828                         return((unsigned char) 15);
  829                     if (PortSettings.c_cflag & CRTSCTS)
  830                         return((unsigned char) 16);
  831                     return((unsigned char) 14);
  832                 break;
  833 
  834                 default:
  835                     if (PortSettings.c_iflag & IXON)
  836                         return((unsigned char) 2);
  837                     if (PortSettings.c_cflag & CRTSCTS)
  838                         return((unsigned char) 3);
  839                     return((unsigned char) 1);
  840                 break;
  841             }
  842     }
  843 
  844 /* Return the status of the modem control lines (DCD, CTS, DSR, RNG) */
  845 unsigned char GetModemState(int PortFd,unsigned char PMState)
  846     {
  847         int MLines;
  848         unsigned char MState = (unsigned char) 0;
  849 
  850         ioctl(PortFd,TIOCMGET,&MLines);
  851 
  852         if ((MLines & TIOCM_CAR) != 0)
  853             MState += (unsigned char) 128;
  854         if ((MLines & TIOCM_RNG) != 0)
  855             MState += (unsigned char) 64;
  856         if ((MLines & TIOCM_DSR) != 0)
  857             MState += (unsigned char) 32;
  858         if ((MLines & TIOCM_CTS) != 0)
  859             MState += (unsigned char) 16;
  860         if ((MState & 128) != (PMState & 128))
  861             MState += (unsigned char) 8;
  862         if ((MState & 64) != (PMState & 64))
  863             MState += (unsigned char) 4;
  864         if ((MState & 32) != (PMState & 32))
  865             MState += (unsigned char) 2;
  866         if ((MState & 16) != (PMState & 16))
  867             MState += (unsigned char) 1;
  868 
  869         return(MState);
  870     }
  871 
  872 /* Set the serial port data size */
  873 void SetPortDataSize(int PortFd, unsigned char DataSize)
  874     {
  875         struct termios PortSettings;
  876         tcflag_t PDataSize;
  877 
  878         switch (DataSize)
  879             {
  880                 case 5:
  881                     PDataSize = CS5;
  882                 break;
  883                 case 6:
  884                     PDataSize = CS6;
  885                 break;
  886                 case 7:
  887                     PDataSize = CS7;
  888                 break;
  889                 case 8:
  890                     PDataSize = CS8;
  891                 break;
  892                 default:
  893                     PDataSize = CS8;
  894                 break;
  895             }
  896 
  897         tcgetattr(PortFd,&PortSettings);
  898         PortSettings.c_cflag &= ~CSIZE;
  899         PortSettings.c_cflag |= PDataSize & CSIZE;
  900         tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  901     }
  902 
  903 /* Set the serial port parity */
  904 void SetPortParity(int PortFd, unsigned char Parity)
  905     {
  906         struct termios PortSettings;
  907 
  908         tcgetattr(PortFd,&PortSettings);
  909 
  910         switch (Parity)
  911             {
  912                 case 1:
  913                     PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB;
  914                 break;
  915                 case 2:
  916                     PortSettings.c_cflag = PortSettings.c_cflag | PARENB | PARODD;
  917                 break;
  918                 case 3:
  919                     PortSettings.c_cflag = (PortSettings.c_cflag | PARENB) & ~PARODD;
  920                 break;
  921                 /* There's no support for MARK and SPACE parity so sets no parity */
  922                 default:
  923                     LogMsg(LOG_WARNING,"Requested unsupported parity, set to no parity.");
  924                     PortSettings.c_cflag = PortSettings.c_cflag & ~PARENB;
  925                 break;
  926             }
  927 
  928         tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  929     }
  930 
  931 /* Set the serial port stop bits size */
  932 void SetPortStopSize(int PortFd, unsigned char StopSize)
  933     {
  934         struct termios PortSettings;
  935 
  936         tcgetattr(PortFd,&PortSettings);
  937 
  938         switch (StopSize)
  939             {
  940                 case 1:
  941                     PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  942                 break;
  943                 case 2:
  944                     PortSettings.c_cflag = PortSettings.c_cflag | CSTOPB;
  945                 break;
  946                 case 3:
  947                     PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  948                     LogMsg(LOG_WARNING,"Requested unsupported 1.5 bits stop size, set to 1 bit stop size.");
  949                 break;
  950                 default:
  951                     PortSettings.c_cflag = PortSettings.c_cflag & ~CSTOPB;
  952                 break;
  953             }
  954 
  955         tcsetattr(PortFd,TCSADRAIN,&PortSettings);
  956     }
  957 
  958 /* Set the port flow control and DTR and RTS status */
  959 void SetPortFlowControl(int PortFd,unsigned char How)
  960     {
  961         struct termios PortSettings;
  962         int MLines;
  963 
  964         /* Gets the base status from the port */
  965         tcgetattr(PortFd,&PortSettings);
  966         ioctl(PortFd,TIOCMGET,&MLines);
  967 
  968         /* Check which settings to change */
  969         switch (How)
  970             {
  971                 /* No Flow Control (outbound/both) */
  972                 case 1:
  973                     PortSettings.c_iflag = PortSettings.c_iflag & ~IXON;
  974                     PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF;
  975                     PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS;
  976                 break;
  977                 /* XON/XOFF Flow Control (outbound/both) */
  978                 case 2:
  979                     PortSettings.c_iflag = PortSettings.c_iflag | IXON;
  980                     PortSettings.c_iflag = PortSettings.c_iflag | IXOFF;
  981                     PortSettings.c_cflag = PortSettings.c_cflag & ~CRTSCTS;
  982                 break;
  983                 /* HARDWARE Flow Control (outbound/both) */
  984                 case 3:
  985                     PortSettings.c_iflag = PortSettings.c_iflag & ~IXON;
  986                     PortSettings.c_iflag = PortSettings.c_iflag & ~IXOFF;
  987                     PortSettings.c_cflag = PortSettings.c_cflag | CRTSCTS;
  988                 break;
  989                 /* BREAK State ON */
  990                 case 5:
  991                     tcsendbreak(PortFd,1);
  992                     BreakSignaled = True;
  993                 break;
  994                 /* BREAK State OFF */
  995                 case 6:
  996                     /* Should not send another break */
  997                     /* tcsendbreak(PortFd,0); */
  998                     BreakSignaled = False;
  999                 break;
 1000                 /* DTR Signal State ON */
 1001                 case 8:
 1002                     MLines = MLines | TIOCM_DTR;
 1003                 break;
 1004                 /* DTR Signal State OFF */
 1005                 case 9:
 1006                     MLines = MLines & ~TIOCM_DTR;
 1007                 break;
 1008                 /* RTS Signal State ON */
 1009                 case 11:
 1010                     MLines = MLines | TIOCM_RTS;
 1011                 break;
 1012                 /* RTS Signal State OFF */
 1013                 case 12:
 1014                     MLines = MLines & ~TIOCM_RTS;
 1015                 break;
 1016 
 1017                 /* INBOUND FLOW CONTROL is ignored */
 1018                 /* No Flow Control (inbound) */
 1019                 case 14:
 1020                 /* XON/XOFF Flow Control (inbound) */
 1021                 case 15:
 1022                 /* HARDWARE Flow Control (inbound) */
 1023                 case 16:
 1024                     LogMsg(LOG_WARNING,"Inbound flow control ignored.");
 1025                 break;
 1026                 default:
 1027                     LogMsg(LOG_WARNING,"Requested unsupported flow control.");
 1028                 break;
 1029             }
 1030 
 1031         tcsetattr(PortFd,TCSADRAIN,&PortSettings);
 1032         ioctl(PortFd,TIOCMSET,&MLines);
 1033     }
 1034 
 1035 /* Set the serial port speed */
 1036 void SetPortSpeed(int PortFd, unsigned long BaudRate)
 1037     {
 1038         struct termios PortSettings;
 1039         speed_t Speed;
 1040 
 1041         switch (BaudRate)
 1042             {
 1043                 case 50UL:
 1044                     Speed = B50;
 1045                 break;
 1046                 case 75UL:
 1047                     Speed = B75;
 1048                 break;
 1049                 case 110UL:
 1050                     Speed = B110;
 1051                 break;
 1052                 case 134UL:
 1053                     Speed = B134;
 1054                 break;
 1055                 case 150UL:
 1056                     Speed = B150;
 1057                 break;
 1058                 case 200UL:
 1059                     Speed = B200;
 1060                 break;
 1061                 case 300UL:
 1062                     Speed = B300;
 1063                 break;
 1064                 case 600UL:
 1065                     Speed = B600;
 1066                 break;
 1067                 case 1200UL:
 1068                     Speed = B1200;
 1069                 break;
 1070                 case 1800UL:
 1071                     Speed = B1800;
 1072                 break;
 1073                 case 2400UL:
 1074                     Speed = B2400;
 1075                 break;
 1076                 case 4800UL:
 1077                     Speed = B4800;
 1078                 break;
 1079                 case 9600UL:
 1080                     Speed = B9600;
 1081                 break;
 1082                 case 19200UL:
 1083                     Speed = B19200;
 1084                 break;
 1085                 case 38400UL:
 1086                     Speed = B38400;
 1087                 break;
 1088                 case 57600UL:
 1089                     Speed = B57600;
 1090                 break;
 1091                 case 115200UL:
 1092                     Speed = B115200;
 1093                 break;
 1094                 case 230400UL:
 1095                     Speed = B230400;
 1096                 break;
 1097                 case 460800UL:
 1098                     Speed = B460800;
 1099                 break;
 1100                 default:
 1101                     LogMsg(LOG_WARNING,"Unknwon baud rate requested, setting to 9600.");
 1102                     Speed = B9600;
 1103                 break;
 1104             }
 1105 
 1106         tcgetattr(PortFd,&PortSettings);
 1107         cfsetospeed(&PortSettings,Speed);
 1108         cfsetispeed(&PortSettings,Speed);
 1109         tcsetattr(PortFd,TCSADRAIN,&PortSettings);
 1110     }
 1111 
 1112 /* Send the signature Sig to the client */
 1113 void SendSignature(BufferType * B, char * Sig)
 1114     {
 1115         AddToBuffer(B,TNIAC);
 1116         AddToBuffer(B,TNSB);
 1117         AddToBuffer(B,TNCOM_PORT_OPTION);
 1118         AddToBuffer(B,TNASC_SIGNATURE);
 1119         SendStr(B,Sig);
 1120         AddToBuffer(B,TNIAC);
 1121         AddToBuffer(B,TNSE);
 1122     }
 1123 
 1124 /* Write a char to socket performing IAC escaping */
 1125 void EscWriteChar(BufferType * B, unsigned char C)
 1126     {
 1127         /* Last received byte */
 1128         static unsigned char Last=0;
 1129 
 1130         if (C == TNIAC)
 1131             AddToBuffer(B,C);
 1132         else
 1133             if (C != 0x0A && tnstate[TN_TRANSMIT_BINARY].is_will == False && Last == 0x0D)
 1134                 AddToBuffer(B,0x00);
 1135         AddToBuffer(B,C);
 1136 
 1137         /* Set last received byte */
 1138         Last = C;
 1139     }
 1140 
 1141 /* Redirect char C to Device checking for IAC escape sequences */
 1142 void EscRedirectChar(BufferType * SockB, BufferType * DevB, int PortFd, unsigned char C)
 1143     {
 1144         /* Last received byte */
 1145         static unsigned char Last = 0;
 1146 
 1147         /* Check the IAC escape status */
 1148         switch (IACEscape)
 1149             {
 1150                 /* Normal status */
 1151                 case IACNormal:
 1152                     if (C == TNIAC)
 1153                         IACEscape = IACReceived;
 1154                     else
 1155                         if (tnstate[TN_TRANSMIT_BINARY].is_do == False && C == 0x00 && Last == 0x0D)
 1156                             /* Swallow the NUL after a CR if not receiving BINARY */
 1157                             break;
 1158                         else
 1159                             AddToBuffer(DevB,C);
 1160                 break;
 1161 
 1162                 /* IAC previously received */
 1163                 case IACReceived:
 1164                     if (C == TNIAC)
 1165                         {
 1166                             AddToBuffer(DevB,C);
 1167                             IACEscape = IACNormal;
 1168                         }
 1169                     else
 1170                         {
 1171                             IACCommand[0] = TNIAC;
 1172                             IACCommand[1] = C;
 1173                             IACPos = 2;
 1174                             IACEscape = IACComReceiving;
 1175                             IACSigEscape = IACNormal;
 1176                         }
 1177                 break;
 1178 
 1179                 /* IAC Command reception */
 1180                 case IACComReceiving:
 1181                     /* Telnet suboption, could be only CPC */
 1182                     if (IACCommand[1] == TNSB)
 1183                         {
 1184                             /* Get the suboption signature */
 1185                             if (IACPos < 4)
 1186                                 {
 1187                                     IACCommand[IACPos] = C;
 1188                                     IACPos++;
 1189                                 }
 1190                             else
 1191                                 {
 1192                                     /* Check which suboption we are dealing with */
 1193                                     switch (IACCommand[3])
 1194                                         {
 1195                                             /* Signature, which needs further escaping */
 1196                                             case TNCAS_SIGNATURE:
 1197                                                 switch (IACSigEscape)
 1198                                                     {
 1199                                                         case IACNormal:
 1200                                                             if (C == TNIAC)
 1201                                                                 IACSigEscape = IACReceived;
 1202                                                             else
 1203                                                                 if (IACPos < TmpStrLen)
 1204                                                                     {
 1205                                                                         IACCommand[IACPos] = C;
 1206                                                                         IACPos++;
 1207                                                                     }
 1208                                                         break;
 1209 
 1210                                                         case IACComReceiving:
 1211                                                             IACSigEscape = IACNormal;
 1212                                                         break;
 1213 
 1214                                                         case IACReceived:
 1215                                                             if (C == TNIAC)
 1216                                                                 {
 1217                                                                     if (IACPos < TmpStrLen)
 1218                                                                         {
 1219                                                                             IACCommand[IACPos] = C;
 1220                                                                             IACPos++;
 1221                                                                         }
 1222                                                                     IACSigEscape = IACNormal;
 1223                                                                 }
 1224                                                             else
 1225                                                                 {
 1226                                                                     if (IACPos < TmpStrLen)
 1227                                                                         {
 1228                                                                             IACCommand[IACPos] = TNIAC;
 1229                                                                             IACPos++;
 1230                                                                         }
 1231 
 1232                                                                     if (IACPos < TmpStrLen)
 1233                                                                         {
 1234                                                                             IACCommand[IACPos] = C;
 1235                                                                             IACPos++;
 1236                                                                         }
 1237 
 1238                                                                     HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
 1239                                                                     IACEscape = IACNormal;
 1240                                                                 }
 1241                                                         break;
 1242                                                     }
 1243                                             break;
 1244 
 1245                                             /* Set baudrate */
 1246                                             case TNCAS_SET_BAUDRATE:
 1247                                                 IACCommand[IACPos] = C;
 1248                                                 IACPos++;
 1249 
 1250                                                 if (IACPos == 10)
 1251                                                     {
 1252                                                         HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
 1253                                                         IACEscape = IACNormal;
 1254                                                     }
 1255                                             break;
 1256 
 1257                                             /* Flow control command */
 1258                                             case TNCAS_FLOWCONTROL_SUSPEND:
 1259                                             case TNCAS_FLOWCONTROL_RESUME:
 1260                                                 IACCommand[IACPos] = C;
 1261                                                 IACPos++;
 1262 
 1263                                             if (IACPos == 6)
 1264                                                 {
 1265                                                     HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
 1266                                                     IACEscape = IACNormal;
 1267                                                 }
 1268                                             break;
 1269 
 1270                                             /* Normal CPC command with single byte parameter */
 1271                                             default:
 1272                                                 IACCommand[IACPos] = C;
 1273                                                 IACPos++;
 1274 
 1275                                                 if (IACPos == 7)
 1276                                                     {
 1277                                                         HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
 1278                                                         IACEscape = IACNormal;
 1279                                                     }
 1280                                             break;
 1281                                         }
 1282                                 }
 1283                         }
 1284                     else
 1285                         {
 1286                             /* Normal 3 byte IAC option */
 1287                             IACCommand[IACPos] = C;
 1288                             IACPos++;
 1289 
 1290                             if (IACPos == 3)
 1291                                 {
 1292                                     HandleIACCommand(SockB,PortFd,IACCommand,IACPos);
 1293                                     IACEscape = IACNormal;
 1294                                 }
 1295                         }
 1296                 break;
 1297             }
 1298 
 1299         /* Set last received byte */
 1300         Last = C;
 1301     }
 1302 
 1303 /* Send the specific telnet option to SockFd using Command as command */
 1304 void SendTelnetOption(BufferType * B, unsigned char Command, char Option)
 1305     {
 1306         unsigned char IAC = TNIAC;
 1307 
 1308         AddToBuffer(B,IAC);
 1309         AddToBuffer(B,Command);
 1310         AddToBuffer(B,Option);
 1311     }
 1312 
 1313 /* Send a string to SockFd performing IAC escaping */
 1314 void SendStr(BufferType * B, char * Str)
 1315     {
 1316         size_t I;
 1317         size_t L;
 1318 
 1319         L = strlen(Str);
 1320 
 1321         for (I = 0; I < L;I++)
 1322             EscWriteChar(B,(unsigned char) Str[I]);
 1323     }
 1324 
 1325 /* Send the baud rate BR to Buffer */
 1326 void SendBaudRate(BufferType *B, unsigned long int BR)
 1327     {
 1328         unsigned char *p;
 1329         unsigned long int NBR;
 1330         int i;
 1331 
 1332         NBR = htonl(BR);
 1333 
 1334         AddToBuffer(B,TNIAC);
 1335         AddToBuffer(B,TNSB);
 1336         AddToBuffer(B,TNCOM_PORT_OPTION);
 1337         AddToBuffer(B,TNASC_SET_BAUDRATE);
 1338         p = (unsigned char *) &NBR;
 1339         for (i = 0;i < (int) sizeof(NBR);i++)
 1340             EscWriteChar(B,p[i]);
 1341         AddToBuffer(B,TNIAC);
 1342         AddToBuffer(B,TNSE);
 1343     }
 1344 
 1345 /* Send the flow control command Command */
 1346 void SendCPCFlowCommand(BufferType *B, unsigned char Command)
 1347     {
 1348         AddToBuffer(B,TNIAC);
 1349         AddToBuffer(B,TNSB);
 1350         AddToBuffer(B,TNCOM_PORT_OPTION);
 1351         AddToBuffer(B,Command);
 1352         AddToBuffer(B,TNIAC);
 1353         AddToBuffer(B,TNSE);
 1354 
 1355         if (Command == TNASC_FLOWCONTROL_SUSPEND)
 1356             LogMsg(LOG_DEBUG,"Sent flow control suspend command.");
 1357         else
 1358             LogMsg(LOG_DEBUG,"Sent flow control resume command.");
 1359     }
 1360 
 1361 /* Send the CPC command Command using Parm as parameter */
 1362 void SendCPCByteCommand(BufferType *B, unsigned char Command, unsigned char Parm)
 1363     {
 1364         AddToBuffer(B,TNIAC);
 1365         AddToBuffer(B,TNSB);
 1366         AddToBuffer(B,TNCOM_PORT_OPTION);
 1367         AddToBuffer(B,Command);
 1368         EscWriteChar(B,Parm);
 1369         AddToBuffer(B,TNIAC);
 1370         AddToBuffer(B,TNSE);
 1371     }
 1372 
 1373 /* Handling of COM Port Control specific commands */
 1374 void HandleCPCCommand(BufferType *SockB, int PortFd, unsigned char * Command, size_t CSize)
 1375     {
 1376         char LogStr[TmpStrLen];
 1377         char SigStr[TmpStrLen];
 1378         unsigned long int BaudRate;
 1379         unsigned char DataSize;
 1380         unsigned char Parity;
 1381         unsigned char StopSize;
 1382         unsigned char FlowControl;
 1383 
 1384         /* Check wich command has been requested */
 1385         switch (Command[3])
 1386             {
 1387                 /* Signature */
 1388                 case TNCAS_SIGNATURE:
 1389                     if (CSize == 6)
 1390                         {
 1391                             /* Void signature, client is asking for our signature */
 1392                             snprintf(SigStr,TmpStrLen - 1,"SRedird %s %s",VersionId,DeviceName);
 1393                             SigStr[TmpStrLen - 1] = '\0';
 1394                             SendSignature(SockB,SigStr);
 1395                             snprintf(LogStr,TmpStrLen - 1,"Sent signature: %s",SigStr);
 1396                             LogStr[TmpStrLen - 1] = '\0';
 1397                             LogMsg(LOG_INFO,LogStr);
 1398                         }
 1399                     else
 1400                         {
 1401                             /* Received client signature */
 1402                             strncpy(SigStr,(char *) &Command[4],CSize - 6);
 1403                             snprintf(LogStr,TmpStrLen - 1,"Received client signature: %s",SigStr);
 1404                             LogStr[TmpStrLen - 1] = '\0';
 1405                             LogMsg(LOG_INFO,LogStr);
 1406                         }
 1407                 break;
 1408 
 1409                 /* Set serial baud rate */
 1410                 case TNCAS_SET_BAUDRATE:
 1411                     /* Retrieve the baud rate which is in network order */
 1412                     BaudRate = ntohl(*((unsigned long int *) &Command[4]));
 1413 
 1414                     if (BaudRate == 0)
 1415                         /* Client is asking for current baud rate */
 1416                         LogMsg(LOG_DEBUG,"Baud rate notification received.");
 1417                     else
 1418                         {
 1419                             /* Change the baud rate */
 1420                             snprintf(LogStr,TmpStrLen - 1,"Port baud rate change to %lu requested.",BaudRate);
 1421                             LogStr[TmpStrLen - 1] = '\0';
 1422                             LogMsg(LOG_DEBUG,LogStr);
 1423                             SetPortSpeed(PortFd,BaudRate);
 1424                         }
 1425 
 1426                     /* Send confirmation */
 1427                     BaudRate = GetPortSpeed(PortFd);
 1428                     SendBaudRate(SockB,BaudRate);
 1429                     snprintf(LogStr,TmpStrLen - 1,"Port baud rate: %lu",BaudRate);
 1430                     LogStr[TmpStrLen - 1] = '\0';
 1431                     LogMsg(LOG_DEBUG,LogStr);
 1432                 break;
 1433 
 1434                 /* Set serial data size */
 1435                 case TNCAS_SET_DATASIZE:
 1436                     if (Command[4] == 0)
 1437                         /* Client is asking for current data size */
 1438                         LogMsg(LOG_DEBUG,"Data size notification requested.");
 1439                     else
 1440                         {
 1441                             /* Set the data size */
 1442                             snprintf(LogStr,TmpStrLen - 1,"Port data size change to %u requested.",
 1443                                 (unsigned int) Command[4]);
 1444                             LogStr[TmpStrLen - 1] = '\0';
 1445                             LogMsg(LOG_DEBUG,LogStr);
 1446                             SetPortDataSize(PortFd,Command[4]);
 1447                         }
 1448 
 1449                     /* Send confirmation */
 1450                     DataSize = GetPortDataSize(PortFd);
 1451                     SendCPCByteCommand(SockB,TNASC_SET_DATASIZE,DataSize);
 1452                     snprintf(LogStr,TmpStrLen - 1,"Port data size: %u",(unsigned int) DataSize);
 1453                     LogStr[TmpStrLen - 1] = '\0';
 1454                     LogMsg(LOG_DEBUG,LogStr);
 1455                 break;
 1456 
 1457                 /* Set the serial parity */
 1458                 case TNCAS_SET_PARITY:
 1459                     if (Command[4] == 0)
 1460                         /* Client is asking for current parity */
 1461                         LogMsg(LOG_DEBUG,"Parity notification requested.");
 1462                     else
 1463                         {
 1464                             /* Set the parity */
 1465                             snprintf(LogStr,TmpStrLen - 1,"Port parity change to %u requested",
 1466                                              (unsigned int) Command[4]);
 1467                             LogStr[TmpStrLen - 1] = '\0';
 1468                             LogMsg(LOG_DEBUG,LogStr);
 1469                             SetPortParity(PortFd,Command[4]);
 1470                         }
 1471 
 1472                     /* Send confirmation */
 1473                     Parity = GetPortParity(PortFd);
 1474                     SendCPCByteCommand(SockB,TNASC_SET_PARITY,Parity);
 1475                     snprintf(LogStr,TmpStrLen - 1,"Port parity: %u",(unsigned int) Parity);
 1476                     LogStr[TmpStrLen - 1] = '\0';
 1477                     LogMsg(LOG_DEBUG,LogStr);
 1478                 break;
 1479 
 1480                 /* Set the serial stop size */
 1481                 case TNCAS_SET_STOPSIZE:
 1482                     if (Command[4] == 0)
 1483                         /* Client is asking for current stop size */
 1484                         LogMsg(LOG_DEBUG,"Stop size notification requested.");
 1485                     else
 1486                         {
 1487                             /* Set the stop size */
 1488                             snprintf(LogStr,TmpStrLen - 1,"Port stop size change to %u requested.",
 1489                                              (unsigned int) Command[4]);
 1490                             LogStr[TmpStrLen - 1] = '\0';
 1491                             LogMsg(LOG_DEBUG,LogStr);
 1492                             SetPortStopSize(PortFd,Command[4]);
 1493                         }
 1494 
 1495                     /* Send confirmation */
 1496                     StopSize = GetPortStopSize(PortFd);
 1497                     SendCPCByteCommand(SockB,TNASC_SET_STOPSIZE,StopSize);
 1498                     snprintf(LogStr,TmpStrLen - 1,"Port stop size: %u",(unsigned int) StopSize);
 1499                     LogStr[TmpStrLen - 1] = '\0';
 1500                     LogMsg(LOG_DEBUG,LogStr);
 1501                 break;
 1502 
 1503                 /* Flow control and DTR/RTS handling */
 1504                 case TNCAS_SET_CONTROL:
 1505                     switch (Command[4])
 1506                         {
 1507                             case 0:
 1508                             case 4:
 1509                             case 7:
 1510                             case 10:
 1511                             case 13:
 1512                                 /* Client is asking for current flow control or DTR/RTS status */
 1513                                 LogMsg(LOG_DEBUG,"Flow control notification requested.");
 1514                                 FlowControl = GetPortFlowControl(PortFd,Command[4]);
 1515                                 SendCPCByteCommand(SockB,TNASC_SET_CONTROL,FlowControl);
 1516                                 snprintf(LogStr,TmpStrLen - 1,"Port flow control: %u",(unsigned int) FlowControl);
 1517                                 LogStr[TmpStrLen - 1] = '\0';
 1518                                 LogMsg(LOG_DEBUG,LogStr);
 1519                             break;
 1520 
 1521                             case 5:
 1522                                 /* Break command */
 1523                                 tcsendbreak(PortFd,1);
 1524                                 BreakSignaled = True;
 1525                                 LogMsg(LOG_DEBUG,"Break Signal ON.");
 1526                                 SendCPCByteCommand(SockB,TNASC_SET_CONTROL,Command[4]);
 1527                             break;
 1528 
 1529                             case 6:
 1530                                 BreakSignaled = False;
 1531                                 LogMsg(LOG_DEBUG,"Break Signal OFF.");
 1532                                 SendCPCByteCommand(SockB,TNASC_SET_CONTROL,Command[4]);
 1533                             break;
 1534 
 1535                             default:
 1536                                 /* Set the flow control */
 1537                                 snprintf(LogStr,TmpStrLen - 1,"Port flow control change to %u requested.",(unsigned int) Command[4]);
 1538                                 LogStr[TmpStrLen - 1] = '\0';
 1539                                 LogMsg(LOG_DEBUG,LogStr);
 1540                                 SetPortFlowControl(PortFd,Command[4]);
 1541 
 1542                                 /* Flow control status confirmation */
 1543                                 if (CiscoIOSCompatible && Command[4] >= 13 && Command[4] <=16)
 1544                                     /* INBOUND not supported separately.
 1545                                         Following the behavior of Cisco ISO 11.3
 1546                                     */
 1547                                     FlowControl = 0;
 1548                                 else
 1549                                     /* Return the actual port flow control settings */
 1550                                     FlowControl = GetPortFlowControl(PortFd,0);
 1551 
 1552                                 SendCPCByteCommand(SockB,TNASC_SET_CONTROL,FlowControl);
 1553                                 snprintf(LogStr,TmpStrLen - 1,"Port flow control: %u",(unsigned int) FlowControl);
 1554                                 LogStr[TmpStrLen - 1] = '\0';
 1555                                 LogMsg(LOG_DEBUG,LogStr);
 1556                             break;
 1557                         }
 1558                 break;
 1559 
 1560                 /* Set the line state mask */
 1561                 case TNCAS_SET_LINESTATE_MASK:
 1562                     snprintf(LogStr,TmpStrLen - 1,"Line state set to %u",(unsigned int) Command[4]);
 1563                     LogStr[TmpStrLen - 1] = '\0';
 1564                     LogMsg(LOG_DEBUG,LogStr);
 1565 
 1566                     /* Only break notification supported */
 1567                     LineStateMask = Command[4] & (unsigned char) 16;
 1568                     SendCPCByteCommand(SockB,TNASC_SET_LINESTATE_MASK,LineStateMask);
 1569                 break;
 1570 
 1571                 /* Set the modem state mask */
 1572                 case TNCAS_SET_MODEMSTATE_MASK:
 1573                     snprintf(LogStr,TmpStrLen - 1,"Modem state mask set to %u",(unsigned int) Command[4]);
 1574                     LogStr[TmpStrLen - 1] = '\0';
 1575                     LogMsg(LOG_DEBUG,LogStr);
 1576                     ModemStateMask = Command[4];
 1577                     SendCPCByteCommand(SockB,TNASC_SET_MODEMSTATE_MASK,ModemStateMask);
 1578                 break;
 1579 
 1580                 /* Port flush requested */
 1581                 case TNCAS_PURGE_DATA:
 1582                     snprintf(LogStr,TmpStrLen - 1,"Port flush %u requested.",(unsigned int) Command[4]);
 1583                     LogStr[TmpStrLen - 1] = '\0';
 1584                     LogMsg(LOG_DEBUG,LogStr);
 1585                     switch (Command[4])
 1586                         {
 1587                             /* Inbound flush */
 1588                             case 1:
 1589                                 tcflush(PortFd,TCIFLUSH);
 1590                             break;
 1591                             /* Outbound flush */
 1592                             case 2:
 1593                                 tcflush(PortFd,TCOFLUSH);
 1594                             break;
 1595                             /* Inbound/outbound flush */
 1596                             case 3:
 1597                                 tcflush(PortFd,TCIOFLUSH);
 1598                             break;
 1599                         }
 1600 
 1601                     SendCPCByteCommand(SockB,TNASC_PURGE_DATA,Command[4]);
 1602                 break;
 1603 
 1604                 /* Suspend output to the client */
 1605                 case TNCAS_FLOWCONTROL_SUSPEND:
 1606                     LogMsg(LOG_DEBUG,"Flow control suspend requested.");
 1607                     InputFlow = False;
 1608                 break;
 1609 
 1610                 /* Resume output to the client */
 1611                 case TNCAS_FLOWCONTROL_RESUME:
 1612                     LogMsg(LOG_DEBUG,"Flow control resume requested.");
 1613                     InputFlow = True;
 1614                 break;
 1615 
 1616                 /* Unknown request */
 1617                 default:
 1618                     snprintf(LogStr,TmpStrLen - 1,"Unhandled request %u",(unsigned int) Command[3]);
 1619                     LogStr[TmpStrLen - 1] = '\0';
 1620                     LogMsg(LOG_DEBUG,LogStr);
 1621                 break;
 1622         }
 1623     }
 1624 
 1625 /* Common telnet IAC commands handling */
 1626 void HandleIACCommand(BufferType * SockB, int PortFd, unsigned char * Command, size_t CSize)
 1627     {
 1628         char LogStr[TmpStrLen];
 1629 
 1630         /* Check which command */
 1631         switch(Command[1])
 1632             {
 1633                 /* Suboptions */
 1634                 case TNSB:
 1635                     if (tnstate[Command[2]].is_will == False && tnstate[Command[2]].is_do == False)
 1636                         break;
 1637 
 1638                     switch (Command[2])
 1639                         {
 1640                             /* RFC 2217 COM Port Control Protocol option */
 1641                             case TNCOM_PORT_OPTION:
 1642                                 HandleCPCCommand(SockB,PortFd,Command,CSize);
 1643                             break;
 1644 
 1645                             default:
 1646                                 snprintf(LogStr,TmpStrLen - 1,"Unknown suboption received: %u", (unsigned int) Command[2]);
 1647                                 LogStr[TmpStrLen - 1] = '\0';
 1648                                 LogMsg(LOG_DEBUG,LogStr);
 1649                             break;
 1650                         }
 1651                 break;
 1652 
 1653                 /* Requests for options */
 1654                 case TNWILL:
 1655                     switch (Command[2])
 1656                         {
 1657                             /* COM Port Control Option */
 1658                             case TNCOM_PORT_OPTION:
 1659                                 LogMsg(LOG_INFO,"Telnet COM Port Control Enabled (WILL).");
 1660                                 TCPCEnabled = True;
 1661                                 if (tnstate[Command[2]].sent_do == False)
 1662                                     {
 1663                                         SendTelnetOption(SockB,TNDO,Command[2]);
 1664                                     }
 1665                                 tnstate[Command[2]].is_do = True;
 1666                             break;
 1667 
 1668                             /* Telnet Binary mode */
 1669                             case TN_TRANSMIT_BINARY:
 1670                                 LogMsg(LOG_INFO,"Telnet Binary Transfer Enabled (WILL).");
 1671                                 if (tnstate[Command[2]].sent_do == False)
 1672                                     SendTelnetOption(SockB,TNDO,Command[2]);
 1673                                 tnstate[Command[2]].is_do = True;
 1674                             break;
 1675 
 1676                             /* Echo request not handled */
 1677                             case TN_ECHO:
 1678                                 LogMsg(LOG_INFO,"Rejecting Telnet Echo Option (WILL).");
 1679                                 if (tnstate[Command[2]].sent_do == False)
 1680                                     SendTelnetOption(SockB,TNDO,Command[2]);
 1681                                 tnstate[Command[2]].is_do = True;
 1682                             break;
 1683 
 1684                             /* No go ahead needed */
 1685                             case TN_SUPPRESS_GO_AHEAD:
 1686                                 LogMsg(LOG_INFO,"Suppressing Go Ahead characters (WILL).");
 1687                                 if (tnstate[Command[2]].sent_do == False)
 1688                                     SendTelnetOption(SockB,TNDO,Command[2]);
 1689                                 tnstate[Command[2]].is_do = True;
 1690                             break;
 1691 
 1692                             /* Reject everything else */
 1693                             default:
 1694                                 snprintf(LogStr,TmpStrLen - 1,"Rejecting option WILL: %u",(unsigned int) Command[2]);
 1695                                 LogStr[TmpStrLen - 1] = '\0';
 1696                                 LogMsg(LOG_DEBUG,LogStr);
 1697                                 SendTelnetOption(SockB,TNDONT,Command[2]);
 1698                                 tnstate[Command[2]].is_do = False;
 1699                             break;
 1700                         }
 1701                     tnstate[Command[2]].sent_do = False;
 1702                     tnstate[Command[2]].sent_dont = False;
 1703                 break;
 1704 
 1705                 /* Confirmations for options */
 1706                 case TNDO:
 1707                     switch (Command[2])
 1708                         {
 1709                             /* COM Port Control Option */
 1710                             case TNCOM_PORT_OPTION:
 1711                                 LogMsg(LOG_INFO,"Telnet COM Port Control Enabled (DO).");
 1712                                 TCPCEnabled = True;
 1713                                 if (tnstate[Command[2]].sent_will == False)
 1714                                     SendTelnetOption(SockB,TNWILL,Command[2]);
 1715                                 tnstate[Command[2]].is_will = True;
 1716                             break;
 1717 
 1718                             /* Telnet Binary mode */
 1719                             case TN_TRANSMIT_BINARY:
 1720                                 LogMsg(LOG_INFO,"Telnet Binary Transfer Enabled (DO).");
 1721                                 if (tnstate[Command[2]].sent_will == False)
 1722                                     SendTelnetOption(SockB,TNWILL,Command[2]);
 1723                                 tnstate[Command[2]].is_will = True;
 1724                             break;
 1725 
 1726                             /* Echo request handled.    The modem will echo for the user. */
 1727                             case TN_ECHO:
 1728                                 LogMsg(LOG_INFO,"Rejecting Telnet Echo Option (DO).");
 1729                                 if (tnstate[Command[2]].sent_will == False)
 1730                                     SendTelnetOption(SockB,TNWILL,Command[2]);
 1731                                 tnstate[Command[2]].is_will = True;
 1732                             break;
 1733 
 1734                             /* No go ahead needed */
 1735                             case TN_SUPPRESS_GO_AHEAD:
 1736                                 LogMsg(LOG_INFO,"Suppressing Go Ahead characters (DO).");
 1737                                 if (tnstate[Command[2]].sent_will == False)
 1738                                     SendTelnetOption(SockB,TNWILL,Command[2]);
 1739                                 tnstate[Command[2]].is_will = True;
 1740                             break;
 1741 
 1742                             /* Reject everything else */
 1743                             default:
 1744                                 snprintf(LogStr,TmpStrLen - 1,"Rejecting option DO: %u",(unsigned int) Command[2]);
 1745                                 LogStr[TmpStrLen - 1] = '\0';
 1746                                 LogMsg(LOG_DEBUG,LogStr);
 1747                                 SendTelnetOption(SockB,TNWONT,Command[2]);
 1748                                 tnstate[Command[2]].is_will = False;
 1749                             break;
 1750                         }
 1751                     tnstate[Command[2]].sent_will = False;
 1752                     tnstate[Command[2]].sent_wont = False;
 1753                 break;
 1754 
 1755                 /* Notifications of rejections for options */
 1756                 case TNDONT:
 1757                     snprintf(LogStr,TmpStrLen - 1,"Received rejection for option: %u",(unsigned int) Command[2]);
 1758                     LogStr[TmpStrLen - 1] = '\0';
 1759                     LogMsg(LOG_DEBUG,LogStr);
 1760                     if (tnstate[Command[2]].is_will == True)
 1761                         {
 1762                             SendTelnetOption(SockB,TNWONT,Command[2]);
 1763                             tnstate[Command[2]].is_will = False;
 1764                         }
 1765                     tnstate[Command[2]].sent_will = False;
 1766                     tnstate[Command[2]].sent_wont = False;
 1767                 break;
 1768 
 1769                 case TNWONT:
 1770                     if (Command[2] == TNCOM_PORT_OPTION)
 1771                         {
 1772                             LogMsg(LOG_ERR,"Client doesn't support Telnet COM Port "
 1773                                 "Protocol Option (RFC 2217), trying to serve anyway.");
 1774                         }
 1775                     else
 1776                         {
 1777                             snprintf(LogStr,TmpStrLen - 1,"Received rejection for option: %u",(unsigned int) Command[2]);
 1778                             LogStr[TmpStrLen - 1] = '\0';
 1779                             LogMsg(LOG_DEBUG,LogStr);
 1780                         }
 1781                     if (tnstate[Command[2]].is_do == True)
 1782                         {
 1783                             SendTelnetOption(SockB,TNDONT,Command[2]);
 1784                             tnstate[Command[2]].is_do = False;
 1785                         }
 1786                     tnstate[Command[2]].sent_do = False;
 1787                     tnstate[Command[2]].sent_dont = False;
 1788                 break;
 1789         }
 1790     }
 1791 
 1792 /* Write a buffer to SockFd with IAC escaping */
 1793 void EscWriteBuffer(BufferType * B, unsigned char * Buffer, unsigned int BSize)
 1794     {
 1795         unsigned int I;
 1796 
 1797         if (BSize > 0)
 1798             for (I = 0;I < BSize;I++)
 1799                 {
 1800                     if (Buffer[I] == TNIAC)
 1801                         AddToBuffer(B,TNIAC);
 1802                     AddToBuffer(B,Buffer[I]);
 1803                 }
 1804     }
 1805 
 1806 void Usage(void)
 1807 {
 1808         /* Write little usage information */
 1809         puts("sredird: RFC 2217 compliant serial port redirector");
 1810         puts(SRedirdVersionId);
 1811         puts("This program should be run only by the inetd superserver");
 1812         puts("Usage: sredird [-i] <loglevel> <device> <lockfile> [pollingterval]");
 1813         puts("-i indicates Cisco IOS Bug compatibility");
 1814         puts("Poll interval is in milliseconds, default is 100, "
 1815                     "0 means no polling");
 1816 
 1817         /* Same on the system log */
 1818         LogMsg(LOG_ERR,"sredird: RFC 2217 compliant serial port redirector.");
 1819         LogMsg(LOG_ERR,SRedirdVersionId);
 1820         LogMsg(LOG_ERR,"This program should be run only by the inetd superserver.");
 1821         LogMsg(LOG_ERR,"Usage: sredird [-i] <loglevel> <device> <lockfile> [pollingterval]");
 1822         LogMsg(LOG_ERR,"-i indicates Cisco IOS Bug compatibility");
 1823         LogMsg(LOG_ERR,"Poll interval is in milliseconds, default is 100, 0 means no polling.");
 1824 }
 1825 
 1826 /* Main function */
 1827 int main(int argc, char * argv[])
 1828     {
 1829         /* Input fd set */
 1830         fd_set InFdSet;
 1831 
 1832         /* Output fd set */
 1833         fd_set OutFdSet;
 1834 
 1835         /* Char read */
 1836         unsigned char C;
 1837 
 1838         /* Temporary string for logging */
 1839         char LogStr[TmpStrLen];
 1840 
 1841         /* Actual port settings */
 1842         struct termios PortSettings;
 1843 
 1844         /* Base timeout for stream reading */
 1845         struct timeval BTimeout;
 1846 
 1847         /* Timeout for stream reading */
 1848         struct timeval RTimeout;
 1849 
 1850         /* Pointer to timeout structure to set */
 1851         struct timeval * ETimeout = &RTimeout;
 1852 
 1853         /* Remote flow control flag */
 1854         Boolean RemoteFlowOff = False;
 1855 
 1856         /* Buffer to Device from Network */
 1857         BufferType ToDevBuf;
 1858 
 1859         /* Buffer to Network from Device */
 1860         BufferType ToNetBuf;
 1861 
 1862         /* Socket setup flag */
 1863         int SockParmEnable = 1;
 1864 
 1865         /* Generic socket parameter */
 1866         int SockParm;
 1867 
 1868         /* Out buffer clock ticks limit */
 1869         clock_t MaxBTicks;
 1870         
 1871         /* Optional argument processing indexes */
 1872         int argi = 1;
 1873         int i;
 1874 
 1875         /* Open the system log */
 1876         openlog("sredird",LOG_PID,LOG_USER);
 1877 
 1878         /* Check the command line argument count */
 1879         if (argc < 4)
 1880             {
 1881                 Usage();
 1882                 return(Error);
 1883             }
 1884 
 1885         /* Process optional switch arguments */
 1886         for (argi = 1;argv[argi][0] == '-' && argi < argc;argi++) 
 1887             {
 1888                 i = 1;
 1889                 while (argv[argi][i])
 1890                     {
 1891                         switch (argv[argi][i++])
 1892                             {
 1893                                 /* Cisco IOS compatibility */
 1894                                 case 'i':
 1895                                     if (CiscoIOSCompatible)
 1896                                         {
 1897                                             /* Already set */
 1898                                             Usage();
 1899                                             return(Error);
 1900                                         }
 1901                                     else
 1902                                         CiscoIOSCompatible = True;
 1903                                 break;
 1904                                 
 1905                                 default:
 1906                                     Usage();
 1907                                     return(Error);
 1908                                 break;
 1909                             }
 1910                     }
 1911             }
 1912 
 1913         /* Sets the log level */
 1914         MaxLogLevel = atoi(argv[argi++]);
 1915 
 1916         /* Gets device and lock file names */
 1917         DeviceName = argv[argi++];
 1918         LockFileName = argv[argi++];
 1919 
 1920         /* Retrieve the polling interval */
 1921         if (argc == argi + 1)
 1922             {
 1923                 BTimeout.tv_sec = 0;
 1924                 BTimeout.tv_usec = atol(argv[4]) * 1000;
 1925                 MaxBTicks = (BTimeout.tv_usec * CLOCKS_PER_SEC) / (1000 * 1000);
 1926 
 1927                 if (BTimeout.tv_usec <= 0)
 1928                     {
 1929                         ETimeout = NULL;
 1930                         MaxBTicks = 0;
 1931                     }
 1932             }
 1933         else
 1934             {
 1935                 BTimeout.tv_sec = 0;
 1936                 BTimeout.tv_usec = ModemStatePolling * 1000;
 1937                 MaxBTicks = (BTimeout.tv_usec * CLOCKS_PER_SEC) / (1000 * 1000);
 1938             }
 1939 
 1940         /* Logs sredird start */
 1941         LogMsg(LOG_NOTICE,"SRedird started.");
 1942 
 1943         /* Logs sredird log level */
 1944         snprintf(LogStr,TmpStrLen - 1,"Log level: %i",MaxLogLevel);
 1945         LogStr[TmpStrLen - 1] = '\0';
 1946         LogMsg(LOG_INFO,LogStr);
 1947 
 1948         /* Logs the polling interval */
 1949         snprintf(LogStr,TmpStrLen - 1,"Polling interval (ms): %u",(unsigned int) (BTimeout.tv_usec / 1000));
 1950         LogStr[TmpStrLen - 1] = '\0';
 1951         LogMsg(LOG_INFO,LogStr);
 1952 
 1953         /* Register exit and signal handler functions */
 1954         atexit(ExitFunction);
 1955         signal(SIGHUP,SignalFunction);
 1956         signal(SIGQUIT,SignalFunction);
 1957         signal(SIGABRT,SignalFunction);
 1958         signal(SIGPIPE,SignalFunction);
 1959         signal(SIGTERM,SignalFunction);
 1960 
 1961         /* Register the function to be called on break condition */
 1962         signal(SIGINT,BreakFunction);
 1963 
 1964         /* Try to lock the device */
 1965         if (HDBLockFile(LockFileName,getpid()) != LockOk)
 1966             {
 1967                 /* Lock failed */
 1968                 snprintf(LogStr,TmpStrLen - 1,"Unable to lock %s. Exiting.",LockFileName);
 1969                 LogStr[TmpStrLen - 1] = '\0';
 1970                 LogMsg(LOG_NOTICE,LogStr);
 1971                 return(Error);
 1972             }
 1973         else
 1974             {
 1975                 /* Lock succeeded */
 1976                 snprintf(LogStr,TmpStrLen - 1,"Device %s locked.",DeviceName);
 1977                 LogStr[TmpStrLen - 1] = '\0';
 1978                 LogMsg(LOG_INFO,LogStr);
 1979             }
 1980 
 1981         /* Open the device */
 1982         if ((DeviceFd = open(DeviceName,O_RDWR | O_NOCTTY | O_NDELAY,0)) == OpenError)
 1983             {
 1984                 /* Open failed */
 1985                 snprintf(LogStr,TmpStrLen - 1,"Device in use. Come back later.\r\n");
 1986                 LogStr[TmpStrLen - 1] = '\0';
 1987                 LogMsg(LOG_ERR,LogStr);
 1988                 snprintf(LogStr,TmpStrLen - 1,"Unable to open device %s. Exiting.",DeviceName);
 1989                 LogStr[TmpStrLen - 1] = '\0';
 1990                 LogMsg(LOG_ERR,LogStr);
 1991                 return(Error);
 1992             }
 1993         else
 1994             DeviceOpened = True;
 1995 
 1996         /* Get the actual port settings */
 1997         tcgetattr(DeviceFd,&InitialPortSettings);
 1998         InitPortRetrieved = True;
 1999         tcgetattr(DeviceFd,&PortSettings);
 2000 
 2001         /* Set the serial port to raw mode */
 2002         cfmakeraw(&PortSettings);
 2003 
 2004         /* Enable HANGUP on close and disable modem control line handling */
 2005         PortSettings.c_cflag = (PortSettings.c_cflag | HUPCL) | CLOCAL;
 2006 
 2007         /* Enable break handling */
 2008         PortSettings.c_iflag = (PortSettings.c_iflag & ~IGNBRK) | BRKINT;
 2009 
 2010         /* Write the port settings to device */
 2011         tcsetattr(DeviceFd,TCSANOW,&PortSettings);
 2012 
 2013         /* Reset the device fd to blocking mode */
 2014         if (fcntl(DeviceFd,F_SETFL,fcntl(DeviceFd,F_GETFL) & ~(O_NDELAY)) == OpenError)
 2015             LogMsg(LOG_ERR,"Unable to reset device to non blocking mode, ignoring.");
 2016 
 2017         /* Initialize the input buffer */
 2018         InitBuffer(&ToDevBuf);
 2019         InitBuffer(&ToNetBuf);
 2020 
 2021         /* Setup sockets for low latency and automatic keepalive;
 2022          * doesn't check if anything fails because failure doesn't prevent
 2023          * correct functioning but only provides slightly worse behaviour
 2024          */
 2025         SockParm = IPTOS_LOWDELAY;
 2026         setsockopt(STDIN_FILENO,SOL_SOCKET,SO_KEEPALIVE,&SockParmEnable,sizeof(SockParmEnable));
 2027         setsockopt(STDIN_FILENO,SOL_IP,IP_TOS,&SockParm,sizeof(SockParm));
 2028         setsockopt(STDIN_FILENO,SOL_SOCKET,SO_OOBINLINE,&SockParmEnable,sizeof(SockParmEnable));
 2029         setsockopt(STDOUT_FILENO,SOL_SOCKET,SO_KEEPALIVE,&SockParmEnable,sizeof(SockParmEnable));
 2030         setsockopt(STDOUT_FILENO,SOL_IP,IP_TOS,&SockParm,sizeof(SockParm));
 2031 
 2032         /* Make reads/writes unblocking */
 2033         ioctl(STDOUT_FILENO,FIONBIO,&SockParmEnable);
 2034         ioctl(STDIN_FILENO,FIONBIO,&SockParmEnable);
 2035         ioctl(DeviceFd,FIONBIO,&SockParmEnable);
 2036 
 2037         /* Send initial Telnet negotiations to the client */
 2038         InitTelnetStateMachine();
 2039         SendTelnetOption(&ToNetBuf,TNWILL,TN_TRANSMIT_BINARY);
 2040         tnstate[TN_TRANSMIT_BINARY].sent_will = True;
 2041         SendTelnetOption(&ToNetBuf,TNDO,TN_TRANSMIT_BINARY);
 2042         tnstate[TN_TRANSMIT_BINARY].sent_do = True;
 2043         SendTelnetOption(&ToNetBuf,TNWILL,TN_ECHO);
 2044         tnstate[TN_ECHO].sent_will = True;
 2045         SendTelnetOption(&ToNetBuf,TNWILL,TN_SUPPRESS_GO_AHEAD);
 2046         tnstate[TN_SUPPRESS_GO_AHEAD].sent_will = True;
 2047         SendTelnetOption(&ToNetBuf,TNDO,TN_SUPPRESS_GO_AHEAD);
 2048         tnstate[TN_SUPPRESS_GO_AHEAD].sent_do = True;
 2049         SendTelnetOption(&ToNetBuf,TNDO,TNCOM_PORT_OPTION);
 2050         tnstate[TNCOM_PORT_OPTION].sent_do = True;
 2051 
 2052         /* Set up fd sets */
 2053         /* Initially we have to read from all, but we only have data to send
 2054          * to the network */
 2055         FD_ZERO(&InFdSet);
 2056         FD_SET(STDIN_FILENO,&InFdSet);
 2057         FD_SET(DeviceFd,&InFdSet);
 2058         FD_ZERO(&OutFdSet);
 2059         FD_SET(STDOUT_FILENO,&OutFdSet);
 2060 
 2061         /* Set up timeout for modem status polling */
 2062         if (ETimeout != NULL)
 2063             *ETimeout = BTimeout;
 2064 
 2065         /* Main loop with fd's control */
 2066         while (True)
 2067             {
 2068                 if (select(DeviceFd + 1,&InFdSet,&OutFdSet,NULL,ETimeout) > 0)
 2069                     {
 2070                         /* Handle buffers in the following order
 2071                          *   Error
 2072                          *   Output
 2073                          *   Input
 2074                          * In other words, ensure we can write, make room, read more data
 2075                          */
 2076 
 2077                         if (FD_ISSET(DeviceFd,&OutFdSet))
 2078                             {
 2079                                 /* Write to serial port */
 2080                                 while (!IsBufferEmpty(&ToDevBuf))
 2081                                     {
 2082                                         int x;
 2083                                         C = GetFromBuffer(&ToDevBuf);
 2084                                         x = write(DeviceFd,&C,1);
 2085                                         if (x < 0 && errno == EWOULDBLOCK)
 2086                                             {
 2087                                                 PushToBuffer(&ToDevBuf,C);
 2088                                                 break;
 2089                                             }
 2090                                         else
 2091                                             if (x < 1)
 2092                                                 {
 2093                                                     LogMsg(LOG_NOTICE,"Error writing to device.");
 2094                                                     return(NoError);
 2095                                                 }
 2096                                     }
 2097                             }
 2098 
 2099                         if (FD_ISSET(STDOUT_FILENO,&OutFdSet))
 2100                             {
 2101                                 /* Write to network */
 2102                                 while (!IsBufferEmpty(&ToNetBuf))
 2103                                     {
 2104                                         int x;
 2105                                         C = GetFromBuffer(&ToNetBuf);
 2106                                         x = write(STDOUT_FILENO,&C,1);
 2107                                         if (x < 0 && errno == EWOULDBLOCK)
 2108                                             {
 2109                                                 PushToBuffer(&ToNetBuf,C);
 2110                                                 break;
 2111                                             }
 2112                                         else
 2113                                             if (x < 1)
 2114                                                 {
 2115                                                     LogMsg(LOG_NOTICE,"Error writing to network.");
 2116                                                     return(NoError);
 2117                                                 }
 2118                                     }
 2119                             }
 2120 
 2121                         if (FD_ISSET(DeviceFd,&InFdSet))
 2122                             {
 2123                                 /* Read from serial port */
 2124                                 while (!IsBufferFull(&ToNetBuf))
 2125                                     {
 2126                                         int x;
 2127                                         x = read(DeviceFd,&C,1);
 2128                                         if (x < 0 && errno == EWOULDBLOCK)
 2129                                             break;
 2130                                         else
 2131                                             if (x < 1)
 2132                                                 {
 2133                                                     LogMsg(LOG_NOTICE,"Error reading from device.");
 2134                                                     return(NoError);
 2135                                                 }
 2136                                         EscWriteChar(&ToNetBuf,C);
 2137                                     }
 2138                             }
 2139 
 2140                         if (FD_ISSET(STDIN_FILENO,&InFdSet))
 2141                             {
 2142                                 /* Read from network */
 2143                                 while (!IsBufferFull(&ToDevBuf))
 2144                                     {
 2145                                         int x;
 2146                                         x = read(STDIN_FILENO,&C,1);
 2147                                         if (x < 0 && errno == EWOULDBLOCK)
 2148                                             {
 2149                                                 break;
 2150                                             }
 2151                                         else
 2152                                             if (x < 1)
 2153                                                 {
 2154                                                     LogMsg(LOG_NOTICE,"Error reading from network.");
 2155                                                     return(NoError);
 2156                                                 }
 2157                                         EscRedirectChar(&ToNetBuf,&ToDevBuf,DeviceFd,C);
 2158                                     }
 2159                             }
 2160 
 2161                         /* Check if the buffer is not full and remote flow is off */
 2162                         if (RemoteFlowOff == True && IsBufferFull(&ToDevBuf) == False)
 2163                             {
 2164                                 /* Send a flow control resume command */
 2165                                 SendCPCFlowCommand(&ToNetBuf,TNASC_FLOWCONTROL_RESUME);
 2166                                 RemoteFlowOff = False;
 2167                             }
 2168                     }
 2169 
 2170                 /* Check the port state and notify the client if it's changed */
 2171                 if (TCPCEnabled == True && InputFlow == True)
 2172                     {
 2173                         if ((GetModemState(DeviceFd,ModemState) & ModemStateMask &
 2174                             ModemStateECMask) != (ModemState & ModemStateMask & ModemStateECMask))
 2175                             {
 2176                                 ModemState = GetModemState(DeviceFd,ModemState);
 2177                                 SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_MODEMSTATE,
 2178                                     (ModemState & ModemStateMask));
 2179                                 snprintf(LogStr,TmpStrLen - 1,"Sent modem state: %u",
 2180                                     (unsigned int) (ModemState & ModemStateMask));
 2181                                 LogStr[TmpStrLen - 1] = '\0';
 2182                                 LogMsg(LOG_DEBUG,LogStr);
 2183                             }
 2184 #ifdef COMMENT
 2185                         /* GetLineState() not yet implemented */
 2186                         if ((GetLineState(DeviceFd,LineState) & LineStateMask &
 2187                                     LineStateECMask) != (LineState & LineStateMask & LineStateECMask))
 2188                             {
 2189                                 LineState = GetLineState(DeviceFd,LineState);
 2190                                 SendCPCByteCommand(&ToNetBuf,TNASC_NOTIFY_LINESTATE,
 2191                                     (LineState & LineStateMask));
 2192                                 snprintf(LogStr,TmpStrLen - 1,"Sent line state: %u",
 2193                                     (unsigned int) (LineState & LineStateMask));
 2194                                 LogStr[TmpStrLen - 1] = '\0';
 2195                                 LogMsg(LOG_DEBUG,LogStr);
 2196                             }
 2197 #endif /* COMMENT */
 2198                     }
 2199 
 2200                 /* Resets the fd sets */
 2201                 FD_ZERO(&InFdSet);
 2202 
 2203                 /* Check if the buffer is not full */
 2204                 if (IsBufferFull(&ToDevBuf) == False)
 2205                     {
 2206                         FD_SET(STDIN_FILENO,&InFdSet);
 2207                     }
 2208                 else
 2209                     if (RemoteFlowOff == False)
 2210                         {
 2211                             /* Send a flow control suspend command */
 2212                             SendCPCFlowCommand(&ToNetBuf,TNASC_FLOWCONTROL_SUSPEND);
 2213                             RemoteFlowOff = True;
 2214                         }
 2215 
 2216                 /* If input flow has been disabled from the remote client
 2217                 don't read from the device */
 2218                 if (!IsBufferFull(&ToNetBuf) && InputFlow == True)
 2219                     FD_SET(DeviceFd,&InFdSet);
 2220 
 2221                 FD_ZERO(&OutFdSet);
 2222                 /* Check if there are characters available to write */
 2223                 if (!IsBufferEmpty(&ToDevBuf))
 2224                         FD_SET(DeviceFd,&OutFdSet);
 2225                 if (!IsBufferEmpty(&ToNetBuf))
 2226                         FD_SET(STDOUT_FILENO,&OutFdSet);
 2227 
 2228                 /* Set up timeout for modem status polling */
 2229                 if (ETimeout != NULL)
 2230                         *ETimeout = BTimeout;
 2231             }
 2232     }