From ecf5fd1d59633d9fe99b4890247f988b1aa80592 Mon Sep 17 00:00:00 2001 From: wb2osz Date: Tue, 1 Jan 2019 19:59:58 -0500 Subject: [PATCH] Issue 186 - Copy KISS frames between TCP KISS clients. --- config.c | 13 ++++++++ config.h | 1 + kiss_frame.c | 39 +++++++++++++++++++++-- kissnet.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++ kissnet.h | 2 ++ 5 files changed, 140 insertions(+), 2 deletions(-) diff --git a/config.c b/config.c index 8a6ed49..b5dab4e 100644 --- a/config.c +++ b/config.c @@ -854,6 +854,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_misc_config->agwpe_port = DEFAULT_AGWPE_PORT; p_misc_config->kiss_port = DEFAULT_KISS_PORT; p_misc_config->enable_kiss_pt = 0; /* -p option */ + p_misc_config->kiss_copy = 0; /* Defaults from http://info.aprs.net/index.php?title=SmartBeaconing */ @@ -4332,6 +4333,16 @@ void config_init (char *fname, struct audio_s *p_audio_config, } } + +/* + * KISSCOPY - Data from network KISS client is copied to all others. + */ + + else if (strcasecmp(t, "KISSCOPY") == 0) { + p_misc_config->kiss_copy = 1; + } + + /* * GPSNMEA - Device name for reading from GPS receiver. */ @@ -4712,6 +4723,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_misc_config->maxframe_basic = n; } else { + p_misc_config->maxframe_basic = AX25_K_MAXFRAME_BASIC_DEFAULT; text_color_set(DW_COLOR_ERROR); dw_printf ("Line %d: Invalid MAXFRAME value outside range of %d to %d. Using default %d.\n", line, AX25_K_MAXFRAME_BASIC_MIN, AX25_K_MAXFRAME_BASIC_MAX, p_misc_config->maxframe_basic); @@ -4737,6 +4749,7 @@ void config_init (char *fname, struct audio_s *p_audio_config, p_misc_config->maxframe_extended = n; } else { + p_misc_config->maxframe_extended = AX25_K_MAXFRAME_EXTENDED_DEFAULT; text_color_set(DW_COLOR_ERROR); dw_printf ("Line %d: Invalid EMAXFRAME value outside of range %d to %d. Using default %d.\n", line, AX25_K_MAXFRAME_EXTENDED_MIN, AX25_K_MAXFRAME_EXTENDED_MAX, p_misc_config->maxframe_extended); diff --git a/config.h b/config.h index 8a3c013..baf6cb4 100644 --- a/config.h +++ b/config.h @@ -35,6 +35,7 @@ struct misc_config_s { int agwpe_port; /* Port number for the "AGW TCPIP Socket Interface" */ int kiss_port; /* Port number for the "TCP KISS" protocol. */ + int kiss_copy; /* Data from network KISS client is copied to all others. */ int enable_kiss_pt; /* Enable pseudo terminal for KISS. */ /* Want this to be off by default because it hangs */ /* after a while if nothing is reading from other end. */ diff --git a/kiss_frame.c b/kiss_frame.c index 44d01e8..78fb9a2 100644 --- a/kiss_frame.c +++ b/kiss_frame.c @@ -93,6 +93,7 @@ #include "tq.h" #include "xmit.h" #include "version.h" +#include "kissnet.h" /* In server.c. Should probably move to some misc. function file. */ @@ -506,7 +507,7 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v * debug - Debug option is selected. * * client - Client app number for TCP KISS. - * Ignored for pseudo termal and serial port. + * Should be -1 for pseudo termal and serial port. * * sendfun - Function to send something to the client application. * "Set Hardware" can send a response. @@ -522,7 +523,7 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int)) { - int port; + int port; // Should rename to chan because that's what we use everywhere else. int cmd; packet_t pp; alevel_t alevel; @@ -534,6 +535,10 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli { case KISS_CMD_DATA_FRAME: /* 0 = Data Frame */ + if (client >= 0) { + kissnet_copy (kiss_msg, kiss_len, port, cmd, client); + } + /* Special hack - Discard apparently bad data from Linux AX25. */ /* Note July 2017: There is a variant of of KISS, called SMACK, that assumes */ @@ -545,6 +550,36 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli /* Our current default is a maximum of 6 channels but it is easily */ /* increased by changing one number and recompiling. */ +// Additional information, from Mike Playle, December 2018, for Issue #42 +// +// I came across this the other day with Xastir, and took a quick look. +// The problem is fixable without the kiss_frame.c hack, which doesn't help with Xastir anyway. +// +// Workaround +// +// After the kissattach command, put the interface into CRC mode "none" with a command like this: +// +// # kissparms -c 1 -p radio +// +// Analysis +// +// The source of this behaviour is the kernel's KISS implementation: +// +// https://elixir.bootlin.com/linux/v4.9/source/drivers/net/hamradio/mkiss.c#L489 +// +// It defaults to starting in state CRC_MODE_SMACK_TEST and ending up in mode CRC_NONE +// after the first two packets, which have their framing byte modified by this code in the process. +// It looks to me like deliberate behaviour on the kernel's part. +// +// Setting the CRC mode explicitly before sending any packets stops this state machine from running. +// +// Is this a bug? I don't know - that's up to you! Maybe it would make sense for Direwolf to set +// the CRC mode itself, or to expect this behaviour and ignore these flags on the first packets +// received from the Linux pty. +// +// This workaround seems sound to me, though, so perhaps this is just a documentation issue. + + if (kiss_len > 16 && (port == 2 || port == 8) && kiss_msg[1] == 'Q' << 1 && diff --git a/kissnet.c b/kissnet.c index 3c49e67..ba7aa24 100644 --- a/kissnet.c +++ b/kissnet.c @@ -159,6 +159,7 @@ static THREAD_F connect_listen_thread (void *arg); static THREAD_F kissnet_listen_thread (void *arg); +static struct misc_config_s *s_misc_config_p; static int kiss_debug = 0; /* Print information flowing from and to client. */ @@ -204,6 +205,8 @@ void kissnet_init (struct misc_config_s *mc) pthread_t cmd_listen_tid[MAX_NET_CLIENTS]; int e; #endif + s_misc_config_p = mc; + int kiss_port = mc->kiss_port; /* default 8001 but easily changed. */ @@ -650,6 +653,90 @@ void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int f } /* end kissnet_send_rec_packet */ +/*------------------------------------------------------------------- + * + * Name: kissnet_copy + * + * Purpose: Send data from one network KISS client to all others. + * + * Inputs: in_msg - KISS frame data without the framing or escapes. + * The first byte is channel (port) and command (should be data). + * + * in_len - Number of bytes in above. + * + * chan - Channel. Redundant because it is also in first byte of kiss_msg. + * Not currently used. + * + * cmd - KISS command nybble. Redundant because it is in first byte. + * Should be 0 because I'm expecting this only for data. + * + * from_client - Number of network (TCP) client instance. + * Should be 0, 1, 2, ... + * + * + * Global In: kiss_copy - From misc. configuration. + * This enables the feature. + * + * + * Description: Send message to any attached network KISS clients, other than the one where it came from. + * Enable this by putting KISSCOPY in the configuration file. + * Note that this applies only to network (TCP) KISS clients, not serial port, or pseudo terminal. + * + * + *--------------------------------------------------------------------*/ + + +void kissnet_copy (unsigned char *in_msg, int in_len, int chan, int cmd, int from_client) +{ + unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN]; + int kiss_len; + int err; + int send_to; + + (void) chan; + (void) cmd; + + if (s_misc_config_p->kiss_copy) { + + for (send_to = 0; send_to < MAX_NET_CLIENTS; send_to++) { + + if (send_to != from_client && client_sock[send_to] != -1) { + + kiss_len = kiss_encapsulate (in_msg, in_len, kiss_buff); + + /* This has the escapes and the surrounding FENDs. */ + + if (kiss_debug) { + kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len); + } + +#if __WIN32__ + err = SOCK_SEND(client_sock[send_to], (char*)kiss_buff, kiss_len); + if (err == SOCKET_ERROR) + { + text_color_set(DW_COLOR_ERROR); + dw_printf ("\nError %d copying message to KISS client %d application. Closing connection.\n\n", WSAGetLastError(), send_to); + closesocket (client_sock[send_to]); + client_sock[send_to] = -1; + WSACleanup(); + } +#else + err = SOCK_SEND (client_sock[send_to], kiss_buff, kiss_len); + if (err <= 0) + { + text_color_set(DW_COLOR_ERROR); + dw_printf ("\nError copying message to KISS client %d application. Closing connection.\n\n", send_to); + close (client_sock[send_to]); + client_sock[send_to] = -1; + } +#endif + } // if origin and destination different. + } // loop over all KISS network clients. + } // Feature enabled. + +} /* end kissnet_copy */ + + /*------------------------------------------------------------------- * diff --git a/kissnet.h b/kissnet.h index a0681b9..ac00752 100644 --- a/kissnet.h +++ b/kissnet.h @@ -17,5 +17,7 @@ void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int void kiss_net_set_debug (int n); +void kissnet_copy (unsigned char *kiss_msg, int kiss_len, int chan, int cmd, int from_client); + /* end kissnet.h */