ttynvt version 0.10
This commit is contained in:
committed by
Kim Woelders
parent
02a2149c1f
commit
e68e140ef0
+26
@@ -0,0 +1,26 @@
|
|||||||
|
# autoreconf
|
||||||
|
/aclocal.m4
|
||||||
|
/autom4te.cache/
|
||||||
|
/compile
|
||||||
|
/config.h.in
|
||||||
|
/config.h.in~
|
||||||
|
/configure
|
||||||
|
/depcomp
|
||||||
|
/install-sh
|
||||||
|
/missing
|
||||||
|
Makefile.in
|
||||||
|
|
||||||
|
# configure
|
||||||
|
/config.h
|
||||||
|
/config.log
|
||||||
|
/config.status
|
||||||
|
/stamp-h1
|
||||||
|
.deps
|
||||||
|
Makefile
|
||||||
|
|
||||||
|
# build
|
||||||
|
*.o
|
||||||
|
/ttynvt
|
||||||
|
|
||||||
|
/ttynvt-*.tar.gz
|
||||||
|
/ttynvt-*.tar.xz
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
Frank Rolsted Jensen <frj@thrane.eu>
|
||||||
|
Kim Woelders <kw@thrane.eu>
|
||||||
+4
-4
@@ -1,7 +1,7 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
of this license document, but changing it is not allowed.
|
of this license document, but changing it is not allowed.
|
||||||
@@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
|
|||||||
convey the exclusion of warranty; and each file should have at least
|
convey the exclusion of warranty; and each file should have at least
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
ttynvt
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
Copyright (C) 2018 lars-thrane-as
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -329,7 +329,7 @@ necessary. Here is a sample; alter the names:
|
|||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
{signature of Ty Coon}, 1 April 1989
|
<signature of Ty Coon>, 1 April 1989
|
||||||
Ty Coon, President of Vice
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
This General Public License does not permit incorporating your program into
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
# Build ttynvt
|
||||||
|
#
|
||||||
|
|
||||||
|
MAINTAINERCLEANFILES = \
|
||||||
|
aclocal.m4 autom4te.cache compile config.h.in config.h.in~ configure \
|
||||||
|
depcomp install-sh missing \
|
||||||
|
Makefile.in
|
||||||
|
|
||||||
|
CFLAGS_OPT = -O3
|
||||||
|
CFLAGS_WARN = -Wall -Wextra -Werror -Wno-unused-parameter
|
||||||
|
|
||||||
|
bin_PROGRAMS = ttynvt
|
||||||
|
|
||||||
|
ttynvt_SOURCES = \
|
||||||
|
ttynvt.c \
|
||||||
|
telnet_basic.c telnet_rfc2217.c telnet.h telnet_param.h
|
||||||
|
|
||||||
|
ttynvt_CPPFLAGS = -I$(top_builddir) $(FUSE_CFLAGS) $(CFLAGS_OPT) $(CFLAGS_WARN)
|
||||||
|
|
||||||
|
ttynvt_LDADD = $(FUSE_LIBS)
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
ttynvt makes a virtual serial device (tty) and connects
|
||||||
|
the device to a Network Virtual Terminal (NVT).
|
||||||
|
|
||||||
|
+-ttynvt-+------------------------+
|
||||||
|
| |\ |
|
||||||
|
| | +---------------+ |
|
||||||
|
| | | |
|
||||||
|
| | | |
|
||||||
|
/dev/ttyNVT | pty /dev/ppp pty |
|
||||||
|
| | slave | master |
|
||||||
|
| | | | | |
|
||||||
|
--------------------------------------------------
|
||||||
|
| | | | | |
|
||||||
|
| | | | | |
|
||||||
|
+--FUSE--+ +-tty--ldisc------+ TCP--->host
|
||||||
|
|
||||||
|
|
||||||
|
1 Build environment
|
||||||
|
gcc is required.
|
||||||
|
glibc must support pthreads.
|
||||||
|
libfuse - Filesystem in Userspace - development support is needed.
|
||||||
|
|
||||||
|
2 Target
|
||||||
|
The linux kernel at the target system must support FUSE (FUSE_FS=y) and
|
||||||
|
libpthread and libfuse must be installed in the root filesystem.
|
||||||
|
|
||||||
|
3 Build
|
||||||
|
$ autoreconf -vif
|
||||||
|
Example configuration for native build:
|
||||||
|
$ ./configure
|
||||||
|
Example configuration for cross build:
|
||||||
|
$ ./configure --host=ARCH-unknown-linux \
|
||||||
|
CC=PATH-TO-CROSS-GCC \
|
||||||
|
PKG_CONFIG_LIBDIR=PATH-TO-CROSS-PKG_CONFIG_LIBDIR"
|
||||||
|
or
|
||||||
|
$ ./configure --host=ARCH-unknown-linux \
|
||||||
|
CC=PATH-TO-CROSS-GCC \
|
||||||
|
LDFLAGS="-L PATH-TO-LOCATION-OF-libfuse.so"
|
||||||
|
$ make
|
||||||
|
|
||||||
|
The default target in the Makefile builds the Network Virtual Terminal.
|
||||||
|
Output name is: ttynvt.
|
||||||
|
|
||||||
|
4 Run
|
||||||
|
The application (ttynvt) installs a virtual serial device in the /dev
|
||||||
|
directory (by default: /dev/ttyNVT0).
|
||||||
|
The major/minor number of the device, the address (name/IP) and the port
|
||||||
|
number of the serial server must be specified when the application
|
||||||
|
is started (command-line options).
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
./ttynvt -M 199 -m 6 -n ttyNVT0 -S 169.254.1.1:5020
|
||||||
|
|
||||||
|
To get a list of all command-line options:
|
||||||
|
./ttynvt --help
|
||||||
|
|
||||||
|
5. Test
|
||||||
|
The serial server: ser2net (http://ser2net.sourceforge.net/) might be used
|
||||||
|
to test the virtual serial server on the target.
|
||||||
|
Install the server (ser2net) and add following line to the configuration
|
||||||
|
file (/etc/ser2net.conf):
|
||||||
|
5020:telnet:0:/dev/ttyS0:115200 remctl NONE 1STOPBIT 8DATABITS RTSCTS HANGUP_WHEN_DONE
|
||||||
|
At the server, plug-in a loopback connector in the serial port (ttyS0).
|
||||||
|
At the target, open the virtual serial port, with a termial program,
|
||||||
|
e.g minicom:
|
||||||
|
minicom -D /dev/ttyNVT0
|
||||||
|
|
||||||
|
6 Diagnostic
|
||||||
|
Add the command-line option '-D <level>' to enable logging of diagnostic information.
|
||||||
|
The log is forwarded to syslog with the debug level.
|
||||||
|
Wireshark is also very useful when debugging the interface between the client
|
||||||
|
and the server.
|
||||||
|
|
||||||
|
Ref: RFC-854 - Telnet Protocol Specification
|
||||||
|
RFC-2217 - Telnet Com Port Control Option
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
m4_define([pkg_version], [0.10])
|
||||||
|
#m4_define([pkg_revision], [005])
|
||||||
|
m4_define([pkg_version], m4_ifdef([pkg_revision], [pkg_version.pkg_revision], [pkg_version]))
|
||||||
|
|
||||||
|
AC_INIT([ttynvt],[pkg_version],[frj@thrane.eu])
|
||||||
|
AM_INIT_AUTOMAKE([foreign dist-xz])
|
||||||
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
|
|
||||||
|
AC_PROG_CC
|
||||||
|
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
|
AC_HEADER_STDC
|
||||||
|
|
||||||
|
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
|
||||||
|
define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
|
||||||
|
define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:])dnl
|
||||||
|
|
||||||
|
AC_C_BIGENDIAN
|
||||||
|
AC_C_CONST
|
||||||
|
AC_C_INLINE
|
||||||
|
|
||||||
|
AC_CHECK_SIZEOF(int, 4)
|
||||||
|
AC_CHECK_SIZEOF(long, 4)
|
||||||
|
|
||||||
|
PKG_PROG_PKG_CONFIG
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(FUSE, fuse)
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
AC_CONFIG_FILES([
|
||||||
|
Makefile
|
||||||
|
])
|
||||||
|
AC_OUTPUT
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "------------------------------------------------------------------------"
|
||||||
|
echo "$PACKAGE Version $VERSION configured"
|
||||||
|
echo "------------------------------------------------------------------------"
|
||||||
|
echo
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Lars Thrane A/S
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* Telnet interface
|
||||||
|
*/
|
||||||
|
#ifndef TELNET_H
|
||||||
|
#define TELNET_H
|
||||||
|
|
||||||
|
typedef int (srv_tx_f) (void *cctx, const void *buf, int len);
|
||||||
|
typedef int (srv_rx_f) (void *cctx, int timeout);
|
||||||
|
typedef void (srv_ms_f) (void *cctx, int status);
|
||||||
|
|
||||||
|
/* Telnet context */
|
||||||
|
typedef struct {
|
||||||
|
void *cctx; /* Client context */
|
||||||
|
|
||||||
|
srv_tx_f *srv_tx; /* Write to server */
|
||||||
|
srv_rx_f *srv_rx; /* Read from server */
|
||||||
|
srv_ms_f *srv_ms; /* Modem status from server */
|
||||||
|
|
||||||
|
unsigned int bytes_rx; /* Rx byte count */
|
||||||
|
unsigned int off_rx; /* Rx buffer offset */
|
||||||
|
unsigned char mode_telnet; /* Telnet mode */
|
||||||
|
unsigned char mode_rfc2217; /* RFC-2217 mode */
|
||||||
|
unsigned char telnet_ack[256]; /* telnet option ack counter */
|
||||||
|
} tn_ctx_t;
|
||||||
|
|
||||||
|
extern tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx, srv_rx_f * frx,
|
||||||
|
srv_ms_f * fss);
|
||||||
|
|
||||||
|
extern int telnet_open(tn_ctx_t * tcc);
|
||||||
|
|
||||||
|
extern int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen);
|
||||||
|
extern int telnet_tx(tn_ctx_t * tcc, const char *buf, int len);
|
||||||
|
|
||||||
|
extern void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm,
|
||||||
|
const void *val, int len);
|
||||||
|
|
||||||
|
extern void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
||||||
|
unsigned char *pu, int nd);
|
||||||
|
|
||||||
|
extern void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd,
|
||||||
|
const void *val, int nd);
|
||||||
|
extern void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd);
|
||||||
|
|
||||||
|
/*RFC2217 modem state*/
|
||||||
|
#define TNS_STATE_CD 0x80
|
||||||
|
#define TNS_STATE_RI 0x40
|
||||||
|
#define TNS_STATE_DSR 0x20
|
||||||
|
#define TNS_STATE_CTS 0x10
|
||||||
|
|
||||||
|
/*RFC2217 configuration commands*/
|
||||||
|
#define TNS_SET_BAUDRATE 1
|
||||||
|
#define TNS_SET_DATASIZE 2
|
||||||
|
#define TNS_SET_PARITY 3
|
||||||
|
#define TNS_SET_STOPSIZE 4
|
||||||
|
#define TNS_SET_CONTROL 5
|
||||||
|
#define TNS_SET_PURGE 12
|
||||||
|
|
||||||
|
/*RFC2217 control commands*/
|
||||||
|
#define TNS_CTL_NOFLOW 1
|
||||||
|
#define TNS_CTL_XONOFF 2
|
||||||
|
#define TNS_CTL_CTSRTS 3
|
||||||
|
#define TNS_CTL_DTR_ON 8
|
||||||
|
#define TNS_CTL_DTR_OFF 9
|
||||||
|
#define TNS_CTL_RTS_ON 11
|
||||||
|
#define TNS_CTL_RTS_OFF 12
|
||||||
|
|
||||||
|
#endif /*TELNET_H */
|
||||||
+299
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Lars Thrane A/S
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* Telnet server - Telnet protocol handling
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "telnet.h"
|
||||||
|
#include "telnet_param.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Telnet commands */
|
||||||
|
#if 0
|
||||||
|
static const char *const tn_cmd[] = {
|
||||||
|
"SE", "NOP", "MARK", "BRK", "IP", "AO", "AYT", "EC",
|
||||||
|
"EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OPT_NACK 0 /* Reject (DONT/WONT) */
|
||||||
|
#define OPT_IGNORE 1 /* Ignore the command (?) */
|
||||||
|
#define OPT_ACK 2 /* Acknowledge (DO /WILL) */
|
||||||
|
|
||||||
|
/* Telnet option support */
|
||||||
|
static const unsigned char tn_opt[256] = {
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
[TNO_BINARY] = OPT_ACK,
|
||||||
|
[TNO_SUPP_GA] = OPT_ACK,
|
||||||
|
// [TNO_TTYP] = OPT_NACK,
|
||||||
|
// [TNO_NAWS] = OPT_NACK,
|
||||||
|
// [TNO_NEO] = OPT_NACK,
|
||||||
|
[TNO_CPCO] = OPT_ACK,
|
||||||
|
// [TNO_KERMIT] = OPT_NACK,
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void _telnet_handle_req(tn_ctx_t * tcc, int cmd, int opt)
|
||||||
|
{
|
||||||
|
char buf[3];
|
||||||
|
|
||||||
|
if (tcc->telnet_ack[opt] > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (tn_opt[opt])
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case OPT_IGNORE:
|
||||||
|
return;
|
||||||
|
case OPT_ACK:
|
||||||
|
cmd = TNC_FD_DO;
|
||||||
|
break;
|
||||||
|
case OPT_NACK:
|
||||||
|
cmd = TNC_FE_DONT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[0] = TNC_FF_IAC;
|
||||||
|
buf[1] = cmd;
|
||||||
|
buf[2] = opt;
|
||||||
|
|
||||||
|
tcc->telnet_ack[opt]++;
|
||||||
|
|
||||||
|
tcc->srv_tx(tcc->cctx, buf, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _telnet_handle_resp(tn_ctx_t * tcc, int cmd, int opt)
|
||||||
|
{
|
||||||
|
if (opt == TNO_CPCO)
|
||||||
|
{
|
||||||
|
if (cmd == TNC_FD_DO)
|
||||||
|
tcc->mode_rfc2217 = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void telnet_set_opt(tn_ctx_t * tcc, int opt, int prm, const void *val, int len)
|
||||||
|
{
|
||||||
|
unsigned char buf[128], *pu = buf;
|
||||||
|
const unsigned char *pv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
*pu++ = TNC_FF_IAC;
|
||||||
|
*pu++ = TNC_FA_SB;
|
||||||
|
|
||||||
|
*pu++ = opt;
|
||||||
|
*pu++ = prm;
|
||||||
|
if (len > 0 && len <= 32)
|
||||||
|
{
|
||||||
|
pv = val;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
*pu++ = *pv;
|
||||||
|
if (*pv++ == TNC_FF_IAC)
|
||||||
|
*pu++ = TNC_FF_IAC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pu++ = TNC_FF_IAC;
|
||||||
|
*pu++ = TNC_F0_SE;
|
||||||
|
|
||||||
|
len = pu - buf;
|
||||||
|
|
||||||
|
tcc->srv_tx(tcc->cctx, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _telnet_handle_opt(tn_ctx_t * tcc, int opt,
|
||||||
|
unsigned char *pu, int nd)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case TNO_CPCO: /* RFC 2217 */
|
||||||
|
tcc->mode_rfc2217 = 1;
|
||||||
|
telnet_rfc2217_handle_opt(tcc, opt, pu, nd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_rx(tn_ctx_t * tcc, char *buf, size_t * plen)
|
||||||
|
{
|
||||||
|
char *s, *p;
|
||||||
|
unsigned char *pu;
|
||||||
|
size_t len, rem;
|
||||||
|
int np, nd;
|
||||||
|
int b1, b2;
|
||||||
|
|
||||||
|
len = *plen;
|
||||||
|
tcc->bytes_rx += len;
|
||||||
|
|
||||||
|
if (len < (size_t) tcc->off_rx)
|
||||||
|
tcc->off_rx = 0;
|
||||||
|
|
||||||
|
for (s = buf + tcc->off_rx, rem = len - tcc->off_rx; rem > 0; s = p)
|
||||||
|
{
|
||||||
|
p = memchr(s, TNC_FF_IAC, rem);
|
||||||
|
if (!p)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* We have IAC (= 0xff) */
|
||||||
|
np = rem - (p - s); /* N. chars available incl. IAC */
|
||||||
|
if (np < 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
pu = (unsigned char *)p;
|
||||||
|
b1 = pu[1];
|
||||||
|
switch (b1)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case TNC_F0_SE:
|
||||||
|
case TNC_F1_NOP:
|
||||||
|
case TNC_F2_MARK:
|
||||||
|
case TNC_F3_BRK:
|
||||||
|
case TNC_F4_IP:
|
||||||
|
case TNC_F5_AO:
|
||||||
|
case TNC_F6_AYT:
|
||||||
|
case TNC_F7_EC:
|
||||||
|
case TNC_F8_EL:
|
||||||
|
case TNC_F9_GA:
|
||||||
|
nd = 2; /* Drop 2 bytes */
|
||||||
|
goto tn_drop;
|
||||||
|
|
||||||
|
case TNC_FB_WILL:
|
||||||
|
case TNC_FC_WONT:
|
||||||
|
case TNC_FD_DO:
|
||||||
|
case TNC_FE_DONT:
|
||||||
|
if (np < 3)
|
||||||
|
goto tn_more; /* Need more */
|
||||||
|
tcc->mode_telnet = 1; /* Any such sequence activates TN */
|
||||||
|
b2 = pu[2];
|
||||||
|
if (b1 == TNC_FB_WILL)
|
||||||
|
_telnet_handle_req(tcc, b1, b2);
|
||||||
|
else if (b1 == TNC_FD_DO)
|
||||||
|
_telnet_handle_resp(tcc, b1, b2);
|
||||||
|
nd = 3; /* Drop 3 bytes */
|
||||||
|
goto tn_drop;
|
||||||
|
|
||||||
|
case TNC_FA_SB:
|
||||||
|
for (nd = 2; nd < np - 1; nd++)
|
||||||
|
{
|
||||||
|
if (pu[nd] == TNC_FF_IAC && pu[nd + 1] == TNC_F0_SE)
|
||||||
|
{
|
||||||
|
nd -= 2;
|
||||||
|
if (nd <= 0)
|
||||||
|
break;
|
||||||
|
b2 = pu[2];
|
||||||
|
tcc->mode_telnet = 1; /* Any such sequence activates TN */
|
||||||
|
_telnet_handle_opt(tcc, b2, pu + 3, nd - 1);
|
||||||
|
nd += 4;
|
||||||
|
goto tn_drop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (np < 16)
|
||||||
|
goto tn_more; /* Not done */
|
||||||
|
/* This does not look right */
|
||||||
|
rem = 0; /* Quit loop */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TNC_FF_IAC:
|
||||||
|
p++;
|
||||||
|
nd = 1; /* Drop 1 bytes */
|
||||||
|
goto tn_drop;
|
||||||
|
|
||||||
|
tn_drop:
|
||||||
|
if (!tcc->mode_telnet)
|
||||||
|
goto tn_break;
|
||||||
|
rem -= nd + (p - s);
|
||||||
|
len -= nd;
|
||||||
|
memmove(p, p + nd, rem);
|
||||||
|
break;
|
||||||
|
|
||||||
|
tn_break:
|
||||||
|
rem = 0; /* Quit loop */
|
||||||
|
break;
|
||||||
|
|
||||||
|
tn_more: /* Request more data */
|
||||||
|
tcc->off_rx = len - np;
|
||||||
|
*plen = len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcc->off_rx = 0;
|
||||||
|
*plen = len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_tx(tn_ctx_t * tcc, const char *buf, int len)
|
||||||
|
{
|
||||||
|
const char *s, *p;
|
||||||
|
int rem, nd;
|
||||||
|
|
||||||
|
for (s = buf, rem = len; rem > 0; s = p)
|
||||||
|
{
|
||||||
|
if (tcc->mode_telnet)
|
||||||
|
p = memchr(s, TNC_FF_IAC, rem);
|
||||||
|
else
|
||||||
|
p = NULL;
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
/* Send the rest */
|
||||||
|
nd = rem;
|
||||||
|
tcc->srv_tx(tcc->cctx, s, nd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nd = p - s + 1;
|
||||||
|
tcc->srv_tx(tcc->cctx, s, nd);
|
||||||
|
tcc->srv_tx(tcc->cctx, p, 1); /* One TNC_FF_IAC */
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
rem -= nd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int telnet_open(tn_ctx_t * tcc)
|
||||||
|
{
|
||||||
|
time_t t = time(NULL);;
|
||||||
|
char buf[3];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
buf[0] = TNC_FF_IAC;
|
||||||
|
buf[1] = TNC_FB_WILL;
|
||||||
|
buf[2] = TNO_CPCO;
|
||||||
|
|
||||||
|
tcc->srv_tx(tcc->cctx, buf, 3);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
res = tcc->srv_rx(tcc->cctx, 1000);
|
||||||
|
if (res <= 0)
|
||||||
|
return -1;
|
||||||
|
else if (tcc->mode_rfc2217)
|
||||||
|
return 0;
|
||||||
|
else if (t - time(NULL) > 2)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tn_ctx_t *telnet_ctx_init(void *cctx, srv_tx_f * ftx,
|
||||||
|
srv_rx_f * frx, srv_ms_f * fms)
|
||||||
|
{
|
||||||
|
tn_ctx_t *tcc;
|
||||||
|
|
||||||
|
tcc = calloc(1, sizeof(tn_ctx_t));
|
||||||
|
tcc->cctx = cctx;
|
||||||
|
tcc->srv_tx = ftx; /* Write to server */
|
||||||
|
tcc->srv_rx = frx; /* Read from server */
|
||||||
|
tcc->srv_ms = fms; /* Set modem state */
|
||||||
|
|
||||||
|
return tcc;
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Lars Thrane A/S
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* Telnet parameters
|
||||||
|
*/
|
||||||
|
#ifndef TELNET_PARAM_H
|
||||||
|
#define TELNET_PARAM_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Telnet commands
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TNC_F0_SE (0xf0) /* End of subnegotiation parameters */
|
||||||
|
#define TNC_F1_NOP (0xf1) /* No operation */
|
||||||
|
#define TNC_F2_MARK (0xf2) /* The data stream portion of a Synch.
|
||||||
|
This should always be accompanied
|
||||||
|
by a TCP Urgent notification. */
|
||||||
|
#define TNC_F3_BRK (0xf3) /* NVT character BRK. */
|
||||||
|
#define TNC_F4_IP (0xf4) /* The function IP (interrupt process) */
|
||||||
|
#define TNC_F5_AO (0xf5) /* The function AO (abort output) */
|
||||||
|
#define TNC_F6_AYT (0xf6) /* The function AYT (are you there) */
|
||||||
|
#define TNC_F7_EC (0xf7) /* The function EC (erase charceter) */
|
||||||
|
#define TNC_F8_EL (0xf8) /* The function EL (erase line) */
|
||||||
|
#define TNC_F9_GA (0xf9) /* The GA signal (go ahead) */
|
||||||
|
#define TNC_FA_SB (0xfa) /* Subnegotiation begin */
|
||||||
|
#define TNC_FB_WILL (0xfb) /* Indicates the desire to begin
|
||||||
|
performing, or confirmation that
|
||||||
|
you are now performing, the
|
||||||
|
indicated option. */
|
||||||
|
#define TNC_FC_WONT (0xfc) /* Indicates the refusal to perform,
|
||||||
|
or continue performing, the
|
||||||
|
indicated option. */
|
||||||
|
#define TNC_FD_DO (0xfd) /* Indicates the request that the
|
||||||
|
other party perform, or
|
||||||
|
confirmation that you are expecting
|
||||||
|
the other party to perform, the
|
||||||
|
indicated option. */
|
||||||
|
#define TNC_FE_DONT (0xfe) /* Indicates the demand that the
|
||||||
|
other party stop performing,
|
||||||
|
or confirmation that you are no
|
||||||
|
longer expecting the other party
|
||||||
|
to perform, the indicated option. */
|
||||||
|
#define TNC_FF_IAC (0xff) /* Interpret as Command / data byte */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Telnet options
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
|
||||||
|
*
|
||||||
|
* 0 Binary Transmission [RFC856]
|
||||||
|
* 1 Echo [RFC857]
|
||||||
|
* 2 Reconnection [DDN Protocol Handbook, ... ]
|
||||||
|
* 3 Suppress Go Ahead [RFC858]
|
||||||
|
* 4 Approx Message Size Negotiation ["The Ethernet, ... ]
|
||||||
|
* 5 Status [RFC859]
|
||||||
|
* 6 Timing Mark [RFC860]
|
||||||
|
* 7 Remote Controlled Trans and Echo [RFC726]
|
||||||
|
* 8 Output Line Width [DDN Protocol Handbook, ... ]
|
||||||
|
* 9 Output Page Size [DDN Protocol Handbook, ... ]
|
||||||
|
* 10 Output Carriage-Return Disposition [RFC652]
|
||||||
|
* 11 Output Horizontal Tab Stops [RFC653]
|
||||||
|
* 12 Output Horizontal Tab Disposition [RFC654]
|
||||||
|
* 13 Output Formfeed Disposition [RFC655]
|
||||||
|
* 14 Output Vertical Tabstops [RFC656]
|
||||||
|
* 15 Output Vertical Tab Disposition [RFC657]
|
||||||
|
* 16 Output Linefeed Disposition [RFC658]
|
||||||
|
* 17 Extended ASCII [RFC698]
|
||||||
|
* 18 Logout [RFC727]
|
||||||
|
* 19 Byte Macro [RFC735]
|
||||||
|
* 20 Data Entry Terminal [RFC1043][RFC732]
|
||||||
|
* 21 SUPDUP [RFC736][RFC734]
|
||||||
|
* 22 SUPDUP Output [RFC749]
|
||||||
|
* 23 Send Location [RFC779]
|
||||||
|
* 24 Terminal Type [RFC1091]
|
||||||
|
* 25 End of Record [RFC885]
|
||||||
|
* 26 TACACS User Identification [RFC927]
|
||||||
|
* 27 Output Marking [RFC933]
|
||||||
|
* 28 Terminal Location Number [RFC946]
|
||||||
|
* 29 Telnet 3270 Regime [RFC1041]
|
||||||
|
* 30 X.3 PAD [RFC1053]
|
||||||
|
* 31 Negotiate About Window Size [RFC1073]
|
||||||
|
* 32 Terminal Speed [RFC1079]
|
||||||
|
* 33 Remote Flow Control [RFC1372]
|
||||||
|
* 34 Linemode [RFC1184]
|
||||||
|
* 35 X Display Location [RFC1096]
|
||||||
|
* 36 Environment Option [RFC1408]
|
||||||
|
* 37 Authentication Option [RFC2941]
|
||||||
|
* 38 Encryption Option [RFC2946]
|
||||||
|
* 39 New Environment Option [RFC1572]
|
||||||
|
* 40 TN3270E [RFC2355]
|
||||||
|
* 41 XAUTH [Rob_Earhart]
|
||||||
|
* 42 CHARSET [RFC2066]
|
||||||
|
* 43 Telnet Remote Serial Port (RSP) [Robert_Barnes]
|
||||||
|
* 44 Com Port Control Option [RFC2217]
|
||||||
|
* 45 Telnet Suppress Local Echo [Wirt_Atmar]
|
||||||
|
* 46 Telnet Start TLS [Michael_Boe]
|
||||||
|
* 47 KERMIT [RFC2840]
|
||||||
|
* 48 SEND-URL [David_Croft]
|
||||||
|
* 49 FORWARD_X [Jeffrey_Altman]
|
||||||
|
* 50-137 Unassigned [IANA]
|
||||||
|
* 138 TELOPT PRAGMA LOGON [Steve_McGregory]
|
||||||
|
* 139 TELOPT SSPI LOGON [Steve_McGregory]
|
||||||
|
* 140 TELOPT PRAGMA HEARTBEAT [Steve_McGregory]
|
||||||
|
* 141-254 Unassigned
|
||||||
|
* 255 Extended-Options-List [RFC861]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TNO_BINARY 0 /* Binary Transmission */
|
||||||
|
#define TNO_ECHO 1 /* Echo */
|
||||||
|
#define TNO_SUPP_GA 3 /* Suppress Go Ahead */
|
||||||
|
#define TNO_LOGOUT 18 /* Logout */
|
||||||
|
#define TNO_TTYP 24 /* Terminal Type */
|
||||||
|
#define TNO_NAWS 31 /* Negotiate About Window Size */
|
||||||
|
#define TNO_NEO 39 /* New Environment Option */
|
||||||
|
#define TNO_CPCO 44 /* RFC 2217 */
|
||||||
|
#define TNO_KERMIT 47 /* Kermit */
|
||||||
|
|
||||||
|
#endif /* TELNET_PARAM_H */
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Lars Thrane A/S
|
||||||
|
* SPDX-License-Identifier: GPL-2.0
|
||||||
|
*
|
||||||
|
* Telnet server - RFC-2217 handling
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "telnet.h"
|
||||||
|
#include "telnet_param.h"
|
||||||
|
|
||||||
|
void telnet_rfc2217_handle_opt(tn_ctx_t * tcc, int opt,
|
||||||
|
unsigned char *pu, int nd)
|
||||||
|
{
|
||||||
|
unsigned int sub;
|
||||||
|
|
||||||
|
sub = pu[0];
|
||||||
|
switch (sub)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case 100: /* SIGNATURE */
|
||||||
|
telnet_set_opt(tcc, opt, 0, "LT-NVT", 6);
|
||||||
|
break;
|
||||||
|
case 106: /* NOTIFY-LINESTATE */
|
||||||
|
break;
|
||||||
|
case 107: /* NOTIFY-MODEMSTATE */
|
||||||
|
if (tcc->srv_ms)
|
||||||
|
tcc->srv_ms(tcc->cctx, pu[1]);
|
||||||
|
break;
|
||||||
|
case 108: /* FLOWCONTROL-SUSPEND */
|
||||||
|
case 109: /* FLOWCONTROL-RESUME */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void telnet_rfc2217_cfg(tn_ctx_t * tcc, int cmd, const void *val, int nd)
|
||||||
|
{
|
||||||
|
if (!tcc->mode_rfc2217)
|
||||||
|
return;
|
||||||
|
|
||||||
|
telnet_set_opt(tcc, TNO_CPCO, cmd, val, nd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void telnet_rfc2217_ctl(tn_ctx_t * tcc, int cmd)
|
||||||
|
{
|
||||||
|
if (!tcc->mode_rfc2217)
|
||||||
|
return;
|
||||||
|
|
||||||
|
telnet_set_opt(tcc, TNO_CPCO, TNS_SET_CONTROL, &cmd, 1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user