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