From b6254da2034181170fb8edbe3fe637e158e9ba08 Mon Sep 17 00:00:00 2001 From: WB2OSZ Date: Sun, 5 Mar 2017 15:15:33 -0500 Subject: [PATCH] Issue 84. IGate was truncating packets that contained nul character in the information/comment part. --- CHANGES.md | 17 +++++ ax25_pad.c | 136 ++++++++++++++++++++-------------------- decode_aprs.c | 72 ++++++++++++++++++++- direwolf.c | 2 +- igate.c | 169 ++++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 300 insertions(+), 96 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 42c4107..950f336 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,23 @@ # 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 ## diff --git a/ax25_pad.c b/ax25_pad.c index bbc5879..457ae71 100644 --- a/ax25_pad.c +++ b/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 * 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 * + * 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. * 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 *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; char atemp[AX25_MAX_ADDR_LEN]; + char info_part[AX25_MAX_INFO_LEN+1]; + int info_len; 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 */ /* 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)); -/* - * 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. */ 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++; - 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. * 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 ) { - //char *last; int k; 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. */ - strlcpy ((char*)(this_p->frame_data+this_p->frame_len), pinfo, sizeof(this_p->frame_data)-this_p->frame_len); - this_p->frame_len += strlen(pinfo); + memcpy ((char*)(this_p->frame_data+this_p->frame_len), info_part, info_len); + this_p->frame_len += info_len; return (this_p); } @@ -2536,7 +2539,7 @@ unsigned short ax25_m_m_crc (packet_t pp) * * 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. * Normally we allow UTF-8. @@ -2587,7 +2590,6 @@ void ax25_safe_print (char *pstr, int len, int ascii_only) if (len > MAXSAFE) len = MAXSAFE; - //while (len > 0 && *pstr != '\0') while (len > 0) { ch = *((unsigned char *)pstr); diff --git a/decode_aprs.c b/decode_aprs.c index 64d8c02..00f8e80 100644 --- a/decode_aprs.c +++ b/decode_aprs.c @@ -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_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. */ @@ -3907,7 +3934,7 @@ static void substr_se (char *dest, const char *src, int start, int endp1) * clen - Length of comment or -1 to take it all. * * Outputs: A->g_telemetry - Base 91 telemetry |ss1122| - * A->g_altitude_ft - from /A=123456 + * A->g_altitude_ft - from /A=123456 * A->g_lat - Might be adjusted from !DAO! * A->g_lon - Might be adjusted from !DAO! * A->g_aprstt_loc - Private extension to !DAO! @@ -3938,6 +3965,49 @@ static void substr_se (char *dest, const char *src, int start, int endp1) * * /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. * *------------------------------------------------------------------*/ diff --git a/direwolf.c b/direwolf.c index 0782c20..f5e21ec 100644 --- a/direwolf.c +++ b/direwolf.c @@ -260,7 +260,7 @@ int main (int argc, char *argv[]) text_color_init(t_opt); 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 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); #if defined(ENABLE_GPSD) || defined(USE_HAMLIB) diff --git a/igate.c b/igate.c index 144a56b..f625ec4 100644 --- a/igate.c +++ b/igate.c @@ -118,7 +118,7 @@ static packet_t dp_queue_head; static void satgate_delay_packet (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 rx_to_ig_init (void); @@ -266,7 +266,7 @@ int main (int argc, char *argv[]) SLEEP_SEC (20); text_color_set(DW_COLOR_INFO); dw_printf ("Send received packet\n"); - send_msg_to_server ("W1ABC>APRS:?"); + send_msg_to_server ("W1ABC>APRS:?", strlen("W1ABC>APRS:?"); } #endif return 0; @@ -797,7 +797,7 @@ static void * connnect_thread (void *arg) strlcat (stemp, " 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. */ @@ -827,7 +827,7 @@ static void * connnect_thread (void *arg) strlcpy (heartbeat, "#", sizeof(heartbeat)); /* 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) { @@ -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. + * Do NOT trim trailing spaces. */ 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); - (void)(info_len); /* * 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. * 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. + * 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. * 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, ":", 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++; /* @@ -1152,58 +1220,74 @@ static void send_packet_to_server (packet_t pp, int chan) * * 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, * 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. * 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; - char stemp[IGATE_MAX_MSG]; + char stemp[IGATE_MAX_MSG+1]; + int stemp_len; if (igate_sock == -1) { 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) { text_color_set(DW_COLOR_XMIT); dw_printf ("[rx>ig] "); - ax25_safe_print (stemp, strlen(stemp), 0); + ax25_safe_print (stemp, stemp_len, 0); 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__ - err = send (igate_sock, stemp, strlen(stemp), 0); + err = send (igate_sock, stemp, stemp_len, 0); if (err == SOCKET_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__); closesocket (igate_sock); igate_sock = -1; WSACleanup(); } #else - err = write (igate_sock, stemp, strlen(stemp)); + err = write (igate_sock, stemp, stemp_len); if (err <= 0) { 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); igate_sock = -1; } @@ -1295,7 +1379,7 @@ static void * igate_recv_thread (void *arg) #endif { unsigned char ch; - unsigned char message[1000]; // Spec says max 500 or so. + unsigned char message[1000]; // Spec says max 512. int len; @@ -1313,14 +1397,27 @@ static void * igate_recv_thread (void *arg) ch = get1ch(); stats_downlink_bytes++; - if (len < (int)(sizeof(message))) - { - message[len] = ch; + // 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. + // 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'); + message[sizeof(message)-1] = '\0'; + /* * 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 * after someone else sent it to the server and it came back to me, that * CR was now a trailing space. + * * 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. * We compensate for this by ignoring trailing spaces when performing * 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); 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. */ @@ -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 * 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 * 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 * IGate adding it. Two wrongs don't make a right. Trailing spaces are not that