mirror of https://github.com/wb2osz/direwolf.git
Allow multiple TCP KISS ports and option for single radio channel.
This commit is contained in:
parent
81447ed49f
commit
8683ddcbd6
85
src/config.c
85
src/config.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2021 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// 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
|
||||||
|
@ -852,7 +852,14 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
||||||
|
|
||||||
memset (p_misc_config, 0, sizeof(struct misc_config_s));
|
memset (p_misc_config, 0, sizeof(struct misc_config_s));
|
||||||
p_misc_config->agwpe_port = DEFAULT_AGWPE_PORT;
|
p_misc_config->agwpe_port = DEFAULT_AGWPE_PORT;
|
||||||
p_misc_config->kiss_port = DEFAULT_KISS_PORT;
|
|
||||||
|
for (int i=0; i<MAX_KISS_TCP_PORTS; i++) {
|
||||||
|
p_misc_config->kiss_port[i] = 0; // entry not used.
|
||||||
|
p_misc_config->kiss_chan[i] = -1;
|
||||||
|
}
|
||||||
|
p_misc_config->kiss_port[0] = DEFAULT_KISS_PORT;
|
||||||
|
p_misc_config->kiss_chan[0] = -1; // all channels.
|
||||||
|
|
||||||
p_misc_config->enable_kiss_pt = 0; /* -p option */
|
p_misc_config->enable_kiss_pt = 0; /* -p option */
|
||||||
p_misc_config->kiss_copy = 0;
|
p_misc_config->kiss_copy = 0;
|
||||||
|
|
||||||
|
@ -4477,27 +4484,89 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KISSPORT - Port number for KISS over IP.
|
* KISSPORT port [ chan ] - Port number for KISS over IP.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Previously we allowed only a single TCP port for KISS.
|
||||||
|
// An increasing number of people want to run multiple radios.
|
||||||
|
// Unfortunately, most applications don't know how to deal with multi-radio TNCs.
|
||||||
|
// They ignore the channel on receive and always transmit to channel 0.
|
||||||
|
// Running multiple instances of direwolf is a work-around but this leads to
|
||||||
|
// more complex configuration and we lose the cross-channel digipeating capability.
|
||||||
|
// In release 1.7 we add a new feature to assign a single radio channel to a TCP port.
|
||||||
|
// e.g.
|
||||||
|
// KISSPORT 8001 # default, all channels. Radio channel = KISS channel.
|
||||||
|
//
|
||||||
|
// KISSPORT 7000 0 # Only radio channel 0 for receive.
|
||||||
|
// # Transmit to radio channel 0, ignoring KISS channel.
|
||||||
|
//
|
||||||
|
// KISSPORT 7001 1 # Only radio channel 1 for receive. KISS channel set to 0.
|
||||||
|
// # Transmit to radio channel 1, ignoring KISS channel.
|
||||||
|
|
||||||
|
// FIXME
|
||||||
else if (strcasecmp(t, "KISSPORT") == 0) {
|
else if (strcasecmp(t, "KISSPORT") == 0) {
|
||||||
int n;
|
int n;
|
||||||
|
int tcp_port = 0;
|
||||||
|
int chan = -1; // optional. default to all if not specified.
|
||||||
t = split(NULL,0);
|
t = split(NULL,0);
|
||||||
if (t == NULL) {
|
if (t == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Line %d: Missing port number for KISSPORT command.\n", line);
|
dw_printf ("Line %d: Missing TCP port number for KISSPORT command.\n", line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
n = atoi(t);
|
n = atoi(t);
|
||||||
if ((n >= MIN_IP_PORT_NUMBER && n <= MAX_IP_PORT_NUMBER) || n == 0) {
|
if ((n >= MIN_IP_PORT_NUMBER && n <= MAX_IP_PORT_NUMBER) || n == 0) {
|
||||||
p_misc_config->kiss_port = n;
|
tcp_port = n;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p_misc_config->kiss_port = DEFAULT_KISS_PORT;
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Line %d: Invalid port number for KISS TCPIP Socket Interface. Using %d.\n",
|
dw_printf ("Line %d: Invalid TCP port number for KISS TCPIP Socket Interface.\n", line);
|
||||||
line, p_misc_config->kiss_port);
|
dw_printf ("Use something in the range of %d to %d.\n", MIN_IP_PORT_NUMBER, MAX_IP_PORT_NUMBER);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t = split(NULL,0);
|
||||||
|
if (t != NULL) {
|
||||||
|
chan = atoi(t);
|
||||||
|
if (chan < 0 || chan >= MAX_CHANS) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Line %d: Invalid channel %d for KISSPORT command. Must be in range 0 thru %d.\n", line, chan, MAX_CHANS-1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "KISSPORT 0" is used to remove the default entry.
|
||||||
|
|
||||||
|
if (tcp_port == 0) {
|
||||||
|
p_misc_config->kiss_port[0] = 0; // Should all be wiped out?
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Try to find an empty slot.
|
||||||
|
// A duplicate TCP port number will overwrite the previous value.
|
||||||
|
|
||||||
|
int slot = -1;
|
||||||
|
for (int i = 0; i < MAX_KISS_TCP_PORTS && slot == -1; i++) {
|
||||||
|
if (p_misc_config->kiss_port[i] == tcp_port) {
|
||||||
|
slot = i;
|
||||||
|
if ( ! (slot == 0 && tcp_port == DEFAULT_KISS_PORT)) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Line %d: Warning: Duplicate TCP port %d will overwrite previous value.\n", line, tcp_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (p_misc_config->kiss_port[i] == 0) {
|
||||||
|
slot = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (slot >= 0) {
|
||||||
|
p_misc_config->kiss_port[slot] = tcp_port;
|
||||||
|
p_misc_config->kiss_chan[slot] = chan;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Line %d: Too many KISSPORT commands.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
24
src/config.h
24
src/config.h
|
@ -30,11 +30,31 @@ enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
|
||||||
|
|
||||||
|
|
||||||
#define MAX_BEACONS 30
|
#define MAX_BEACONS 30
|
||||||
|
#define MAX_KISS_TCP_PORTS (MAX_CHANS+1)
|
||||||
|
|
||||||
struct misc_config_s {
|
struct misc_config_s {
|
||||||
|
|
||||||
int agwpe_port; /* Port number for the "AGW TCPIP Socket Interface" */
|
int agwpe_port; /* TCP Port number for the "AGW TCPIP Socket Interface" */
|
||||||
int kiss_port; /* Port number for the "TCP KISS" protocol. */
|
|
||||||
|
// Previously we allowed only a single TCP port for KISS.
|
||||||
|
// An increasing number of people want to run multiple radios.
|
||||||
|
// Unfortunately, most applications don't know how to deal with multi-radio TNCs.
|
||||||
|
// They ignore the channel on receive and always transmit to channel 0.
|
||||||
|
// Running multiple instances of direwolf is a work-around but this leads to
|
||||||
|
// more complex configuration and we lose the cross-channel digipeating capability.
|
||||||
|
// In release 1.7 we add a new feature to assign a single radio channel to a TCP port.
|
||||||
|
// e.g.
|
||||||
|
// KISSPORT 8001 # default, all channels. Radio channel = KISS channel.
|
||||||
|
//
|
||||||
|
// KISSPORT 7000 0 # Only radio channel 0 for receive.
|
||||||
|
// # Transmit to radio channel 0, ignoring KISS channel.
|
||||||
|
//
|
||||||
|
// KISSPORT 7001 1 # Only radio channel 1 for receive. KISS channel set to 0.
|
||||||
|
// # Transmit to radio channel 1, ignoring KISS channel.
|
||||||
|
|
||||||
|
int kiss_port[MAX_KISS_TCP_PORTS]; /* TCP Port number for the "TCP KISS" protocol. */
|
||||||
|
int kiss_chan[MAX_KISS_TCP_PORTS]; /* Radio Channel number for this port or -1 for all. */
|
||||||
|
|
||||||
int kiss_copy; /* Data from network KISS client is copied to all others. */
|
int kiss_copy; /* Data from network KISS client is copied to all others. */
|
||||||
int enable_kiss_pt; /* Enable pseudo terminal for KISS. */
|
int enable_kiss_pt; /* Enable pseudo terminal for KISS. */
|
||||||
/* Want this to be off by default because it hangs */
|
/* Want this to be off by default because it hangs */
|
||||||
|
|
|
@ -1419,10 +1419,10 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
|
||||||
|
|
||||||
flen = ax25_pack(pp, fbuf);
|
flen = ax25_pack(pp, fbuf);
|
||||||
|
|
||||||
server_send_rec_packet (chan, pp, fbuf, flen); // AGW net protocol
|
server_send_rec_packet (chan, pp, fbuf, flen); // AGW net protocol
|
||||||
kissnet_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1); // KISS TCP
|
kissnet_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1); // KISS TCP
|
||||||
kissserial_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1); // KISS serial port
|
kissserial_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1); // KISS serial port
|
||||||
kisspt_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1); // KISS pseudo terminal
|
kisspt_send_rec_packet (chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1); // KISS pseudo terminal
|
||||||
|
|
||||||
if (A_opt_ais_to_obj && strlen(ais_obj_packet) != 0) {
|
if (A_opt_ais_to_obj && strlen(ais_obj_packet) != 0) {
|
||||||
packet_t ao_pp = ax25_from_text (ais_obj_packet, 1);
|
packet_t ao_pp = ax25_from_text (ais_obj_packet, 1);
|
||||||
|
@ -1431,9 +1431,9 @@ void app_process_rec_packet (int chan, int subchan, int slice, packet_t pp, alev
|
||||||
int ao_flen = ax25_pack(ao_pp, ao_fbuf);
|
int ao_flen = ax25_pack(ao_pp, ao_fbuf);
|
||||||
|
|
||||||
server_send_rec_packet (chan, ao_pp, ao_fbuf, ao_flen);
|
server_send_rec_packet (chan, ao_pp, ao_fbuf, ao_flen);
|
||||||
kissnet_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, -1);
|
kissnet_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, NULL, -1);
|
||||||
kissserial_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, -1);
|
kissserial_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, NULL, -1);
|
||||||
kisspt_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, -1);
|
kisspt_send_rec_packet (chan, KISS_CMD_DATA_FRAME, ao_fbuf, ao_flen, NULL, -1);
|
||||||
ax25_delete (ao_pp);
|
ax25_delete (ao_pp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ void kisspt_set_debug (int n)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client)
|
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *kps, int client)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,7 @@ static int kisspt_open_pt (void)
|
||||||
* flen - Length of raw received frame not including the FCS
|
* flen - Length of raw received frame not including the FCS
|
||||||
* or -1 for a text string.
|
* or -1 for a text string.
|
||||||
*
|
*
|
||||||
* client - Not used for pseudo terminal.
|
* kps, client - Not used for pseudo terminal.
|
||||||
* Here so that 3 related functions all have
|
* Here so that 3 related functions all have
|
||||||
* the same parameter list.
|
* the same parameter list.
|
||||||
*
|
*
|
||||||
|
@ -385,7 +385,7 @@ static int kisspt_open_pt (void)
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client)
|
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *kps, int client)
|
||||||
{
|
{
|
||||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
||||||
int kiss_len;
|
int kiss_len;
|
||||||
|
@ -591,7 +591,7 @@ static void * kisspt_listen_thread (void *arg)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = kisspt_get();
|
ch = kisspt_get();
|
||||||
kiss_rec_byte (&kf, ch, kisspt_debug, -1, kisspt_send_rec_packet);
|
kiss_rec_byte (&kf, ch, kisspt_debug, NULL, -1, kisspt_send_rec_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (void *) 0; /* Unreachable but avoids compiler warning. */
|
return (void *) 0; /* Unreachable but avoids compiler warning. */
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "kiss_frame.h" // for struct kissport_status_s
|
||||||
|
|
||||||
|
|
||||||
void kisspt_init (struct misc_config_s *misc_config);
|
void kisspt_init (struct misc_config_s *misc_config);
|
||||||
|
|
||||||
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client);
|
void kisspt_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen,
|
||||||
|
struct kissport_status_s *notused1, int notused2);
|
||||||
|
|
||||||
void kisspt_set_debug (int n);
|
void kisspt_set_debug (int n);
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,8 @@ void text_color_set (dw_color_t c)
|
||||||
|
|
||||||
#ifndef DECAMAIN
|
#ifndef DECAMAIN
|
||||||
#ifndef KISSUTIL
|
#ifndef KISSUTIL
|
||||||
static void kiss_set_hardware (int chan, char *command, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int));
|
static void kiss_set_hardware (int chan, char *command, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient));
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -340,6 +341,8 @@ int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
|
||||||
* Inputs: kf - Current state of building a frame.
|
* Inputs: kf - Current state of building a frame.
|
||||||
* ch - A byte from the input stream.
|
* ch - A byte from the input stream.
|
||||||
* debug - Activates debug output.
|
* debug - Activates debug output.
|
||||||
|
* kps - KISS TCP port status block.
|
||||||
|
* NULL for pseudo terminal and serial port.
|
||||||
* client - Client app number for TCP KISS.
|
* client - Client app number for TCP KISS.
|
||||||
* Ignored for pseudo termal and serial port.
|
* Ignored for pseudo termal and serial port.
|
||||||
* sendfun - Function to send something to the client application.
|
* sendfun - Function to send something to the client application.
|
||||||
|
@ -377,7 +380,9 @@ int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int))
|
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug,
|
||||||
|
struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient))
|
||||||
{
|
{
|
||||||
|
|
||||||
//dw_printf ("kiss_frame ( %c %02x ) \n", ch, ch);
|
//dw_printf ("kiss_frame ( %c %02x ) \n", ch, ch);
|
||||||
|
@ -420,10 +425,10 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v
|
||||||
if (strcasecmp("restart\r", (char*)(kf->noise)) == 0 ||
|
if (strcasecmp("restart\r", (char*)(kf->noise)) == 0 ||
|
||||||
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
|
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
|
||||||
// first 2 parameters don't matter when length is -1 indicating text.
|
// first 2 parameters don't matter when length is -1 indicating text.
|
||||||
(*sendfun) (0, 0, (unsigned char *)"\xc0\xc0", -1, client);
|
(*sendfun) (0, 0, (unsigned char *)"\xc0\xc0", -1, kps, client);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
(*sendfun) (0, 0, (unsigned char *)"\r\ncmd:", -1, client);
|
(*sendfun) (0, 0, (unsigned char *)"\r\ncmd:", -1, kps, client);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
kf->noise_len = 0;
|
kf->noise_len = 0;
|
||||||
|
@ -469,7 +474,7 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v
|
||||||
hex_dump (unwrapped+1, ulen-1);
|
hex_dump (unwrapped+1, ulen-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
kiss_process_msg (unwrapped, ulen, debug, client, sendfun);
|
kiss_process_msg (unwrapped, ulen, debug, kps, client, sendfun);
|
||||||
|
|
||||||
kf->state = KS_SEARCHING;
|
kf->state = KS_SEARCHING;
|
||||||
return;
|
return;
|
||||||
|
@ -506,6 +511,9 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v
|
||||||
*
|
*
|
||||||
* debug - Debug option is selected.
|
* debug - Debug option is selected.
|
||||||
*
|
*
|
||||||
|
* kps - Used only for TCP KISS.
|
||||||
|
* Should be NULL for pseudo terminal and serial port.
|
||||||
|
*
|
||||||
* client - Client app number for TCP KISS.
|
* client - Client app number for TCP KISS.
|
||||||
* Should be -1 for pseudo termal and serial port.
|
* Should be -1 for pseudo termal and serial port.
|
||||||
*
|
*
|
||||||
|
@ -519,28 +527,40 @@ void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, v
|
||||||
// Some functions are only for the TNC end.
|
// Some functions are only for the TNC end.
|
||||||
// Other functions are suitble for both TNC and client app.
|
// Other functions are suitble for both TNC and client app.
|
||||||
|
|
||||||
// This is used only by the TNC sided.
|
// This is used only by the TNC side.
|
||||||
|
|
||||||
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int))
|
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *kps, int client))
|
||||||
{
|
{
|
||||||
int port; // Should rename to chan because that's what we use everywhere else.
|
int chan;
|
||||||
int cmd;
|
int cmd;
|
||||||
packet_t pp;
|
|
||||||
alevel_t alevel;
|
alevel_t alevel;
|
||||||
|
|
||||||
port = (kiss_msg[0] >> 4) & 0xf;
|
// New in 1.7:
|
||||||
|
// We can have KISS TCP ports which convey only a single radio channel.
|
||||||
|
// This is to allow operation by applications which only know how to talk to single radio TNCs.
|
||||||
|
|
||||||
|
if (kps != NULL && kps->chan != -1) {
|
||||||
|
// Ignore channel from KISS and substitute radio channel for that KISS TCP port.
|
||||||
|
chan = kps->chan;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Normal case of getting radio channel from the KISS frame.
|
||||||
|
chan = (kiss_msg[0] >> 4) & 0xf;
|
||||||
|
}
|
||||||
cmd = kiss_msg[0] & 0xf;
|
cmd = kiss_msg[0] & 0xf;
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
case KISS_CMD_DATA_FRAME: /* 0 = Data Frame */
|
case KISS_CMD_DATA_FRAME: /* 0 = Data Frame */
|
||||||
|
|
||||||
if (client >= 0) {
|
// kissnet_copy clobbers first byte but we don't care
|
||||||
kissnet_copy (kiss_msg, kiss_len, port, cmd, client);
|
// because we have already determined channel and command.
|
||||||
}
|
|
||||||
|
kissnet_copy (kiss_msg, kiss_len, chan, cmd, kps, client);
|
||||||
|
|
||||||
/* Note July 2017: There is a variant of of KISS, called SMACK, that assumes */
|
/* Note July 2017: There is a variant of of KISS, called SMACK, that assumes */
|
||||||
/* a TNC can never have more than 8 ports. http://symek.de/g/smack.html */
|
/* a TNC can never have more than 8 channels. http://symek.de/g/smack.html */
|
||||||
/* It uses the MSB to indicate that a checksum is added. I wonder if this */
|
/* It uses the MSB to indicate that a checksum is added. I wonder if this */
|
||||||
/* is why we sometimes hear about a request to transmit on channel 8. */
|
/* is why we sometimes hear about a request to transmit on channel 8. */
|
||||||
/* Should we have a message that asks the user if SMACK is being used, */
|
/* Should we have a message that asks the user if SMACK is being used, */
|
||||||
|
@ -580,20 +600,22 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
|
|
||||||
// Would it make sense to implement SMACK? I don't think so.
|
// Would it make sense to implement SMACK? I don't think so.
|
||||||
// Adding a checksum to the KISS data offers no benefit because it is very reliable.
|
// Adding a checksum to the KISS data offers no benefit because it is very reliable.
|
||||||
// It violates the original protocol specification which states that 16 ports (radio channels) are possible.
|
// It violates the original protocol specification which states that 16 radio channels are possible.
|
||||||
|
// (Some times the term 'port' is used but I try to use 'channel' all the time because 'port'
|
||||||
|
// has too many other meanings. Serial port, TCP port, ...)
|
||||||
// SMACK imposes a limit of 8. That limit might have been OK back in 1991 but not now.
|
// SMACK imposes a limit of 8. That limit might have been OK back in 1991 but not now.
|
||||||
// There are people using more than 8 radio channels (using SDR not traditional radios) with direwolf.
|
// There are people using more than 8 radio channels (using SDR not traditional radios) with direwolf.
|
||||||
|
|
||||||
|
|
||||||
/* Verify that the port (channel) number is valid. */
|
/* Verify that the radio channel number is valid. */
|
||||||
/* Any sort of medium should be OK here. */
|
/* Any sort of medium should be OK here. */
|
||||||
|
|
||||||
if (port < 0 || port >= MAX_CHANS || save_audio_config_p->achan[port].medium == MEDIUM_NONE) {
|
if (chan < 0 || chan >= MAX_CHANS || save_audio_config_p->achan[chan].medium == MEDIUM_NONE) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Invalid transmit channel %d from KISS client app.\n", port);
|
dw_printf ("Invalid transmit channel %d from KISS client app.\n", chan);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf ("Are you using AX.25 for Linux? It might be trying to use a modified\n");
|
dw_printf ("Are you using AX.25 for Linux? It might be trying to use a modified\n");
|
||||||
dw_printf ("version of KISS which uses the port (channel) field differently than the\n");
|
dw_printf ("version of KISS which uses the channel field differently than the\n");
|
||||||
dw_printf ("original KISS protocol specification. The solution might be to use\n");
|
dw_printf ("original KISS protocol specification. The solution might be to use\n");
|
||||||
dw_printf ("a command like \"kissparms -c 1 -p radio\" to set CRC none mode.\n");
|
dw_printf ("a command like \"kissparms -c 1 -p radio\" to set CRC none mode.\n");
|
||||||
dw_printf ("Another way of doing this is pre-loading the \"kiss\" kernel module with CRC disabled:\n");
|
dw_printf ("Another way of doing this is pre-loading the \"kiss\" kernel module with CRC disabled:\n");
|
||||||
|
@ -606,7 +628,7 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (&alevel, 0xff, sizeof(alevel));
|
memset (&alevel, 0xff, sizeof(alevel));
|
||||||
pp = ax25_from_frame (kiss_msg+1, kiss_len-1, alevel);
|
packet_t pp = ax25_from_frame (kiss_msg+1, kiss_len-1, alevel);
|
||||||
if (pp == NULL) {
|
if (pp == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("ERROR - Invalid KISS data frame from client app.\n");
|
dw_printf ("ERROR - Invalid KISS data frame from client app.\n");
|
||||||
|
@ -621,10 +643,10 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
|
|
||||||
if (ax25_get_num_repeaters(pp) >= 1 &&
|
if (ax25_get_num_repeaters(pp) >= 1 &&
|
||||||
ax25_get_h(pp,AX25_REPEATER_1)) {
|
ax25_get_h(pp,AX25_REPEATER_1)) {
|
||||||
tq_append (port, TQ_PRIO_0_HI, pp);
|
tq_append (chan, TQ_PRIO_0_HI, pp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tq_append (port, TQ_PRIO_1_LO, pp);
|
tq_append (chan, TQ_PRIO_1_LO, pp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -637,13 +659,13 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set TXDELAY = %d (*10mS units = %d mS), port %d\n", kiss_msg[1], kiss_msg[1] * 10, port);
|
dw_printf ("KISS protocol set TXDELAY = %d (*10mS units = %d mS), chan %d\n", kiss_msg[1], kiss_msg[1] * 10, chan);
|
||||||
if (kiss_msg[1] < 4 || kiss_msg[1] > 100) {
|
if (kiss_msg[1] < 4 || kiss_msg[1] > 100) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Are you sure you want such an extreme value for TXDELAY?\n");
|
dw_printf ("Are you sure you want such an extreme value for TXDELAY?\n");
|
||||||
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
||||||
}
|
}
|
||||||
xmit_set_txdelay (port, kiss_msg[1]);
|
xmit_set_txdelay (chan, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_PERSISTENCE: /* 2 = Persistence */
|
case KISS_CMD_PERSISTENCE: /* 2 = Persistence */
|
||||||
|
@ -654,13 +676,13 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set Persistence = %d, port %d\n", kiss_msg[1], port);
|
dw_printf ("KISS protocol set Persistence = %d, chan %d\n", kiss_msg[1], chan);
|
||||||
if (kiss_msg[1] < 5 || kiss_msg[1] > 250) {
|
if (kiss_msg[1] < 5 || kiss_msg[1] > 250) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Are you sure you want such an extreme value for PERSIST?\n");
|
dw_printf ("Are you sure you want such an extreme value for PERSIST?\n");
|
||||||
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
||||||
}
|
}
|
||||||
xmit_set_persist (port, kiss_msg[1]);
|
xmit_set_persist (chan, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_SLOTTIME: /* 3 = SlotTime */
|
case KISS_CMD_SLOTTIME: /* 3 = SlotTime */
|
||||||
|
@ -671,13 +693,13 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set SlotTime = %d (*10mS units = %d mS), port %d\n", kiss_msg[1], kiss_msg[1] * 10, port);
|
dw_printf ("KISS protocol set SlotTime = %d (*10mS units = %d mS), chan %d\n", kiss_msg[1], kiss_msg[1] * 10, chan);
|
||||||
if (kiss_msg[1] < 2 || kiss_msg[1] > 50) {
|
if (kiss_msg[1] < 2 || kiss_msg[1] > 50) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Are you sure you want such an extreme value for SLOTTIME?\n");
|
dw_printf ("Are you sure you want such an extreme value for SLOTTIME?\n");
|
||||||
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
||||||
}
|
}
|
||||||
xmit_set_slottime (port, kiss_msg[1]);
|
xmit_set_slottime (chan, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_TXTAIL: /* 4 = TXtail */
|
case KISS_CMD_TXTAIL: /* 4 = TXtail */
|
||||||
|
@ -688,13 +710,13 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set TXtail = %d (*10mS units = %d mS), port %d\n", kiss_msg[1], kiss_msg[1] * 10, port);
|
dw_printf ("KISS protocol set TXtail = %d (*10mS units = %d mS), chan %d\n", kiss_msg[1], kiss_msg[1] * 10, chan);
|
||||||
if (kiss_msg[1] < 2) {
|
if (kiss_msg[1] < 2) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Setting TXTAIL so low is asking for trouble. You probably don't want to do this.\n");
|
dw_printf ("Setting TXTAIL so low is asking for trouble. You probably don't want to do this.\n");
|
||||||
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
dw_printf ("See \"Radio Channel - Transmit Timing\" section of User Guide for explanation.\n");
|
||||||
}
|
}
|
||||||
xmit_set_txtail (port, kiss_msg[1]);
|
xmit_set_txtail (chan, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_FULLDUPLEX: /* 5 = FullDuplex */
|
case KISS_CMD_FULLDUPLEX: /* 5 = FullDuplex */
|
||||||
|
@ -705,8 +727,8 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set FullDuplex = %d, port %d\n", kiss_msg[1], port);
|
dw_printf ("KISS protocol set FullDuplex = %d, chan %d\n", kiss_msg[1], chan);
|
||||||
xmit_set_fulldup (port, kiss_msg[1]);
|
xmit_set_fulldup (chan, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_SET_HARDWARE: /* 6 = TNC specific */
|
case KISS_CMD_SET_HARDWARE: /* 6 = TNC specific */
|
||||||
|
@ -718,11 +740,11 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
}
|
}
|
||||||
kiss_msg[kiss_len] = '\0';
|
kiss_msg[kiss_len] = '\0';
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set hardware \"%s\", port %d\n", (char*)(kiss_msg+1), port);
|
dw_printf ("KISS protocol set hardware \"%s\", chan %d\n", (char*)(kiss_msg+1), chan);
|
||||||
kiss_set_hardware (port, (char*)(kiss_msg+1), debug, client, sendfun);
|
kiss_set_hardware (chan, (char*)(kiss_msg+1), debug, kps, client, sendfun);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KISS_CMD_END_KISS: /* 15 = End KISS mode, port should be 15. */
|
case KISS_CMD_END_KISS: /* 15 = End KISS mode, channel should be 15. */
|
||||||
/* Ignore it. */
|
/* Ignore it. */
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol end KISS mode - Ignored.\n");
|
dw_printf ("KISS protocol end KISS mode - Ignored.\n");
|
||||||
|
@ -842,7 +864,8 @@ void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int cli
|
||||||
|
|
||||||
#ifndef KISSUTIL
|
#ifndef KISSUTIL
|
||||||
|
|
||||||
static void kiss_set_hardware (int chan, char *command, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int))
|
static void kiss_set_hardware (int chan, char *command, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient))
|
||||||
{
|
{
|
||||||
char *param;
|
char *param;
|
||||||
char response[100];
|
char response[100];
|
||||||
|
@ -860,7 +883,7 @@ static void kiss_set_hardware (int chan, char *command, int debug, int client, v
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf (response, sizeof(response), "DIREWOLF %d.%d", MAJOR_VERSION, MINOR_VERSION);
|
snprintf (response, sizeof(response), "DIREWOLF %d.%d", MAJOR_VERSION, MINOR_VERSION);
|
||||||
(*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), client);
|
(*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), kps, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (strcmp(command, "TXBUF") == 0) { /* TXBUF - Number of bytes in transmit queue. */
|
else if (strcmp(command, "TXBUF") == 0) { /* TXBUF - Number of bytes in transmit queue. */
|
||||||
|
@ -872,7 +895,7 @@ static void kiss_set_hardware (int chan, char *command, int debug, int client, v
|
||||||
|
|
||||||
int n = tq_count (chan, -1, "", "", 1);
|
int n = tq_count (chan, -1, "", "", 1);
|
||||||
snprintf (response, sizeof(response), "TXBUF:%d", n);
|
snprintf (response, sizeof(response), "TXBUF:%d", n);
|
||||||
(*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), client);
|
(*sendfun) (chan, KISS_CMD_SET_HARDWARE, (unsigned char *)response, strlen(response), kps, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
|
||||||
/* kiss_frame.h */
|
/* kiss_frame.h */
|
||||||
|
|
||||||
|
#ifndef KISS_FRAME_H
|
||||||
|
#define KISS_FRAME_H
|
||||||
|
|
||||||
|
|
||||||
#include "audio.h" /* for struct audio_s */
|
#include "audio.h" /* for struct audio_s */
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,6 +65,40 @@ typedef struct kiss_frame_s {
|
||||||
} kiss_frame_t;
|
} kiss_frame_t;
|
||||||
|
|
||||||
|
|
||||||
|
// This is used only for TCPKISS but it put in kissnet.h,
|
||||||
|
// there would be a circular dependecy between the two header files.
|
||||||
|
// Each KISS TCP port has its own status block.
|
||||||
|
|
||||||
|
struct kissport_status_s {
|
||||||
|
|
||||||
|
struct kissport_status_s *pnext; // To next in list.
|
||||||
|
|
||||||
|
volatile int arg2; // temp for passing second arg into
|
||||||
|
// kissnet_listen_thread
|
||||||
|
|
||||||
|
int tcp_port; // default 8001
|
||||||
|
|
||||||
|
int chan; // Radio channel for this tcp port.
|
||||||
|
// -1 for all.
|
||||||
|
|
||||||
|
// The default is a limit of 3 client applications at the same time.
|
||||||
|
// You can increase the limit by changing the line below.
|
||||||
|
// A larger number consumes more resources so don't go crazy by making it larger than needed.
|
||||||
|
|
||||||
|
#define MAX_NET_CLIENTS 3
|
||||||
|
|
||||||
|
int client_sock[MAX_NET_CLIENTS];
|
||||||
|
/* File descriptor for socket for */
|
||||||
|
/* communication with client application. */
|
||||||
|
/* Set to -1 if not connected. */
|
||||||
|
/* (Don't use SOCKET type because it is unsigned.) */
|
||||||
|
|
||||||
|
kiss_frame_t kf[MAX_NET_CLIENTS];
|
||||||
|
/* Accumulated KISS frame and state of decoder. */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef KISSUTIL
|
#ifndef KISSUTIL
|
||||||
void kiss_frame_init (struct audio_s *pa);
|
void kiss_frame_init (struct audio_s *pa);
|
||||||
#endif
|
#endif
|
||||||
|
@ -69,12 +107,18 @@ int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out);
|
||||||
|
|
||||||
int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out);
|
int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out);
|
||||||
|
|
||||||
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int));
|
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient));
|
||||||
|
|
||||||
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
||||||
|
|
||||||
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int));
|
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient));
|
||||||
|
|
||||||
void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int msg_len);
|
void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int msg_len);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // KISS_FRAME_H
|
||||||
|
|
||||||
|
|
||||||
/* end kiss_frame.h */
|
/* end kiss_frame.h */
|
||||||
|
|
516
src/kissnet.c
516
src/kissnet.c
|
@ -1,7 +1,6 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
// Copyright (C) 2011-2014, 2015, 2017, 2021 John Langner, WB2OSZ
|
||||||
// Copyright (C) 2011-2014, 2015, 2017 John Langner, WB2OSZ
|
|
||||||
//
|
//
|
||||||
// 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
|
||||||
|
@ -87,6 +86,83 @@
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Separate TCP ports per radio:
|
||||||
|
|
||||||
|
An increasing number of people are using multiple radios.
|
||||||
|
direwolf is capable of handling many radio channels and
|
||||||
|
provides cross-band repeating, etc.
|
||||||
|
Maybe a single stereo audio interface is used for 2 radios.
|
||||||
|
|
||||||
|
+------------+ tcp 8001, all channels
|
||||||
|
Radio A -------- | | -------------------------- Application A
|
||||||
|
| direwolf |
|
||||||
|
Radio B -------- | | -------------------------- Application B
|
||||||
|
+------------+ tcp 8001, all channels
|
||||||
|
|
||||||
|
The KISS protocol has a 4 bit field for the TNC port (which I prefer to
|
||||||
|
call channel because port has too many different meanings).
|
||||||
|
direwolf handles this fine. However, most applications were written assuming
|
||||||
|
that a TNC could only talk to a single radio. On reception, they ignore the
|
||||||
|
channel in the KISS frame. For transmit, the channel is always set to 0.
|
||||||
|
|
||||||
|
Many people are using the work-around of two separate instances of direwolf.
|
||||||
|
|
||||||
|
+------------+ tcp 8001, KISS ch 0
|
||||||
|
Radio A -------- | direwolf | -------------------------- Application A
|
||||||
|
+------------+
|
||||||
|
|
||||||
|
+------------+ tcp 8002, KISS ch 0
|
||||||
|
Radio B -------- | direwolf | -------------------------- Application B
|
||||||
|
+------------+
|
||||||
|
|
||||||
|
|
||||||
|
Or they might be using a single application that knows how to talk to multiple
|
||||||
|
single port TNCs. But they don't know how to multiplex multiple channels
|
||||||
|
thru a single KISS stream.
|
||||||
|
|
||||||
|
+------------+ tcp 8001, KISS ch 0
|
||||||
|
Radio A -------- | direwolf | ------------------------
|
||||||
|
+------------+ \
|
||||||
|
-- Application
|
||||||
|
+------------+ tcp 8002, KISS ch 0 /
|
||||||
|
Radio B -------- | direwolf | ------------------------
|
||||||
|
+------------+
|
||||||
|
|
||||||
|
Using two different instances of direwolf means more complex configuration
|
||||||
|
and loss of cross-channel digipeating. It is possible to use a stereo
|
||||||
|
audio interface but some ALSA magic is required to make it look like two
|
||||||
|
independent virtual mono interfaces.
|
||||||
|
|
||||||
|
In version 1.7, we add the capability of multiple KISS TCP ports, each for
|
||||||
|
a single radio channel. e.g.
|
||||||
|
|
||||||
|
KISSPORT 8001 1
|
||||||
|
KISSPORT 8002 2
|
||||||
|
|
||||||
|
Now can use a single instance of direwolf.
|
||||||
|
|
||||||
|
|
||||||
|
+------------+ tcp 8001, KISS ch 0
|
||||||
|
Radio A -------- | | -------------------------- Application A
|
||||||
|
| direwolf |
|
||||||
|
Radio B -------- | | -------------------------- Application B
|
||||||
|
+------------+ tcp 8002, KISS ch 0
|
||||||
|
|
||||||
|
When receiving, the KISS channel is set to 0.
|
||||||
|
- only radio channel 1 would be sent over tcp port 8001.
|
||||||
|
- only radio channel 2 would be sent over tcp port 8001.
|
||||||
|
|
||||||
|
When transmitting, the KISS channel is ignored.
|
||||||
|
- frames from tcp port 8001 are transmitted on radio channel 1.
|
||||||
|
- frames from tcp port 8002 are transmitted on radio channel 2.
|
||||||
|
|
||||||
|
Of course, you could also use an application, capable of connecting to
|
||||||
|
multiple single radio TNCs. Separate TCP ports actually go to the
|
||||||
|
same direwolf instance.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Native Windows: Use the Winsock interface.
|
* Native Windows: Use the Winsock interface.
|
||||||
|
@ -127,25 +203,6 @@
|
||||||
void hex_dump (unsigned char *p, int len); // This should be in a .h file.
|
void hex_dump (unsigned char *p, int len); // This should be in a .h file.
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Early on we allowed one AGW connection and one KISS TCP connection at a time.
|
|
||||||
* In version 1.1, we allowed multiple concurrent client apps to attach with the AGW network protocol.
|
|
||||||
* In Version 1.5, we do essentially the same here to allow multiple concurrent KISS TCP clients.
|
|
||||||
* The default is a limit of 3 client applications at the same time.
|
|
||||||
* You can increase the limit by changing the line below.
|
|
||||||
* A larger number consumes more resources so don't go crazy by making it larger than needed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAX_NET_CLIENTS 3
|
|
||||||
|
|
||||||
static int client_sock[MAX_NET_CLIENTS];
|
|
||||||
/* File descriptor for socket for */
|
|
||||||
/* communication with client application. */
|
|
||||||
/* Set to -1 if not connected. */
|
|
||||||
/* (Don't use SOCKET type because it is unsigned.) */
|
|
||||||
|
|
||||||
static kiss_frame_t kf[MAX_NET_CLIENTS];
|
|
||||||
/* Accumulated KISS frame and state of decoder. */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -162,6 +219,12 @@ static THREAD_F kissnet_listen_thread (void *arg);
|
||||||
|
|
||||||
static struct misc_config_s *s_misc_config_p;
|
static struct misc_config_s *s_misc_config_p;
|
||||||
|
|
||||||
|
|
||||||
|
// Each TCP port has its own status block.
|
||||||
|
// There is a variable number so use a linked list.
|
||||||
|
|
||||||
|
static struct kissport_status_s *all_ports = NULL;
|
||||||
|
|
||||||
static int kiss_debug = 0; /* Print information flowing from and to client. */
|
static int kiss_debug = 0; /* Print information flowing from and to client. */
|
||||||
|
|
||||||
void kiss_net_set_debug (int n)
|
void kiss_net_set_debug (int n)
|
||||||
|
@ -177,11 +240,9 @@ void kiss_net_set_debug (int n)
|
||||||
*
|
*
|
||||||
* Purpose: Set up a server to listen for connection requests from
|
* Purpose: Set up a server to listen for connection requests from
|
||||||
* an application such as Xastir or APRSIS32.
|
* an application such as Xastir or APRSIS32.
|
||||||
|
* This is called once from the main program.
|
||||||
*
|
*
|
||||||
* Inputs: mc->kiss_port - TCP port for server.
|
* Inputs: mc->kiss_port - TCP port for server.
|
||||||
* Main program has default of 8000 but allows
|
|
||||||
* an alternative to be specified on the command line
|
|
||||||
*
|
|
||||||
* 0 means disable. New in version 1.2.
|
* 0 means disable. New in version 1.2.
|
||||||
*
|
*
|
||||||
* Outputs:
|
* Outputs:
|
||||||
|
@ -193,8 +254,29 @@ void kiss_net_set_debug (int n)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static void kissnet_init_one (struct kissport_status_s *kps);
|
||||||
|
|
||||||
void kissnet_init (struct misc_config_s *mc)
|
void kissnet_init (struct misc_config_s *mc)
|
||||||
|
{
|
||||||
|
s_misc_config_p = mc;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_KISS_TCP_PORTS; i++) {
|
||||||
|
if (mc->kiss_port[i] != 0) {
|
||||||
|
struct kissport_status_s *kps = calloc(sizeof(struct kissport_status_s), 1);
|
||||||
|
|
||||||
|
kps->tcp_port = mc->kiss_port[i];
|
||||||
|
kps->chan = mc->kiss_chan[i];
|
||||||
|
kissnet_init_one (kps);
|
||||||
|
|
||||||
|
// Add to list.
|
||||||
|
kps->pnext = all_ports;
|
||||||
|
all_ports = kps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void kissnet_init_one (struct kissport_status_s *kps)
|
||||||
{
|
{
|
||||||
int client;
|
int client;
|
||||||
|
|
||||||
|
@ -206,23 +288,22 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
|
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
|
||||||
int e;
|
int e;
|
||||||
#endif
|
#endif
|
||||||
s_misc_config_p = mc;
|
|
||||||
|
|
||||||
int kiss_port = mc->kiss_port; /* default 8001 but easily changed. */
|
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("kissnet_init ( %d )\n", kiss_port);
|
dw_printf ("kissnet_init ( tcp port %d, radio chan = %d )\n", kps->tcp_port, kps->chan);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||||
client_sock[client] = -1;
|
kps->client_sock[client] = -1;
|
||||||
memset (&(kf[client]), 0, sizeof(kf[client]));
|
memset (&(kps->kf[client]), 0, sizeof(kps->kf[client]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kiss_port == 0) {
|
if (kps->tcp_port == 0) {
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("Disabled KISS network client port.\n");
|
dw_printf ("Disabled KISS network client port.\n");
|
||||||
return;
|
return;
|
||||||
|
@ -232,17 +313,18 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
* This waits for a client to connect and sets client_sock[n].
|
* This waits for a client to connect and sets client_sock[n].
|
||||||
*/
|
*/
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
connect_listen_th = (HANDLE)_beginthreadex (NULL, 0, connect_listen_thread, (void *)(ptrdiff_t)kiss_port, 0, NULL);
|
connect_listen_th = (HANDLE)_beginthreadex (NULL, 0, connect_listen_thread, (void *)kps, 0, NULL);
|
||||||
if (connect_listen_th == NULL) {
|
if (connect_listen_th == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create KISS socket connect listening thread\n");
|
dw_printf ("Could not create KISS socket connect listening thread for tcp port %d, radio chan %d\n", kps->tcp_port, kps->chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
e = pthread_create (&connect_listen_tid, NULL, connect_listen_thread, (void *)(ptrdiff_t)kiss_port);
|
e = pthread_create (&connect_listen_tid, NULL, connect_listen_thread, (void *)kps);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror("Could not create KISS socket connect listening thread");
|
perror("Could not create KISS socket connect listening thread");
|
||||||
|
dw_printf ("for tcp port %d, radio chan %d\n", kps->tcp_port, kps->chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -254,15 +336,17 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
*/
|
*/
|
||||||
for (client = 0; client < MAX_NET_CLIENTS; client++) {
|
for (client = 0; client < MAX_NET_CLIENTS; client++) {
|
||||||
|
|
||||||
|
kps->arg2 = client;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, kissnet_listen_thread, (void*)(ptrdiff_t)client, 0, NULL);
|
cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, kissnet_listen_thread, (void*)kps, 0, NULL);
|
||||||
if (cmd_listen_th[client] == NULL) {
|
if (cmd_listen_th[client] == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create KISS command listening thread for client %d\n", client);
|
dw_printf ("Could not create KISS command listening thread for client %d\n", client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
e = pthread_create (&(cmd_listen_tid[client]), NULL, kissnet_listen_thread, (void *)(ptrdiff_t)client);
|
e = pthread_create (&(cmd_listen_tid[client]), NULL, kissnet_listen_thread, (void *)kps);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create KISS command listening thread for client %d\n", client);
|
dw_printf ("Could not create KISS command listening thread for client %d\n", client);
|
||||||
|
@ -271,6 +355,18 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// Wait for new thread to get content of arg2 before reusing it for the next thread create.
|
||||||
|
|
||||||
|
int timer = 0;
|
||||||
|
while (kps->arg2 >= 0) {
|
||||||
|
SLEEP_MS(10);
|
||||||
|
timer++;
|
||||||
|
if (timer > 100) { // 1 second - thread did not start
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("KISS data listening thread did not start for tcp port %d, client slot %d\n", kps->tcp_port, client);
|
||||||
|
kps->arg2 = -1; // Keep moving along.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,9 +377,7 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
*
|
*
|
||||||
* Purpose: Wait for a connection request from an application.
|
* Purpose: Wait for a connection request from an application.
|
||||||
*
|
*
|
||||||
* Inputs: arg - TCP port for server.
|
* Inputs: arg - KISS port status block.
|
||||||
* Main program has default of 8001 but allows
|
|
||||||
* an alternative to be specified on the command line
|
|
||||||
*
|
*
|
||||||
* Outputs: client_sock - File descriptor for communicating with client app.
|
* Outputs: client_sock - File descriptor for communicating with client app.
|
||||||
*
|
*
|
||||||
|
@ -296,20 +390,22 @@ void kissnet_init (struct misc_config_s *mc)
|
||||||
|
|
||||||
static THREAD_F connect_listen_thread (void *arg)
|
static THREAD_F connect_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
|
struct kissport_status_s *kps = arg;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
struct addrinfo *ai = NULL;
|
struct addrinfo *ai = NULL;
|
||||||
int err;
|
int err;
|
||||||
char kiss_port_str[12];
|
char tcp_port_str[12];
|
||||||
|
|
||||||
SOCKET listen_sock;
|
SOCKET listen_sock;
|
||||||
WSADATA wsadata;
|
WSADATA wsadata;
|
||||||
|
|
||||||
snprintf (kiss_port_str, sizeof(kiss_port_str), "%d", (int)(ptrdiff_t)arg);
|
snprintf (tcp_port_str, sizeof(tcp_port_str), "%d", kps->tcp_port);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("DEBUG: kissnet port = %d = '%s'\n", (int)(ptrdiff_t)arg, kiss_port_str);
|
dw_printf ("DEBUG: kissnet port = %d = '%s'\n", (int)(ptrdiff_t)arg, tcp_port_str);
|
||||||
#endif
|
#endif
|
||||||
err = WSAStartup (MAKEWORD(2,2), &wsadata);
|
err = WSAStartup (MAKEWORD(2,2), &wsadata);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
@ -332,7 +428,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
hints.ai_protocol = IPPROTO_TCP;
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
hints.ai_flags = AI_PASSIVE;
|
hints.ai_flags = AI_PASSIVE;
|
||||||
|
|
||||||
err = getaddrinfo(NULL, kiss_port_str, &hints, &ai);
|
err = getaddrinfo(NULL, tcp_port_str, &hints, &ai);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("getaddrinfo failed: %d\n", err);
|
dw_printf("getaddrinfo failed: %d\n", err);
|
||||||
|
@ -350,14 +446,14 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf("Binding to port %s ... \n", kiss_port_str);
|
dw_printf("Binding to port %s ... \n", tcp_port_str);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
err = bind( listen_sock, ai->ai_addr, (int)ai->ai_addrlen);
|
err = bind( listen_sock, ai->ai_addr, (int)ai->ai_addrlen);
|
||||||
if (err == SOCKET_ERROR) {
|
if (err == SOCKET_ERROR) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("Bind failed with error: %d\n", WSAGetLastError()); // TODO: provide corresponding text.
|
dw_printf("Bind failed with error: %d\n", WSAGetLastError()); // TODO: provide corresponding text.
|
||||||
dw_printf("Some other application is probably already using port %s.\n", kiss_port_str);
|
dw_printf("Some other application is probably already using port %s.\n", tcp_port_str);
|
||||||
dw_printf("Try using a different port number with KISSPORT in the configuration file.\n");
|
dw_printf("Try using a different port number with KISSPORT in the configuration file.\n");
|
||||||
freeaddrinfo(ai);
|
freeaddrinfo(ai);
|
||||||
closesocket(listen_sock);
|
closesocket(listen_sock);
|
||||||
|
@ -369,7 +465,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf("opened KISS socket as fd (%d) on port (%s) for stream i/o\n", listen_sock, kiss_port_str );
|
dw_printf("opened KISS socket as fd (%d) on port (%s) for stream i/o\n", listen_sock, tcp_port_str );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -379,7 +475,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
|
|
||||||
client = -1;
|
client = -1;
|
||||||
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
||||||
if (client_sock[c] <= 0) {
|
if (kps->client_sock[c] <= 0) {
|
||||||
client = c;
|
client = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,11 +493,16 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("Ready to accept KISS TCP client application %d on port %s ...\n", client, kiss_port_str);
|
if (kps->chan == -1) {
|
||||||
|
dw_printf("Ready to accept KISS TCP client application %d on port %s ...\n", client, tcp_port_str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dw_printf("Ready to accept KISS TCP client application %d on port %s (radio channel %d) ...\n", client, tcp_port_str, kps->chan);
|
||||||
|
}
|
||||||
|
|
||||||
client_sock[client] = accept(listen_sock, NULL, NULL);
|
kps->client_sock[client] = accept(listen_sock, NULL, NULL);
|
||||||
|
|
||||||
if (client_sock[client] == -1) {
|
if (kps->client_sock[client] == -1) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
||||||
closesocket(listen_sock);
|
closesocket(listen_sock);
|
||||||
|
@ -410,10 +511,15 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("\nAttached to KISS TCP client application %d ...\n\n", client);
|
if (kps->chan == -1) {
|
||||||
|
dw_printf("\nAttached to KISS TCP client application %d on port %s ...\n\n", client, tcp_port_str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dw_printf("\nAttached to KISS TCP client application %d on port %s (radio channel %d) ...\n\n", client, tcp_port_str, kps->chan);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the state and buffer.
|
// Reset the state and buffer.
|
||||||
memset (&(kf[client]), 0, sizeof(kf[client]));
|
memset (&(kps->kf[client]), 0, sizeof(kps->kf[client]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
||||||
|
@ -421,12 +527,11 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#else /* End of Windows case, now Linux. */
|
#else /* End of Windows case, now Linux / Unix / Mac OSX. */
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_in sockaddr; /* Internet socket address stuct */
|
struct sockaddr_in sockaddr; /* Internet socket address stuct */
|
||||||
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
|
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
|
||||||
int kiss_port = (int)(ptrdiff_t)arg;
|
|
||||||
int listen_sock;
|
int listen_sock;
|
||||||
int bcopt = 1;
|
int bcopt = 1;
|
||||||
|
|
||||||
|
@ -446,19 +551,19 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
setsockopt (listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&bcopt, 4);
|
setsockopt (listen_sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&bcopt, 4);
|
||||||
|
|
||||||
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
sockaddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
sockaddr.sin_port = htons(kiss_port);
|
sockaddr.sin_port = htons(kps->tcp_port);
|
||||||
sockaddr.sin_family = AF_INET;
|
sockaddr.sin_family = AF_INET;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf("Binding to port %d ... \n", kiss_port);
|
dw_printf("Binding to port %d ... \n", kps->tcp_port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (bind(listen_sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == -1) {
|
if (bind(listen_sock,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == -1) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("Bind failed with error: %d\n", errno);
|
dw_printf("Bind failed with error: %d\n", errno);
|
||||||
dw_printf("%s\n", strerror(errno));
|
dw_printf("%s\n", strerror(errno));
|
||||||
dw_printf("Some other application is probably already using port %d.\n", kiss_port);
|
dw_printf("Some other application is probably already using port %d.\n", kps->tcp_port);
|
||||||
dw_printf("Try using a different port number with KISSPORT in the configuration file.\n");
|
dw_printf("Try using a different port number with KISSPORT in the configuration file.\n");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
@ -477,7 +582,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
|
|
||||||
client = -1;
|
client = -1;
|
||||||
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
||||||
if (client_sock[c] <= 0) {
|
if (kps->client_sock[c] <= 0) {
|
||||||
client = c;
|
client = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -492,15 +597,25 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("Ready to accept KISS TCP client application %d on port %d ...\n", client, kiss_port);
|
if (kps->chan == -1) {
|
||||||
|
dw_printf("Ready to accept KISS TCP client application %d on port %s ...\n", client, tcp_port_str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dw_printf("Ready to accept KISS TCP client application %d on port %s (radio channel %d) ...\n", client, tcp_port_str, kps->chan);
|
||||||
|
}
|
||||||
|
|
||||||
client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
|
kps->client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("\nAttached to KISS TCP client application %d...\n\n", client);
|
if (kps->chan == -1) {
|
||||||
|
dw_printf("\nAttached to KISS TCP client application %d on port %s ...\n\n", client, tcp_port_str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dw_printf("\nAttached to KISS TCP client application %d on port %s (radio channel %d) ...\n\n", client, tcp_port_str, kps->chan);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the state and buffer.
|
// Reset the state and buffer.
|
||||||
memset (&(kf[client]), 0, sizeof(kf[client]));
|
memset (&(kps->kf[client]), 0, sizeof(kps->kf[client]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
||||||
|
@ -517,7 +632,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
*
|
*
|
||||||
* Name: kissnet_send_rec_packet
|
* Name: kissnet_send_rec_packet
|
||||||
*
|
*
|
||||||
* Purpose: Send a received packet to the client app.
|
* Purpose: Send a packet, received over the radio, to the client app.
|
||||||
*
|
*
|
||||||
* Inputs: chan - Channel number where packet was received.
|
* Inputs: chan - Channel number where packet was received.
|
||||||
* 0 = first, 1 = second if any.
|
* 0 = first, 1 = second if any.
|
||||||
|
@ -537,119 +652,131 @@ static THREAD_F connect_listen_thread (void *arg)
|
||||||
* it is using a traditional TNC and tries to put it
|
* it is using a traditional TNC and tries to put it
|
||||||
* into KISS mode.
|
* into KISS mode.
|
||||||
*
|
*
|
||||||
* tcpclient - It is possible to have more than client attached
|
* onlykps - KISS TCP status block pointer or NULL.
|
||||||
|
*
|
||||||
|
* onlyclient - It is possible to have more than client attached
|
||||||
* at the same time with TCP KISS.
|
* at the same time with TCP KISS.
|
||||||
* When a frame is received from the radio we want it
|
* Starting with version 1.7 we can have multiple TCP ports.
|
||||||
* to go to all of the clients. In this case specify -1.
|
* When a frame is received from the radio we normally want it
|
||||||
|
* to go to all of the clients.
|
||||||
|
* In this case specify NULL for onlykps and -1 tcp client.
|
||||||
* When responding to a command from the client, we want
|
* When responding to a command from the client, we want
|
||||||
* to send only to that one client app. In this case
|
* to send only to that one client app. In this case
|
||||||
* use the value 0 .. MAX_NET_CLIENTS-1.
|
* a non NULL kps and onlyclient >= 0.
|
||||||
*
|
*
|
||||||
* Description: Send message to client(s) if connected.
|
* Description: Send message to client(s) if connected.
|
||||||
* Disconnect from client, and notify user, if any error.
|
* Disconnect from client, and notify user, if any error.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen,
|
||||||
void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int tcpclient)
|
struct kissport_status_s *onlykps, int onlyclient)
|
||||||
{
|
{
|
||||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
||||||
int kiss_len;
|
int kiss_len;
|
||||||
int err;
|
int err;
|
||||||
int first, last, client;
|
|
||||||
|
|
||||||
// Something received over the radio would be sent to all attached clients.
|
// Something received over the radio would normally be sent to all attached clients.
|
||||||
// However, there are times we want to send a response only to a particular client.
|
// However, there are times we want to send a response only to a particular client.
|
||||||
// In the case of a serial port or pseudo terminal, there is only one potential client.
|
// In the case of a serial port or pseudo terminal, there is only one potential client.
|
||||||
// so the response would be sent to only one place. A new parameter has been added for this.
|
// so the response would be sent to only one place. A new parameter has been added for this.
|
||||||
|
|
||||||
if (tcpclient >= 0 && tcpclient < MAX_NET_CLIENTS) {
|
for (struct kissport_status_s *kps = all_ports; kps != NULL; kps = kps->pnext) {
|
||||||
first = tcpclient;
|
|
||||||
last = tcpclient;
|
|
||||||
}
|
|
||||||
else if (tcpclient == -1) {
|
|
||||||
first = 0;
|
|
||||||
last = MAX_NET_CLIENTS - 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("KISS TCP: Internal error, kissnet_send_rec_packet, tcpclient = %d.\n", tcpclient);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (onlykps == NULL || kps == onlykps) {
|
||||||
|
|
||||||
for (client = first; client <= last; client++) {
|
for (int client = 0; client < MAX_NET_CLIENTS; client++) {
|
||||||
|
|
||||||
if (client_sock[client] != -1) {
|
if (onlyclient == -1 || client == onlyclient) {
|
||||||
|
|
||||||
if (flen < 0) {
|
if (kps->client_sock[client] != -1) {
|
||||||
|
|
||||||
|
if (flen < 0) {
|
||||||
|
|
||||||
// A client app might think it is attached to a traditional TNC.
|
// A client app might think it is attached to a traditional TNC.
|
||||||
// It might try sending commands over and over again trying to get the TNC into KISS mode.
|
// It might try sending commands over and over again trying to get the TNC into KISS mode.
|
||||||
// We recognize this attempt and send it something to keep it happy.
|
// We recognize this attempt and send it something to keep it happy.
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("KISS TCP: Something unexpected from client application.\n");
|
dw_printf ("KISS TCP: Something unexpected from client application.\n");
|
||||||
dw_printf ("Is client app treating this like an old TNC with command mode?\n");
|
dw_printf ("Is client app treating this like an old TNC with command mode?\n");
|
||||||
dw_printf ("This can be caused by the application sending commands to put a\n");
|
dw_printf ("This can be caused by the application sending commands to put a\n");
|
||||||
dw_printf ("traditional TNC into KISS mode. It is usually a harmless warning.\n");
|
dw_printf ("traditional TNC into KISS mode. It is usually a harmless warning.\n");
|
||||||
dw_printf ("For best results, configure for a KISS-only TNC to avoid this.\n");
|
dw_printf ("For best results, configure for a KISS-only TNC to avoid this.\n");
|
||||||
dw_printf ("In the case of APRSISCE/32, use \"Simply(KISS)\" rather than \"KISS.\"\n");
|
dw_printf ("In the case of APRSISCE/32, use \"Simply(KISS)\" rather than \"KISS.\"\n");
|
||||||
|
|
||||||
flen = strlen((char*)fbuf);
|
flen = strlen((char*)fbuf);
|
||||||
if (kiss_debug) {
|
if (kiss_debug) {
|
||||||
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
|
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
|
||||||
}
|
}
|
||||||
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
|
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
|
||||||
kiss_len = strlen((char *)kiss_buff);
|
kiss_len = strlen((char *)kiss_buff);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
|
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
|
||||||
|
|
||||||
assert (flen < (int)(sizeof(stemp)));
|
assert (flen < (int)(sizeof(stemp)));
|
||||||
|
|
||||||
stemp[0] = (chan << 4) | kiss_cmd;
|
// New in 1.7.
|
||||||
memcpy (stemp+1, fbuf, flen);
|
// Previously all channels were sent to everyone.
|
||||||
|
// We now have tcp ports which carry only a single radio channel.
|
||||||
|
// The application will see KISS channel 0 regardless of the radio channel.
|
||||||
|
|
||||||
if (kiss_debug >= 2) {
|
if (kps->chan == -1) {
|
||||||
/* AX.25 frame with the CRC removed. */
|
// Normal case, all channels.
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
stemp[0] = (chan << 4) | kiss_cmd;
|
||||||
dw_printf ("\n");
|
}
|
||||||
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
else if (kps->chan == chan) {
|
||||||
hex_dump (fbuf, flen);
|
// Single radio channel for this port. Application sees 0.
|
||||||
}
|
stemp[0] = (0 << 4) | kiss_cmd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Skip it.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
memcpy (stemp+1, fbuf, flen);
|
||||||
|
|
||||||
/* This has the escapes and the surrounding FENDs. */
|
if (kiss_debug >= 2) {
|
||||||
|
/* AX.25 frame with the CRC removed. */
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
||||||
|
hex_dump (fbuf, flen);
|
||||||
|
}
|
||||||
|
|
||||||
if (kiss_debug) {
|
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
||||||
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
|
||||||
}
|
/* This has the escapes and the surrounding FENDs. */
|
||||||
}
|
|
||||||
|
if (kiss_debug) {
|
||||||
|
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = SOCK_SEND(client_sock[client], (char*)kiss_buff, kiss_len);
|
err = SOCK_SEND(kps->client_sock[client], (char*)kiss_buff, kiss_len);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR) {
|
||||||
{
|
text_color_set(DW_COLOR_ERROR);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
dw_printf ("\nError %d sending message to KISS client application %d on port %d. Closing connection.\n\n", WSAGetLastError(), client, kps->tcp_port);
|
||||||
dw_printf ("\nError %d sending message to KISS client %d application. Closing connection.\n\n", WSAGetLastError(), client);
|
closesocket (kps->client_sock[client]);
|
||||||
closesocket (client_sock[client]);
|
kps->client_sock[client] = -1;
|
||||||
client_sock[client] = -1;
|
WSACleanup();
|
||||||
WSACleanup();
|
}
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
err = SOCK_SEND (client_sock[client], kiss_buff, kiss_len);
|
err = SOCK_SEND (kps->client_sock[client], kiss_buff, kiss_len);
|
||||||
if (err <= 0)
|
if (err <= 0) {
|
||||||
{
|
text_color_set(DW_COLOR_ERROR);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
dw_printf ("\nError %d sending message to KISS client application %d on port %d. Closing connection.\n\n", WSAGetLastError(), client, kps->tcp_port);
|
||||||
dw_printf ("\nError sending message to KISS client %d application. Closing connection.\n\n", client);
|
close (kps->client_sock[client]);
|
||||||
close (client_sock[client]);
|
kps->client_sock[client] = -1;
|
||||||
client_sock[client] = -1;
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
} // frame length >= 0
|
||||||
}
|
} // if all clients or the one specifie
|
||||||
|
} // for each client on the tcp port
|
||||||
|
} // if all ports or the one specified
|
||||||
|
} // for each tcp port
|
||||||
|
|
||||||
} /* end kissnet_send_rec_packet */
|
} /* end kissnet_send_rec_packet */
|
||||||
|
|
||||||
|
@ -661,14 +788,14 @@ void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int f
|
||||||
* Purpose: Send data from one network KISS client to all others.
|
* Purpose: Send data from one network KISS client to all others.
|
||||||
*
|
*
|
||||||
* Inputs: in_msg - KISS frame data without the framing or escapes.
|
* Inputs: in_msg - KISS frame data without the framing or escapes.
|
||||||
* The first byte is channel (port) and command (should be data).
|
* The first byte is channel and command (should be data).
|
||||||
|
* Caller no longer cares this byte. We will clobber it here.
|
||||||
*
|
*
|
||||||
* in_len - Number of bytes in above.
|
* in_len - Number of bytes in above.
|
||||||
*
|
*
|
||||||
* chan - Channel. Redundant because it is also in first byte of kiss_msg.
|
* chan - Channel. Use this instead of first byte of in_msg.
|
||||||
* Not currently used.
|
|
||||||
*
|
*
|
||||||
* cmd - KISS command nybble. Redundant because it is in first byte.
|
* cmd - KISS command nybble.
|
||||||
* Should be 0 because I'm expecting this only for data.
|
* Should be 0 because I'm expecting this only for data.
|
||||||
*
|
*
|
||||||
* from_client - Number of network (TCP) client instance.
|
* from_client - Number of network (TCP) client instance.
|
||||||
|
@ -687,52 +814,66 @@ void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int f
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
void kissnet_copy (unsigned char *in_msg, int in_len, int chan, int cmd, int from_client)
|
void kissnet_copy (unsigned char *in_msg, int in_len, int chan, int cmd, struct kissport_status_s *from_kps, int from_client)
|
||||||
{
|
{
|
||||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
||||||
int kiss_len;
|
|
||||||
int err;
|
int err;
|
||||||
int send_to;
|
|
||||||
|
|
||||||
(void) chan;
|
|
||||||
(void) cmd;
|
|
||||||
|
|
||||||
if (s_misc_config_p->kiss_copy) {
|
if (s_misc_config_p->kiss_copy) {
|
||||||
|
|
||||||
for (send_to = 0; send_to < MAX_NET_CLIENTS; send_to++) {
|
for (struct kissport_status_s *kps = all_ports; kps != NULL; kps = kps->pnext) {
|
||||||
|
|
||||||
if (send_to != from_client && client_sock[send_to] != -1) {
|
for (int client = 0; client < MAX_NET_CLIENTS; client++) {
|
||||||
|
|
||||||
kiss_len = kiss_encapsulate (in_msg, in_len, kiss_buff);
|
if ( ! ( kps == from_kps && client == from_client ) ) { // To all but origin.
|
||||||
|
|
||||||
/* This has the escapes and the surrounding FENDs. */
|
if (kps->client_sock[client] != -1) {
|
||||||
|
|
||||||
if (kiss_debug) {
|
if (kps-> chan == -1 || kps->chan == chan) {
|
||||||
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
|
||||||
}
|
// Two different cases here:
|
||||||
|
// - The TCP port allows all channels, or
|
||||||
|
// - The TCP port allows only one channel. In this case set KISS channel to 0.
|
||||||
|
|
||||||
|
if (kps->chan == -1) {
|
||||||
|
in_msg[0] = (chan << 4) | cmd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
in_msg[0] = 0 | cmd; // set channel to zero.
|
||||||
|
}
|
||||||
|
|
||||||
|
int 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__
|
#if __WIN32__
|
||||||
err = SOCK_SEND(client_sock[send_to], (char*)kiss_buff, kiss_len);
|
err = SOCK_SEND(kps->client_sock[client], (char*)kiss_buff, kiss_len);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR) {
|
||||||
{
|
text_color_set(DW_COLOR_ERROR);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
dw_printf ("\nError %d copying message to KISS TCP port %d client %d application. Closing connection.\n\n", WSAGetLastError(), kps->tcp_port, client);
|
||||||
dw_printf ("\nError %d copying message to KISS client %d application. Closing connection.\n\n", WSAGetLastError(), send_to);
|
closesocket (kps->client_sock[client]);
|
||||||
closesocket (client_sock[send_to]);
|
kps->client_sock[client] = -1;
|
||||||
client_sock[send_to] = -1;
|
WSACleanup();
|
||||||
WSACleanup();
|
}
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
err = SOCK_SEND (client_sock[send_to], kiss_buff, kiss_len);
|
err = SOCK_SEND (kps->client_sock[client], kiss_buff, kiss_len);
|
||||||
if (err <= 0)
|
if (err <= 0) {
|
||||||
{
|
text_color_set(DW_COLOR_ERROR);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
dw_printf ("\nError copying message to KISS TCP port %d client %d application. Closing connection.\n\n", kps->tcp_port, client);
|
||||||
dw_printf ("\nError copying message to KISS client %d application. Closing connection.\n\n", send_to);
|
close (kps->client_sock[client]);
|
||||||
close (client_sock[send_to]);
|
kps->client_sock[client] = -1;
|
||||||
client_sock[send_to] = -1;
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
} // if origin and destination different.
|
} // Channel is allowed on this port.
|
||||||
} // loop over all KISS network clients.
|
} // socket is open
|
||||||
|
} // if origin and destination different.
|
||||||
|
} // loop over all KISS network clients for one port.
|
||||||
|
} // loop over all KISS TCP ports
|
||||||
} // Feature enabled.
|
} // Feature enabled.
|
||||||
|
|
||||||
} /* end kissnet_copy */
|
} /* end kissnet_copy */
|
||||||
|
@ -759,20 +900,19 @@ void kissnet_copy (unsigned char *in_msg, int in_len, int chan, int cmd, int fro
|
||||||
/* Return one byte (value 0 - 255) */
|
/* Return one byte (value 0 - 255) */
|
||||||
|
|
||||||
|
|
||||||
static int kiss_get (int client)
|
static int kiss_get (struct kissport_status_s *kps, int client)
|
||||||
{
|
{
|
||||||
unsigned char ch;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
while (client_sock[client] <= 0) {
|
while (kps->client_sock[client] <= 0) {
|
||||||
SLEEP_SEC(1); /* Not connected. Try again later. */
|
SLEEP_SEC(1); /* Not connected. Try again later. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just get one byte at a time. */
|
/* Just get one byte at a time. */
|
||||||
|
|
||||||
n = SOCK_RECV (client_sock[client], (char *)(&ch), 1);
|
unsigned char ch;
|
||||||
|
int n = SOCK_RECV (kps->client_sock[client], (char *)(&ch), 1);
|
||||||
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
#if DEBUG9
|
#if DEBUG9
|
||||||
|
@ -792,13 +932,13 @@ static int kiss_get (int client)
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nKISS client application %d has gone away.\n\n", client);
|
dw_printf ("\nKISS client application %d on TCP port %d has gone away.\n\n", client, kps->tcp_port);
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
closesocket (client_sock[client]);
|
closesocket (kps->client_sock[client]);
|
||||||
#else
|
#else
|
||||||
close (client_sock[client]);
|
close (kps->client_sock[client]);
|
||||||
#endif
|
#endif
|
||||||
client_sock[client] = -1;
|
kps->client_sock[client] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -806,17 +946,19 @@ static int kiss_get (int client)
|
||||||
|
|
||||||
static THREAD_F kissnet_listen_thread (void *arg)
|
static THREAD_F kissnet_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
unsigned char ch;
|
struct kissport_status_s *kps = arg;
|
||||||
|
|
||||||
|
int client = kps->arg2;
|
||||||
|
assert (client >= 0 && client < MAX_NET_CLIENTS);
|
||||||
|
|
||||||
int client = (int)(ptrdiff_t)arg;
|
kps->arg2 = -1; // Indicates thread is running so
|
||||||
|
// arg2 can be reused for the next one.
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("kissnet_listen_thread ( client = %d, socket fd = %d )\n", client, client_sock[client]);
|
dw_printf ("kissnet_listen_thread ( tcp_port = %d, client = %d, socket fd = %d )\n", kps->tcp_port, client, kps->client_sock[client]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert (client >= 0 && client < MAX_NET_CLIENTS);
|
|
||||||
|
|
||||||
|
|
||||||
// So why is kissnet_send_rec_packet mentioned here for incoming from the client app?
|
// So why is kissnet_send_rec_packet mentioned here for incoming from the client app?
|
||||||
|
@ -832,8 +974,8 @@ static THREAD_F kissnet_listen_thread (void *arg)
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = kiss_get(client);
|
unsigned char ch = kiss_get(kps, client);
|
||||||
kiss_rec_byte (&(kf[client]), ch, kiss_debug, client, kissnet_send_rec_packet);
|
kiss_rec_byte (&(kps->kf[client]), ch, kiss_debug, kps, client, kissnet_send_rec_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
|
@ -3,21 +3,27 @@
|
||||||
* Name: kissnet.h
|
* Name: kissnet.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef KISSNET_H
|
||||||
|
#define KISSNET_H
|
||||||
|
|
||||||
#include "ax25_pad.h" /* for packet_t */
|
#include "ax25_pad.h" /* for packet_t */
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "kiss_frame.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void kissnet_init (struct misc_config_s *misc_config);
|
void kissnet_init (struct misc_config_s *misc_config);
|
||||||
|
|
||||||
void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client);
|
void kissnet_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen,
|
||||||
|
struct kissport_status_s *onlykps, int onlyclient);
|
||||||
|
|
||||||
void kiss_net_set_debug (int n);
|
void kiss_net_set_debug (int n);
|
||||||
|
|
||||||
void kissnet_copy (unsigned char *kiss_msg, int kiss_len, int chan, int cmd, int from_client);
|
void kissnet_copy (unsigned char *kiss_msg, int kiss_len, int chan, int cmd, struct kissport_status_s *from_kps, int from_client);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // KISSNET_H
|
||||||
|
|
||||||
/* end kissnet.h */
|
/* end kissnet.h */
|
||||||
|
|
|
@ -261,6 +261,7 @@ void kissserial_init (struct misc_config_s *mc)
|
||||||
* flen - Length of raw received frame not including the FCS
|
* flen - Length of raw received frame not including the FCS
|
||||||
* or -1 for a text string.
|
* or -1 for a text string.
|
||||||
*
|
*
|
||||||
|
* kps
|
||||||
* client - Not used for serial port version.
|
* client - Not used for serial port version.
|
||||||
* Here so that 3 related functions all have
|
* Here so that 3 related functions all have
|
||||||
* the same parameter list.
|
* the same parameter list.
|
||||||
|
@ -272,7 +273,8 @@ void kissserial_init (struct misc_config_s *mc)
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
void kissserial_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client)
|
void kissserial_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen,
|
||||||
|
struct kissport_status_s *notused1, int notused2)
|
||||||
{
|
{
|
||||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
||||||
int kiss_len;
|
int kiss_len;
|
||||||
|
@ -488,7 +490,7 @@ static THREAD_F kissserial_listen_thread (void *arg)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = kissserial_get();
|
ch = kissserial_get();
|
||||||
kiss_rec_byte (&kf, ch, kissserial_debug, -1, kissserial_send_rec_packet);
|
kiss_rec_byte (&kf, ch, kissserial_debug, NULL, -1, kissserial_send_rec_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
|
@ -8,12 +8,14 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "kiss_frame.h"
|
||||||
|
|
||||||
|
|
||||||
void kissserial_init (struct misc_config_s *misc_config);
|
void kissserial_init (struct misc_config_s *misc_config);
|
||||||
|
|
||||||
void kissserial_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen, int client);
|
void kissserial_send_rec_packet (int chan, int kiss_cmd, unsigned char *fbuf, int flen,
|
||||||
|
struct kissport_status_s *notused1, int notused2);
|
||||||
|
|
||||||
|
|
||||||
void kissserial_set_debug (int n);
|
void kissserial_set_debug (int n);
|
||||||
|
|
||||||
|
|
|
@ -663,7 +663,7 @@ static THREAD_F tnc_listen_net (void *arg)
|
||||||
// on the assumption it was being used in only one direction.
|
// on the assumption it was being used in only one direction.
|
||||||
// Not worried enough about it to do anything at this time.
|
// Not worried enough about it to do anything at this time.
|
||||||
|
|
||||||
kiss_rec_byte (&kstate, data[j], verbose, client, NULL);
|
kiss_rec_byte (&kstate, data[j], verbose, NULL, client, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -726,7 +726,7 @@ static THREAD_F tnc_listen_serial (void *arg)
|
||||||
// Feed in one byte at a time.
|
// Feed in one byte at a time.
|
||||||
// kiss_process_msg is called when a complete frame has been accumulated.
|
// kiss_process_msg is called when a complete frame has been accumulated.
|
||||||
|
|
||||||
kiss_rec_byte (&kstate, ch, verbose, client, NULL);
|
kiss_rec_byte (&kstate, ch, verbose, NULL, client, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* end tnc_listen_serial */
|
} /* end tnc_listen_serial */
|
||||||
|
@ -754,7 +754,8 @@ static THREAD_F tnc_listen_serial (void *arg)
|
||||||
*
|
*
|
||||||
*-----------------------------------------------------------------*/
|
*-----------------------------------------------------------------*/
|
||||||
|
|
||||||
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, int client, void (*sendfun)(int,int,unsigned char*,int,int))
|
void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug, struct kissport_status_s *kps, int client,
|
||||||
|
void (*sendfun)(int chan, int kiss_cmd, unsigned char *fbuf, int flen, struct kissport_status_s *onlykps, int onlyclient))
|
||||||
{
|
{
|
||||||
int chan;
|
int chan;
|
||||||
int cmd;
|
int cmd;
|
||||||
|
|
|
@ -897,9 +897,9 @@ static void xmit_object_report (int i, int first_time)
|
||||||
flen = ax25_pack(pp, fbuf);
|
flen = ax25_pack(pp, fbuf);
|
||||||
|
|
||||||
server_send_rec_packet (save_tt_config_p->obj_recv_chan, pp, fbuf, flen);
|
server_send_rec_packet (save_tt_config_p->obj_recv_chan, pp, fbuf, flen);
|
||||||
kissnet_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1);
|
kissnet_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1);
|
||||||
kissserial_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1);
|
kissserial_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1);
|
||||||
kisspt_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, -1);
|
kisspt_send_rec_packet (save_tt_config_p->obj_recv_chan, KISS_CMD_DATA_FRAME, fbuf, flen, NULL, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_time && save_tt_config_p->obj_send_to_ig) {
|
if (first_time && save_tt_config_p->obj_send_to_ig) {
|
||||||
|
|
Loading…
Reference in New Issue