mirror of https://github.com/wb2osz/direwolf.git
Issue 84. IGate was truncating packets that contained nul character
in the information/comment part.
This commit is contained in:
parent
785c8deffa
commit
b6254da203
17
CHANGES.md
17
CHANGES.md
|
@ -2,6 +2,23 @@
|
||||||
# Revision History #
|
# Revision History #
|
||||||
|
|
||||||
|
|
||||||
|
## Version 1.4 -- Development snapshot H -- March 2017 ##
|
||||||
|
|
||||||
|
**This is beta test quality. If no significant issues are reported this will be the version 1.4 release.**
|
||||||
|
|
||||||
|
### New Features: ###
|
||||||
|
|
||||||
|
- Take advantage of new 'gpio' group and new /sys/class/gpio ownership in Raspbian Jessie.
|
||||||
|
|
||||||
|
- Handle more complicated gpio naming for CubieBoard, etc.
|
||||||
|
|
||||||
|
|
||||||
|
### Bugs Fixed: ###
|
||||||
|
|
||||||
|
- IGate did not retain nul characters in the information part of a packet. This should never happen with a valid APRS packet but there are a couple cases where it has. If we encounter these malformed packets, pass them along as-is, rather than truncating.
|
||||||
|
|
||||||
|
- Don't digipeat packets when the source is my call.
|
||||||
|
|
||||||
----------
|
----------
|
||||||
|
|
||||||
## Version 1.4 -- Development snapshot G -- January 2017 ##
|
## Version 1.4 -- Development snapshot G -- January 2017 ##
|
||||||
|
|
136
ax25_pad.c
136
ax25_pad.c
|
@ -335,9 +335,18 @@ void ax25_delete (packet_t this_p)
|
||||||
* Purpose: Parse a frame in human-readable monitoring format and change
|
* Purpose: Parse a frame in human-readable monitoring format and change
|
||||||
* to internal representation.
|
* to internal representation.
|
||||||
*
|
*
|
||||||
* Input: monitor - "TNC-2" format of a monitored packet. i.e.
|
* Input: monitor - "TNC-2" monitor format for packet. i.e.
|
||||||
* source>dest[,repeater1,repeater2,...]:information
|
* source>dest[,repeater1,repeater2,...]:information
|
||||||
*
|
*
|
||||||
|
* The information part can have non-printable characters
|
||||||
|
* in the form of <0xff>. This will be converted to single
|
||||||
|
* bytes. e.g. <0x0d> is carriage return.
|
||||||
|
* In version 1.4H we will allow nul characters which means
|
||||||
|
* we have to maintain a length rather than using strlen().
|
||||||
|
* I maintain that it violates the spec but want to handle it
|
||||||
|
* because it does happen and we want to preserve it when
|
||||||
|
* acting as an IGate rather than corrupting it.
|
||||||
|
*
|
||||||
* strict - True to enforce rules for packets sent over the air.
|
* strict - True to enforce rules for packets sent over the air.
|
||||||
* False to be more lenient for packets from IGate server.
|
* False to be more lenient for packets from IGate server.
|
||||||
*
|
*
|
||||||
|
@ -369,17 +378,11 @@ packet_t ax25_from_text (char *monitor, int strict)
|
||||||
char *pa;
|
char *pa;
|
||||||
char *saveptr; /* Used with strtok_r because strtok is not thread safe. */
|
char *saveptr; /* Used with strtok_r because strtok is not thread safe. */
|
||||||
|
|
||||||
static int first_time = 1;
|
|
||||||
static regex_t unhex_re;
|
|
||||||
int e;
|
|
||||||
char emsg[100];
|
|
||||||
#define MAXMATCH 1
|
|
||||||
regmatch_t match[MAXMATCH];
|
|
||||||
int keep_going;
|
|
||||||
char temp[512];
|
|
||||||
int ssid_temp, heard_temp;
|
int ssid_temp, heard_temp;
|
||||||
char atemp[AX25_MAX_ADDR_LEN];
|
char atemp[AX25_MAX_ADDR_LEN];
|
||||||
|
|
||||||
|
char info_part[AX25_MAX_INFO_LEN+1];
|
||||||
|
int info_len;
|
||||||
|
|
||||||
packet_t this_p = ax25_new ();
|
packet_t this_p = ax25_new ();
|
||||||
|
|
||||||
|
@ -392,58 +395,15 @@ packet_t ax25_from_text (char *monitor, int strict)
|
||||||
|
|
||||||
/* Is it possible to have a nul character (zero byte) in the */
|
/* Is it possible to have a nul character (zero byte) in the */
|
||||||
/* information field of an AX.25 frame? */
|
/* information field of an AX.25 frame? */
|
||||||
/* Yes, but it would be difficult in the from-text case. */
|
/* At this point, we have a normal C string. */
|
||||||
|
/* It is possible that will convert <0x00> to a nul character later. */
|
||||||
|
/* There we need to maintain a separate length and not use normal C string functions. */
|
||||||
|
|
||||||
strlcpy (stuff, monitor, sizeof(stuff));
|
strlcpy (stuff, monitor, sizeof(stuff));
|
||||||
|
|
||||||
/*
|
|
||||||
* Translate hexadecimal values like <0xff> to non-printing characters.
|
|
||||||
* MIC-E message type uses 5 different non-printing characters.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (first_time)
|
|
||||||
{
|
|
||||||
e = regcomp (&unhex_re, "<0x[0-9a-fA-F][0-9a-fA-F]>", 0);
|
|
||||||
if (e) {
|
|
||||||
regerror (e, &unhex_re, emsg, sizeof(emsg));
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("%s:%d: %s\n", __FILE__, __LINE__, emsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
first_time = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
|
||||||
dw_printf ("BEFORE: %s\n", stuff);
|
|
||||||
ax25_safe_print (stuff, -1, 0);
|
|
||||||
dw_printf ("\n");
|
|
||||||
#endif
|
|
||||||
keep_going = 1;
|
|
||||||
while (keep_going) {
|
|
||||||
if (regexec (&unhex_re, stuff, MAXMATCH, match, 0) == 0) {
|
|
||||||
int n;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
stuff[match[0].rm_so + 5] = '\0';
|
|
||||||
n = strtol (stuff + match[0].rm_so + 3, &p, 16);
|
|
||||||
stuff[match[0].rm_so] = n;
|
|
||||||
strlcpy (temp, stuff + match[0].rm_eo, sizeof(temp));
|
|
||||||
strlcpy (stuff + match[0].rm_so + 1, temp, sizeof(stuff)-match[0].rm_so-1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
keep_going = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
|
||||||
dw_printf ("AFTER: %s\n", stuff);
|
|
||||||
ax25_safe_print (stuff, -1, 0);
|
|
||||||
dw_printf ("\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the packet with two addresses and control/pid
|
* Initialize the packet structure with two addresses and control/pid
|
||||||
* for APRS.
|
* for APRS.
|
||||||
*/
|
*/
|
||||||
memset (this_p->frame_data + AX25_DESTINATION*7, ' ' << 1, 6);
|
memset (this_p->frame_data + AX25_DESTINATION*7, ' ' << 1, 6);
|
||||||
|
@ -473,12 +433,6 @@ packet_t ax25_from_text (char *monitor, int strict)
|
||||||
*pinfo = '\0';
|
*pinfo = '\0';
|
||||||
pinfo++;
|
pinfo++;
|
||||||
|
|
||||||
if (strlen(pinfo) > AX25_MAX_INFO_LEN) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Warning: Information part truncated to %d characters.\n", AX25_MAX_INFO_LEN);
|
|
||||||
pinfo[AX25_MAX_INFO_LEN] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Separate the addresses.
|
* Separate the addresses.
|
||||||
* Note that source and destination order is swappped.
|
* Note that source and destination order is swappped.
|
||||||
|
@ -535,7 +489,6 @@ packet_t ax25_from_text (char *monitor, int strict)
|
||||||
*/
|
*/
|
||||||
while (( pa = strtok_r (NULL, ",", &saveptr)) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
|
while (( pa = strtok_r (NULL, ",", &saveptr)) != NULL && this_p->num_addr < AX25_MAX_ADDRS ) {
|
||||||
|
|
||||||
//char *last;
|
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
k = this_p->num_addr;
|
k = this_p->num_addr;
|
||||||
|
@ -561,11 +514,61 @@ packet_t ax25_from_text (char *monitor, int strict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, process the information part.
|
||||||
|
*
|
||||||
|
* Translate hexadecimal values like <0xff> to single bytes.
|
||||||
|
* MIC-E format uses 5 different non-printing characters.
|
||||||
|
* We might want to manually generate UTF-8 characters such as degree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define DEBUG14H 1
|
||||||
|
|
||||||
|
#if DEBUG14H
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("BEFORE: %s\nSAFE: ", pinfo);
|
||||||
|
ax25_safe_print (pinfo, -1, 0);
|
||||||
|
dw_printf ("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
info_len = 0;
|
||||||
|
while (*pinfo != '\0' && info_len < AX25_MAX_INFO_LEN) {
|
||||||
|
|
||||||
|
if (strlen(pinfo) >= 6 &&
|
||||||
|
pinfo[0] == '<' &&
|
||||||
|
pinfo[1] == '0' &&
|
||||||
|
pinfo[2] == 'x' &&
|
||||||
|
isxdigit(pinfo[3]) &&
|
||||||
|
isxdigit(pinfo[4]) &&
|
||||||
|
pinfo[5] == '>') {
|
||||||
|
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
info_part[info_len] = strtol (pinfo + 3, &p, 16);
|
||||||
|
info_len++;
|
||||||
|
pinfo += 6;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
info_part[info_len] = *pinfo;
|
||||||
|
info_len++;
|
||||||
|
pinfo++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info_part[info_len] = '\0';
|
||||||
|
|
||||||
|
#if DEBUG14H
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("AFTER: %s\nSAFE: ", info_part);
|
||||||
|
ax25_safe_print (info_part, info_len, 0);
|
||||||
|
dw_printf ("\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Append the info part.
|
* Append the info part.
|
||||||
*/
|
*/
|
||||||
strlcpy ((char*)(this_p->frame_data+this_p->frame_len), pinfo, sizeof(this_p->frame_data)-this_p->frame_len);
|
memcpy ((char*)(this_p->frame_data+this_p->frame_len), info_part, info_len);
|
||||||
this_p->frame_len += strlen(pinfo);
|
this_p->frame_len += info_len;
|
||||||
|
|
||||||
return (this_p);
|
return (this_p);
|
||||||
}
|
}
|
||||||
|
@ -2536,7 +2539,7 @@ unsigned short ax25_m_m_crc (packet_t pp)
|
||||||
*
|
*
|
||||||
* Inputs: pstr - Pointer to string.
|
* Inputs: pstr - Pointer to string.
|
||||||
*
|
*
|
||||||
* len - Maximum length if not -1.
|
* len - Number of bytes. If < 0 we use strlen().
|
||||||
*
|
*
|
||||||
* ascii_only - Restrict output to only ASCII.
|
* ascii_only - Restrict output to only ASCII.
|
||||||
* Normally we allow UTF-8.
|
* Normally we allow UTF-8.
|
||||||
|
@ -2587,7 +2590,6 @@ void ax25_safe_print (char *pstr, int len, int ascii_only)
|
||||||
if (len > MAXSAFE)
|
if (len > MAXSAFE)
|
||||||
len = MAXSAFE;
|
len = MAXSAFE;
|
||||||
|
|
||||||
//while (len > 0 && *pstr != '\0')
|
|
||||||
while (len > 0)
|
while (len > 0)
|
||||||
{
|
{
|
||||||
ch = *((unsigned char *)pstr);
|
ch = *((unsigned char *)pstr);
|
||||||
|
|
|
@ -199,6 +199,33 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet)
|
||||||
ax25_get_addr_with_ssid (pp, AX25_SOURCE, A->g_src);
|
ax25_get_addr_with_ssid (pp, AX25_SOURCE, A->g_src);
|
||||||
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, dest);
|
ax25_get_addr_with_ssid (pp, AX25_DESTINATION, dest);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report error if the information part contains a nul character.
|
||||||
|
* There are two known cases where this can happen.
|
||||||
|
*
|
||||||
|
* - The Kenwood TM-D710A sometimes sends packets like this:
|
||||||
|
*
|
||||||
|
* VA3AJ-9>T2QU6X,VE3WRC,WIDE1,K8UNS,WIDE2*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`nW<0x1f>oS8>/]"6M}driving fast=
|
||||||
|
* K4JH-9>S5UQ6X,WR4AGC-3*,WIDE1*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`jP}l"&>/]"47}QRV from the EV =
|
||||||
|
*
|
||||||
|
* Notice that the data type indicator of "4" is not valid. If we remove
|
||||||
|
* 4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00> we are left with a good MIC-E format.
|
||||||
|
* This same thing has been observed from others and is intermittent.
|
||||||
|
*
|
||||||
|
* - AGW Tracker can send UTF-16 if an option is selected. This can introduce nul bytes.
|
||||||
|
* This is wrong, it should be using UTF-8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ( ! A->g_quiet ) && ( (int)strlen((char*)pinfo) != info_len) ) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("'nul' character found in Information part. This should never happen.\n");
|
||||||
|
dw_printf("It seems that %s is transmitting with defective software.\n", A->g_src);
|
||||||
|
|
||||||
|
if (strcmp((char*)pinfo, "4P") == 0) {
|
||||||
|
dw_printf("The TM-D710 will do this intermittently. A firmware upgrade is needed to fix it.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (*pinfo) { /* "DTI" data type identifier. */
|
switch (*pinfo) { /* "DTI" data type identifier. */
|
||||||
|
|
||||||
|
@ -3938,6 +3965,49 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
|
||||||
*
|
*
|
||||||
* /A=123456 Altitude
|
* /A=123456 Altitude
|
||||||
*
|
*
|
||||||
|
* What can appear in a comment?
|
||||||
|
*
|
||||||
|
* Chapter 5 of the APRS spec ( http://www.aprs.org/doc/APRS101.PDF ) says:
|
||||||
|
*
|
||||||
|
* "The comment may contain any printable ASCII characters (except | and ~,
|
||||||
|
* which are reserved for TNC channel switching)."
|
||||||
|
*
|
||||||
|
* "Printable" would exclude character values less than space (00100000), e.g.
|
||||||
|
* tab, carriage return, line feed, nul. Sometimes we see carriage return
|
||||||
|
* (00001010) at the end of APRS packets. This would be in violation of the
|
||||||
|
* specification.
|
||||||
|
*
|
||||||
|
* The base 91 telemetry format (http://he.fi/doc/aprs-base91-comment-telemetry.txt ),
|
||||||
|
* which is not part of the APRS spec, uses the | character in the comment to delimit encoded
|
||||||
|
* telemetry data. This would be in violation of the original spec.
|
||||||
|
*
|
||||||
|
* The APRS Spec Addendum 1.2 Proposals ( http://www.aprs.org/aprs12/datum.txt)
|
||||||
|
* adds use of UTF-8 (https://en.wikipedia.org/wiki/UTF-8 )for the free form text in
|
||||||
|
* messages and comments. It can't be used in the fixed width fields.
|
||||||
|
*
|
||||||
|
* Non-ASCII characters are represented by multi-byte sequences. All bytes in these
|
||||||
|
* multi-byte sequences have the most significant bit set to 1. Using UTF-8 would not
|
||||||
|
* add any nul (00000000) bytes to the stream.
|
||||||
|
*
|
||||||
|
* There are two known cases where we can have a nul character value.
|
||||||
|
*
|
||||||
|
* * The Kenwood TM-D710A sometimes sends packets like this:
|
||||||
|
*
|
||||||
|
* VA3AJ-9>T2QU6X,VE3WRC,WIDE1,K8UNS,WIDE2*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`nW<0x1f>oS8>/]"6M}driving fast=
|
||||||
|
* K4JH-9>S5UQ6X,WR4AGC-3*,WIDE1*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`jP}l"&>/]"47}QRV from the EV =
|
||||||
|
*
|
||||||
|
* Notice that the data type indicator of "4" is not valid. If we remove
|
||||||
|
* 4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00> we are left with a good MIC-E format.
|
||||||
|
* This same thing has been observed from others and is intermittent.
|
||||||
|
*
|
||||||
|
* * AGW Tracker can send UTF-16 if an option is selected. This can introduce nul bytes.
|
||||||
|
* This is wrong. It should be using UTF-8 and I'm not going to accomodate it here.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* The digipeater and IGate functions should pass along anything exactly the
|
||||||
|
* we received it, even if it is invalid. If different implementations try to fix it up
|
||||||
|
* somehow, like changing unprintable characters to spaces, we will only make things
|
||||||
|
* worse and thwart the duplicate detection.
|
||||||
*
|
*
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
|
@ -260,7 +260,7 @@ int main (int argc, char *argv[])
|
||||||
text_color_init(t_opt);
|
text_color_init(t_opt);
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||||
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "G", __DATE__);
|
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "H", __DATE__);
|
||||||
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
||||||
|
|
||||||
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)
|
#if defined(ENABLE_GPSD) || defined(USE_HAMLIB)
|
||||||
|
|
169
igate.c
169
igate.c
|
@ -118,7 +118,7 @@ static packet_t dp_queue_head;
|
||||||
|
|
||||||
static void satgate_delay_packet (packet_t pp, int chan);
|
static void satgate_delay_packet (packet_t pp, int chan);
|
||||||
static void send_packet_to_server (packet_t pp, int chan);
|
static void send_packet_to_server (packet_t pp, int chan);
|
||||||
static void send_msg_to_server (const char *msg);
|
static void send_msg_to_server (const char *msg, int msg_len);
|
||||||
static void maybe_xmit_packet_from_igate (char *message, int chan);
|
static void maybe_xmit_packet_from_igate (char *message, int chan);
|
||||||
|
|
||||||
static void rx_to_ig_init (void);
|
static void rx_to_ig_init (void);
|
||||||
|
@ -266,7 +266,7 @@ int main (int argc, char *argv[])
|
||||||
SLEEP_SEC (20);
|
SLEEP_SEC (20);
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("Send received packet\n");
|
dw_printf ("Send received packet\n");
|
||||||
send_msg_to_server ("W1ABC>APRS:?");
|
send_msg_to_server ("W1ABC>APRS:?", strlen("W1ABC>APRS:?");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -797,7 +797,7 @@ static void * connnect_thread (void *arg)
|
||||||
strlcat (stemp, " filter ", sizeof(stemp));
|
strlcat (stemp, " filter ", sizeof(stemp));
|
||||||
strlcat (stemp, save_igate_config_p->t2_filter, sizeof(stemp));
|
strlcat (stemp, save_igate_config_p->t2_filter, sizeof(stemp));
|
||||||
}
|
}
|
||||||
send_msg_to_server (stemp);
|
send_msg_to_server (stemp, strlen(stemp));
|
||||||
|
|
||||||
/* Delay until it is ok to start sending packets. */
|
/* Delay until it is ok to start sending packets. */
|
||||||
|
|
||||||
|
@ -827,7 +827,7 @@ static void * connnect_thread (void *arg)
|
||||||
strlcpy (heartbeat, "#", sizeof(heartbeat));
|
strlcpy (heartbeat, "#", sizeof(heartbeat));
|
||||||
|
|
||||||
/* This will close the socket if any error. */
|
/* This will close the socket if any error. */
|
||||||
send_msg_to_server (heartbeat);
|
send_msg_to_server (heartbeat, strlen(heartbeat));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -861,7 +861,9 @@ static void * connnect_thread (void *arg)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define IGATE_MAX_MSG 520 /* Message to IGate max 512 characters. */
|
#define IGATE_MAX_MSG 512 /* "All 'packets' sent to APRS-IS must be in the TNC2 format terminated */
|
||||||
|
/* by a carriage return, line feed sequence. No line may exceed 512 bytes */
|
||||||
|
/* including the CR/LF sequence." */
|
||||||
|
|
||||||
void igate_send_rec_packet (int chan, packet_t recv_pp)
|
void igate_send_rec_packet (int chan, packet_t recv_pp)
|
||||||
{
|
{
|
||||||
|
@ -993,6 +995,7 @@ void igate_send_rec_packet (int chan, packet_t recv_pp)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cut the information part at the first CR or LF.
|
* Cut the information part at the first CR or LF.
|
||||||
|
* Do NOT trim trailing spaces.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
info_len = ax25_get_info (pp, &pinfo);
|
info_len = ax25_get_info (pp, &pinfo);
|
||||||
|
@ -1074,13 +1077,13 @@ static void send_packet_to_server (packet_t pp, int chan)
|
||||||
|
|
||||||
|
|
||||||
info_len = ax25_get_info (pp, &pinfo);
|
info_len = ax25_get_info (pp, &pinfo);
|
||||||
(void)(info_len);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We will often see the same packet multiple times close together due to digipeating.
|
* We will often see the same packet multiple times close together due to digipeating.
|
||||||
* The consensus seems to be that we should just send the first and drop the later duplicates.
|
* The consensus seems to be that we should just send the first and drop the later duplicates.
|
||||||
* There is some dissent on this issue. http://www.tapr.org/pipermail/aprssig/2016-July/045907.html
|
* There is some dissent on this issue. http://www.tapr.org/pipermail/aprssig/2016-July/045907.html
|
||||||
* There could be some value to sending them all to provide information about digipeater paths.
|
* There could be some value to sending them all to provide information about digipeater paths.
|
||||||
|
* However, the servers should drop all duplicates so we wasting everyone's time but sending duplicates.
|
||||||
* If you feel strongly about this issue, you could remove the following section.
|
* If you feel strongly about this issue, you could remove the following section.
|
||||||
* Currently rx_to_ig_allow only checks for recent duplicates.
|
* Currently rx_to_ig_allow only checks for recent duplicates.
|
||||||
*/
|
*/
|
||||||
|
@ -1132,9 +1135,74 @@ static void send_packet_to_server (packet_t pp, int chan)
|
||||||
|
|
||||||
strlcat (msg, save_audio_config_p->achan[chan].mycall, sizeof(msg));
|
strlcat (msg, save_audio_config_p->achan[chan].mycall, sizeof(msg));
|
||||||
strlcat (msg, ":", sizeof(msg));
|
strlcat (msg, ":", sizeof(msg));
|
||||||
strlcat (msg, (char*)pinfo, sizeof(msg));
|
|
||||||
|
|
||||||
send_msg_to_server (msg);
|
|
||||||
|
|
||||||
|
// It was reported that APRS packets, containing a nul byte in the information part,
|
||||||
|
// are being truncated. https://github.com/wb2osz/direwolf/issues/84
|
||||||
|
//
|
||||||
|
// One might argue that the packets are invalid and the proper behavior would be
|
||||||
|
// to simply discard them, the same way we do if the CRC is bad. One might argue
|
||||||
|
// that we should simply pass along whatever we receive even if we don't like it.
|
||||||
|
// We really shouldn't modify it and make the situation even worse.
|
||||||
|
//
|
||||||
|
// Chapter 5 of the APRS spec ( http://www.aprs.org/doc/APRS101.PDF ) says:
|
||||||
|
//
|
||||||
|
// "The comment may contain any printable ASCII characters (except | and ~,
|
||||||
|
// which are reserved for TNC channel switching)."
|
||||||
|
//
|
||||||
|
// "Printable" would exclude character values less than space (00100000), e.g.
|
||||||
|
// tab, carriage return, line feed, nul. Sometimes we see carriage return
|
||||||
|
// (00001010) at the end of APRS packets. This would be in violation of the
|
||||||
|
// specification.
|
||||||
|
//
|
||||||
|
// The MIC-E position format can have non printable characters (0x1c ... 0x1f, 0x7f)
|
||||||
|
// in the information part. An unfortunate decision, but it is not in the comment part.
|
||||||
|
//
|
||||||
|
// The base 91 telemetry format (http://he.fi/doc/aprs-base91-comment-telemetry.txt ),
|
||||||
|
// which is not part of the APRS spec, uses the | character in the comment to delimit encoded
|
||||||
|
// telemetry data. This would be in violation of the original spec. No one cares.
|
||||||
|
//
|
||||||
|
// The APRS Spec Addendum 1.2 Proposals ( http://www.aprs.org/aprs12/datum.txt)
|
||||||
|
// adds use of UTF-8 (https://en.wikipedia.org/wiki/UTF-8 )for the free form text in
|
||||||
|
// messages and comments. It can't be used in the fixed width fields.
|
||||||
|
//
|
||||||
|
// Non-ASCII characters are represented by multi-byte sequences. All bytes in these
|
||||||
|
// multi-byte sequences have the most significant bit set to 1. Using UTF-8 would not
|
||||||
|
// add any nul (00000000) bytes to the stream.
|
||||||
|
//
|
||||||
|
// Based on all of that, we would not expect to see a nul character in the information part.
|
||||||
|
//
|
||||||
|
// There are two known cases where we can have a nul character value.
|
||||||
|
//
|
||||||
|
// * The Kenwood TM-D710A sometimes sends packets like this:
|
||||||
|
//
|
||||||
|
// VA3AJ-9>T2QU6X,VE3WRC,WIDE1,K8UNS,WIDE2*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`nW<0x1f>oS8>/]"6M}driving fast=
|
||||||
|
// K4JH-9>S5UQ6X,WR4AGC-3*,WIDE1*:4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00>`jP}l"&>/]"47}QRV from the EV =
|
||||||
|
//
|
||||||
|
// Notice that the data type indicator of "4" is not valid. If we remove
|
||||||
|
// 4P<0x00><0x0f>4T<0x00><0x0f>4X<0x00><0x0f>4\<0x00> we are left with a good MIC-E format.
|
||||||
|
// This same thing has been observed from others and is intermittent.
|
||||||
|
//
|
||||||
|
// * AGW Tracker can send UTF-16 if an option is selected. This can introduce nul bytes.
|
||||||
|
// This is wrong, it should be using UTF-8.
|
||||||
|
//
|
||||||
|
// Rather than using strlcat here, we need to use memcpy and maintain our
|
||||||
|
// own lengths, being careful to avoid buffer overflow.
|
||||||
|
|
||||||
|
int msg_len = strlen(msg); // What we have so far before info part.
|
||||||
|
|
||||||
|
if (info_len > IGATE_MAX_MSG - msg_len - 2) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Rx IGate: Too long. Truncating.\n");
|
||||||
|
info_len = IGATE_MAX_MSG - msg_len - 2;
|
||||||
|
}
|
||||||
|
if (info_len > 0) {
|
||||||
|
memcpy (msg + msg_len, pinfo, info_len);
|
||||||
|
msg_len += info_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_msg_to_server (msg, msg_len);
|
||||||
stats_uplink_packets++;
|
stats_uplink_packets++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1152,58 +1220,74 @@ static void send_packet_to_server (packet_t pp, int chan)
|
||||||
*
|
*
|
||||||
* Name: send_msg_to_server
|
* Name: send_msg_to_server
|
||||||
*
|
*
|
||||||
* Purpose: Send to the IGate server.
|
* Purpose: Send something to the IGate server.
|
||||||
* This one function should be used for login, hearbeats,
|
* This one function should be used for login, hearbeats,
|
||||||
* and packets.
|
* and packets.
|
||||||
*
|
*
|
||||||
* Inputs: imsg - Message. We will add CR/LF.
|
* Inputs: imsg - Message. We will add CR/LF here.
|
||||||
*
|
*
|
||||||
|
* imsg_len - Length of imsg in bytes.
|
||||||
|
* It could contain nul characters so we can't
|
||||||
|
* use the normal C string functions.
|
||||||
*
|
*
|
||||||
* Description: Send message to IGate Server if connected.
|
* Description: Send message to IGate Server if connected.
|
||||||
* Disconnect from server, and notify user, if any error.
|
* Disconnect from server, and notify user, if any error.
|
||||||
|
* Should use a word other than message because that has
|
||||||
|
* a specific meaning for APRS.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
static void send_msg_to_server (const char *imsg)
|
static void send_msg_to_server (const char *imsg, int imsg_len)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char stemp[IGATE_MAX_MSG];
|
char stemp[IGATE_MAX_MSG+1];
|
||||||
|
int stemp_len;
|
||||||
|
|
||||||
if (igate_sock == -1) {
|
if (igate_sock == -1) {
|
||||||
return; /* Silently discard if not connected. */
|
return; /* Silently discard if not connected. */
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcpy(stemp, imsg, sizeof(stemp));
|
stemp_len = imsg_len;
|
||||||
|
if (stemp_len + 2 > IGATE_MAX_MSG) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Rx IGate: Too long. Truncating.\n");
|
||||||
|
stemp_len = IGATE_MAX_MSG - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (stemp, imsg, stemp_len);
|
||||||
|
|
||||||
if (s_debug >= 1) {
|
if (s_debug >= 1) {
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[rx>ig] ");
|
dw_printf ("[rx>ig] ");
|
||||||
ax25_safe_print (stemp, strlen(stemp), 0);
|
ax25_safe_print (stemp, stemp_len, 0);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
strlcat (stemp, "\r\n", sizeof(stemp));
|
stemp[stemp_len++] = '\r';
|
||||||
|
stemp[stemp_len++] = '\n';
|
||||||
|
stemp[stemp_len] = '\0';
|
||||||
|
|
||||||
|
stats_uplink_bytes += stemp_len;
|
||||||
|
|
||||||
stats_uplink_bytes += strlen(stemp);
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = send (igate_sock, stemp, strlen(stemp), 0);
|
err = send (igate_sock, stemp, stemp_len, 0);
|
||||||
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 IGate server. Closing connection.\n\n", WSAGetLastError());
|
dw_printf ("\nError %d sending to IGate server. Closing connection.\n\n", WSAGetLastError());
|
||||||
//dw_printf ("DEBUG: igate_sock=%d, line=%d\n", igate_sock, __LINE__);
|
//dw_printf ("DEBUG: igate_sock=%d, line=%d\n", igate_sock, __LINE__);
|
||||||
closesocket (igate_sock);
|
closesocket (igate_sock);
|
||||||
igate_sock = -1;
|
igate_sock = -1;
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
err = write (igate_sock, stemp, strlen(stemp));
|
err = write (igate_sock, stemp, stemp_len);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError sending message to IGate server. Closing connection.\n\n");
|
dw_printf ("\nError sending to IGate server. Closing connection.\n\n");
|
||||||
close (igate_sock);
|
close (igate_sock);
|
||||||
igate_sock = -1;
|
igate_sock = -1;
|
||||||
}
|
}
|
||||||
|
@ -1295,7 +1379,7 @@ static void * igate_recv_thread (void *arg)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
unsigned char ch;
|
unsigned char ch;
|
||||||
unsigned char message[1000]; // Spec says max 500 or so.
|
unsigned char message[1000]; // Spec says max 512.
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1313,14 +1397,27 @@ static void * igate_recv_thread (void *arg)
|
||||||
ch = get1ch();
|
ch = get1ch();
|
||||||
stats_downlink_bytes++;
|
stats_downlink_bytes++;
|
||||||
|
|
||||||
if (len < (int)(sizeof(message)))
|
// I never expected to see a nul character but it can happen.
|
||||||
{
|
// If found, change it to <0x00> and ax25_from_text will change it back to a single byte.
|
||||||
message[len] = ch;
|
// Along the way we can use the normal C string handling.
|
||||||
|
|
||||||
|
if (ch == 0 && len < (int)(sizeof(message)) - 5) {
|
||||||
|
message[len++] = '<';
|
||||||
|
message[len++] = '0';
|
||||||
|
message[len++] = 'x';
|
||||||
|
message[len++] = '0';
|
||||||
|
message[len++] = '0';
|
||||||
|
message[len++] = '>';
|
||||||
|
}
|
||||||
|
else if (len < (int)(sizeof(message)))
|
||||||
|
{
|
||||||
|
message[len++] = ch;
|
||||||
}
|
}
|
||||||
len++;
|
|
||||||
|
|
||||||
} while (ch != '\n');
|
} while (ch != '\n');
|
||||||
|
|
||||||
|
message[sizeof(message)-1] = '\0';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a complete message terminated by LF.
|
* We have a complete message terminated by LF.
|
||||||
*
|
*
|
||||||
|
@ -1335,10 +1432,13 @@ static void * igate_recv_thread (void *arg)
|
||||||
* I've seen a case where the original RF packet had a trailing CR but
|
* I've seen a case where the original RF packet had a trailing CR but
|
||||||
* after someone else sent it to the server and it came back to me, that
|
* after someone else sent it to the server and it came back to me, that
|
||||||
* CR was now a trailing space.
|
* CR was now a trailing space.
|
||||||
|
*
|
||||||
* At first I was tempted to trim a trailing space as well.
|
* At first I was tempted to trim a trailing space as well.
|
||||||
* By fixing this one case it might corrupt the data in other cases.
|
* By fixing this one case it might corrupt the data in other cases.
|
||||||
* We compensate for this by ignoring trailing spaces when performing
|
* We compensate for this by ignoring trailing spaces when performing
|
||||||
* the duplicate detection and removal.
|
* the duplicate detection and removal.
|
||||||
|
*
|
||||||
|
* We need to transmit exactly as we get it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1384,6 +1484,19 @@ static void * igate_recv_thread (void *arg)
|
||||||
ax25_safe_print ((char *)message, len, 0);
|
ax25_safe_print ((char *)message, len, 0);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
|
if ((int)strlen((char*)message) != len) {
|
||||||
|
|
||||||
|
// Invalid. Either drop it or pass it along as-is. Don't change.
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("'nul' character found in packet from IS. This should never happen.\n");
|
||||||
|
dw_printf("The source station is probably transmitting with defective software.\n");
|
||||||
|
|
||||||
|
//if (strcmp((char*)pinfo, "4P") == 0) {
|
||||||
|
// dw_printf("The TM-D710 will do this intermittently. A firmware upgrade is needed to fix it.\n");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record that we heard from the source address.
|
* Record that we heard from the source address.
|
||||||
*/
|
*/
|
||||||
|
@ -2038,10 +2151,12 @@ static int rx_to_ig_allow (packet_t pp)
|
||||||
* At first I thought duplicate removal was broken but it turns out they
|
* At first I thought duplicate removal was broken but it turns out they
|
||||||
* are not exactly the same.
|
* are not exactly the same.
|
||||||
*
|
*
|
||||||
* The receive IGate spec says a packet should be cut at a CR.
|
* >>> The receive IGate spec says a packet should be cut at a CR. <<<
|
||||||
|
*
|
||||||
* In one case it is removed as expected In another case, it is replaced by a trailing
|
* In one case it is removed as expected In another case, it is replaced by a trailing
|
||||||
* space character. Maybe someone thought non printable characters should be
|
* space character. Maybe someone thought non printable characters should be
|
||||||
* replaced by spaces???
|
* replaced by spaces??? (I have since been told someone thought it would be a good
|
||||||
|
* idea to replace unprintable characters with spaces. How's that working out for MIC-E position???)
|
||||||
*
|
*
|
||||||
* At first I was tempted to remove any trailing spaces to make up for the other
|
* At first I was tempted to remove any trailing spaces to make up for the other
|
||||||
* IGate adding it. Two wrongs don't make a right. Trailing spaces are not that
|
* IGate adding it. Two wrongs don't make a right. Trailing spaces are not that
|
||||||
|
|
Loading…
Reference in New Issue