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