More efficient and reliable connected mode lost frame recovery.

This commit is contained in:
wb2osz 2018-01-01 16:38:43 -05:00
parent 3611971fe7
commit 9cd305950f
5 changed files with 730 additions and 223 deletions

File diff suppressed because it is too large Load Diff

View File

@ -355,15 +355,19 @@ packet_t ax25_u_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_ad
* *
* pf - Poll/Final flag. * pf - Poll/Final flag.
* *
* pinfo - Pointer to data for Info field. Allowed only for SREJ.
*
* info_len - Length for Info field.
*
* *
* Returns: Pointer to new packet object. * Returns: Pointer to new packet object.
* *
*------------------------------------------------------------------------------*/ *------------------------------------------------------------------------------*/
#if AX25MEMDEBUG #if AX25MEMDEBUG
packet_t ax25_s_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, char *src_file, int src_line) packet_t ax25_s_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len, char *src_file, int src_line)
#else #else
packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf) packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len)
#endif #endif
{ {
packet_t this_p; packet_t this_p;
@ -383,7 +387,7 @@ packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_ad
if ( ! set_addrs (this_p, addrs, num_addr, cr)) { if ( ! set_addrs (this_p, addrs, num_addr, cr)) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error in %s: Could not set addresses for U frame.\n", __func__); dw_printf ("Internal error in %s: Could not set addresses for S frame.\n", __func__);
ax25_delete (this_p); ax25_delete (this_p);
return (NULL); return (NULL);
} }
@ -401,6 +405,14 @@ packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_ad
nr &= (modulo - 1); nr &= (modulo - 1);
} }
// Erratum: The AX.25 spec is not clear about whether SREJ should be command, response, or both.
// The underlying X.25 spec clearly says it is reponse only. Let's go with that.
if (ftype == frame_type_S_SREJ && cr != cr_res) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error in %s: SREJ must be response.\n", __func__);
}
switch (ftype) { switch (ftype) {
case frame_type_S_RR: ctrl = 0x01; break; case frame_type_S_RR: ctrl = 0x01; break;
@ -434,6 +446,24 @@ packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_ad
this_p->frame_len++; this_p->frame_len++;
} }
if (ftype == frame_type_S_SREJ) {
if (pinfo != NULL && info_len > 0) {
if (info_len > AX25_MAX_INFO_LEN) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error in %s: SREJ frame, Invalid information field length %d.\n", __func__, info_len);
info_len = AX25_MAX_INFO_LEN;
}
memcpy (p, pinfo, info_len);
p += info_len;
this_p->frame_len += info_len;
}
}
else {
if (pinfo != NULL || info_len != 0) {
text_color_set(DW_COLOR_ERROR);
dw_printf ("Internal error in %s: Info part not allowed for RR, RNR, REJ frame.\n", __func__);
}
}
*p = '\0'; *p = '\0';
assert (p == this_p->frame_data + this_p->frame_len); assert (p == this_p->frame_data + this_p->frame_len);
@ -813,7 +843,7 @@ int main ()
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf ("\nConstruct S frame, cmd=%d, ftype=%d, pid=0x%02x\n", cr, ftype, pid); dw_printf ("\nConstruct S frame, cmd=%d, ftype=%d, pid=0x%02x\n", cr, ftype, pid);
pp = ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf); pp = ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf, NULL, 0);
ax25_hex_dump (pp); ax25_hex_dump (pp);
ax25_delete (pp); ax25_delete (pp);
@ -827,7 +857,7 @@ int main ()
text_color_set(DW_COLOR_INFO); text_color_set(DW_COLOR_INFO);
dw_printf ("\nConstruct S frame, cmd=%d, ftype=%d, pid=0x%02x\n", cr, ftype, pid); dw_printf ("\nConstruct S frame, cmd=%d, ftype=%d, pid=0x%02x\n", cr, ftype, pid);
pp = ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf); pp = ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf, NULL, 0);
ax25_hex_dump (pp); ax25_hex_dump (pp);
ax25_delete (pp); ax25_delete (pp);
@ -835,6 +865,26 @@ int main ()
} }
} }
/* SREJ is only S frame which can have information part. */
static char srej_info[] = { 1<<1, 2<<1, 3<<1, 4<<1 };
ftype = frame_type_S_SREJ;
for (pf = 0; pf <= 1; pf++) {
modulo = 128;
nr = 127;
cr = cr_res;
text_color_set(DW_COLOR_INFO);
dw_printf ("\nConstruct Multi-SREJ S frame, cmd=%d, ftype=%d, pid=0x%02x\n", cr, ftype, pid);
pp = ax25_s_frame (addrs, num_addr, cr, ftype, modulo, nr, pf, srej_info, (int)(sizeof(srej_info)));
ax25_hex_dump (pp);
ax25_delete (pp);
}
dw_printf ("\n----------\n\n"); dw_printf ("\n----------\n\n");
/* I frame */ /* I frame */

View File

@ -22,14 +22,14 @@
packet_t ax25_u_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len, char *src_file, int src_line); packet_t ax25_u_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len, char *src_file, int src_line);
packet_t ax25_s_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, char *src_file, int src_line); packet_t ax25_s_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len, char *src_file, int src_line);
packet_t ax25_i_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len, char *src_file, int src_line); packet_t ax25_i_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len, char *src_file, int src_line);
#define ax25_u_frame(a,n,c,f,p,q,i,l) ax25_u_frame_debug(a,n,c,f,p,q,i,l,__FILE__,__LINE__) #define ax25_u_frame(a,n,c,f,p,q,i,l) ax25_u_frame_debug(a,n,c,f,p,q,i,l,__FILE__,__LINE__)
#define ax25_s_frame(a,n,c,f,m,r,p) ax25_s_frame_debug(a,n,c,f,m,r,p,__FILE__,__LINE__) #define ax25_s_frame(a,n,c,f,m,r,p,i,l) ax25_s_frame_debug(a,n,c,f,m,r,p,i,l,__FILE__,__LINE__)
#define ax25_i_frame(a,n,c,m,r,s,p,q,i,l) ax25_i_frame_debug(a,n,c,m,r,s,p,q,i,l,__FILE__,__LINE__) #define ax25_i_frame(a,n,c,m,r,s,p,q,i,l) ax25_i_frame_debug(a,n,c,m,r,s,p,q,i,l,__FILE__,__LINE__)
@ -38,7 +38,7 @@ packet_t ax25_i_frame_debug (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int
packet_t ax25_u_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len); packet_t ax25_u_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int pf, int pid, unsigned char *pinfo, int info_len);
packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf); packet_t ax25_s_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, ax25_frame_type_t ftype, int modulo, int nr, int pf, unsigned char *pinfo, int info_len);
packet_t ax25_i_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len); packet_t ax25_i_frame (char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN], int num_addr, cmdres_t cr, int modulo, int nr, int ns, int pf, int pid, unsigned char *pinfo, int info_len);

207
xid.c
View File

@ -2,7 +2,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) 2014, 2016 John Langner, WB2OSZ // Copyright (C) 2014, 2016, 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
@ -50,6 +50,7 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#include "textcolor.h" #include "textcolor.h"
#include "xid.h" #include "xid.h"
@ -66,10 +67,36 @@
#define PI_Ack_Timer 9 #define PI_Ack_Timer 9
#define PI_Retries 10 #define PI_Retries 10
// Forget about the bit order at the physical layer (e.g. HDLC).
// It doesn't matter at all here. We are dealing with bytes.
// A different encoding could send the bits in the opposite order.
// The bit numbers are confusing because this one table (Fig. 4.5) starts
// with 1 for the LSB when everywhere else refers to the LSB as bit 0.
// The first byte must be of the form 0xx0 0001
// The second byte must be of the form 0000 0000
// If we process the two byte "Classes of Procedures" like
// the other multibyte numeric fields, with the more significant
// byte first, we end up with the bit masks below.
// The bit order would be 8 7 6 5 4 3 2 1 16 15 14 13 12 11 10 9
// (This has nothing to do with the HDLC serializing order.
// I'm talking about the way we would normally write binary numbers.)
#define PV_Classes_Procedures_Balanced_ABM 0x0100 #define PV_Classes_Procedures_Balanced_ABM 0x0100
#define PV_Classes_Procedures_Half_Duplex 0x2000 #define PV_Classes_Procedures_Half_Duplex 0x2000
#define PV_Classes_Procedures_Full_Duplex 0x4000 #define PV_Classes_Procedures_Full_Duplex 0x4000
// The first byte must be of the form 1000 0xx0
// The second byte must be of the form 1010 xx00
// The third byte must be of the form 0000 0010
// If we process the three byte "HDLC Optional Parmeters" like
// the other multibyte numeric fields, with the most significant
// byte first, we end up with bit masks like this.
// The bit order would be 8 7 6 5 4 3 2 1 16 15 14 13 12 11 10 9 24 23 22 21 20 19 18 17
#define PV_HDLC_Optional_Functions_REJ_cmd_resp 0x020000 #define PV_HDLC_Optional_Functions_REJ_cmd_resp 0x020000
#define PV_HDLC_Optional_Functions_SREJ_cmd_resp 0x040000 #define PV_HDLC_Optional_Functions_SREJ_cmd_resp 0x040000
#define PV_HDLC_Optional_Functions_Extended_Address 0x800000 #define PV_HDLC_Optional_Functions_Extended_Address 0x800000
@ -79,6 +106,9 @@
#define PV_HDLC_Optional_Functions_TEST_cmd_resp 0x002000 #define PV_HDLC_Optional_Functions_TEST_cmd_resp 0x002000
#define PV_HDLC_Optional_Functions_16_bit_FCS 0x008000 #define PV_HDLC_Optional_Functions_16_bit_FCS 0x008000
#define PV_HDLC_Optional_Functions_Multi_SREJ_cmd_resp 0x000020
#define PV_HDLC_Optional_Functions_Segmenter 0x000040
#define PV_HDLC_Optional_Functions_Synchronous_Tx 0x000002 #define PV_HDLC_Optional_Functions_Synchronous_Tx 0x000002
@ -127,7 +157,7 @@ int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, ch
// rej and modulo are enum so we can't use G_UNKNOWN there. // rej and modulo are enum so we can't use G_UNKNOWN there.
result->full_duplex = G_UNKNOWN; result->full_duplex = G_UNKNOWN;
result->rej = unknown_reject; result->srej = srej_not_specified;
result->modulo = modulo_unknown; result->modulo = modulo_unknown;
result->i_field_length_rx = G_UNKNOWN; result->i_field_length_rx = G_UNKNOWN;
result->window_size_rx = G_UNKNOWN; result->window_size_rx = G_UNKNOWN;
@ -204,21 +234,31 @@ int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, ch
case PI_HDLC_Optional_Functions: case PI_HDLC_Optional_Functions:
if ((pval & PV_HDLC_Optional_Functions_REJ_cmd_resp) && (pval & PV_HDLC_Optional_Functions_SREJ_cmd_resp)) { // Pick highest of those offered.
result->rej = selective_reject_reject; /* Both bits set */
strlcat (desc, "SREJ-REJ ", desc_size); if (pval & PV_HDLC_Optional_Functions_REJ_cmd_resp) {
}
else if ((pval & PV_HDLC_Optional_Functions_REJ_cmd_resp) && ! (pval & PV_HDLC_Optional_Functions_SREJ_cmd_resp)) {
result->rej = implicit_reject; /* Only REJ is set */
strlcat (desc, "REJ ", desc_size); strlcat (desc, "REJ ", desc_size);
} }
else if ( ! (pval & PV_HDLC_Optional_Functions_REJ_cmd_resp) && pval & PV_HDLC_Optional_Functions_SREJ_cmd_resp) { if (pval & PV_HDLC_Optional_Functions_SREJ_cmd_resp) {
result->rej = selective_reject; /* Only SREJ is set */
strlcat (desc, "SREJ ", desc_size); strlcat (desc, "SREJ ", desc_size);
} }
if (pval & PV_HDLC_Optional_Functions_Multi_SREJ_cmd_resp) {
strlcat (desc, "Multi-SREJ ", desc_size);
}
if (pval & PV_HDLC_Optional_Functions_Multi_SREJ_cmd_resp) {
result->srej = srej_multi;
}
else if (pval & PV_HDLC_Optional_Functions_SREJ_cmd_resp) {
result->srej = srej_single;
}
else if (pval & PV_HDLC_Optional_Functions_REJ_cmd_resp) {
result->srej = srej_none;
}
else { else {
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
dw_printf ("XID error: Expected one or both of REJ, SREJ to be set.\n"); dw_printf ("XID error: Expected at least one of REJ, SREJ, Multi-SREJ to be set.\n");
result->srej = srej_none;
} }
if ((pval & PV_HDLC_Optional_Functions_Modulo_8) && ! (pval & PV_HDLC_Optional_Functions_Modulo_128)) { if ((pval & PV_HDLC_Optional_Functions_Modulo_8) && ! (pval & PV_HDLC_Optional_Functions_Modulo_128)) {
@ -331,10 +371,10 @@ int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, ch
* 0 = half duplex. * 0 = half duplex.
* 1 = full duplex. * 1 = full duplex.
* *
* rej - One of: implicit_reject, selective_reject, selective_reject_reject. * srej - Level of selective reject.
* As command, what am I capable of processing? * srej_none (use REJ), srej_single, srej_multi
* As response, take minimum of * As command, offer a menu of what I can handle. (i.e. perhaps multiple bits set)
* * As response, take minimum of what is offered and what I can handle. (one bit set)
* *
* modulo - 8 or 128. * modulo - 8 or 128.
* *
@ -355,6 +395,8 @@ int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, ch
* Default is 10. * Default is 10.
* Use G_UNKNOWN to omit this. * Use G_UNKNOWN to omit this.
* *
* cr - Is it a command or response?
*
* Outputs: info - Information part of XID frame. * Outputs: info - Information part of XID frame.
* Does not include the control byte. * Does not include the control byte.
* Use buffer of 40 bytes just to be safe. * Use buffer of 40 bytes just to be safe.
@ -382,10 +424,17 @@ int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, ch
* Comment: I have a problem with "... occurs at any time." What if we were in the middle * Comment: I have a problem with "... occurs at any time." What if we were in the middle
* of transferring a large file with k=32 then along comes XID which says switch to modulo 8? * of transferring a large file with k=32 then along comes XID which says switch to modulo 8?
* *
* Insight: Or is it Erratum?
* After reading the base standards documents, it seems that the XID command should offer
* up a menu of all the acceptable choices. e.g. REJ, SREJ, Multi-SREJ. One or more bits
* can be set. The XID response, would set a single bit which is the desired choice from
* among those offered.
* Should go back and review half/full duplex and modulo.
*
*--------------------------------------------------------------------*/ *--------------------------------------------------------------------*/
int xid_encode (struct xid_param_s *param, unsigned char *info) int xid_encode (struct xid_param_s *param, unsigned char *info, cmdres_t cr)
{ {
unsigned char *p; unsigned char *p;
int len; int len;
@ -438,11 +487,43 @@ int xid_encode (struct xid_param_s *param, unsigned char *info)
PV_HDLC_Optional_Functions_16_bit_FCS | PV_HDLC_Optional_Functions_16_bit_FCS |
PV_HDLC_Optional_Functions_Synchronous_Tx; PV_HDLC_Optional_Functions_Synchronous_Tx;
if (param->rej == implicit_reject || param->rej == selective_reject_reject || param->rej == unknown_reject) //text_color_set (DW_COLOR_ERROR);
x |= PV_HDLC_Optional_Functions_REJ_cmd_resp; //dw_printf ("****** XID temp hack - test no SREJ ******\n");
// param->srej = srej_none;
if (param->rej == selective_reject || param->rej == selective_reject_reject) if (cr == cr_cmd) {
x |= PV_HDLC_Optional_Functions_SREJ_cmd_resp; // offer a "menu" of acceptable choices. i.e. 1, 2 or 3 bits set.
switch (param->srej) {
case srej_none:
default:
x |= PV_HDLC_Optional_Functions_REJ_cmd_resp;
break;
case srej_single:
x |= PV_HDLC_Optional_Functions_REJ_cmd_resp |
PV_HDLC_Optional_Functions_SREJ_cmd_resp;
break;
case srej_multi:
x |= PV_HDLC_Optional_Functions_REJ_cmd_resp |
PV_HDLC_Optional_Functions_SREJ_cmd_resp |
PV_HDLC_Optional_Functions_Multi_SREJ_cmd_resp;
break;
}
}
else {
// for response, set only a single bit.
switch (param->srej) {
case srej_none:
default:
x |= PV_HDLC_Optional_Functions_REJ_cmd_resp;
break;
case srej_single:
x |= PV_HDLC_Optional_Functions_SREJ_cmd_resp;
break;
case srej_multi:
x |= PV_HDLC_Optional_Functions_Multi_SREJ_cmd_resp;
break;
}
}
if (param->modulo == modulo_128) if (param->modulo == modulo_128)
x |= PV_HDLC_Optional_Functions_Modulo_128; x |= PV_HDLC_Optional_Functions_Modulo_128;
@ -531,7 +612,7 @@ static unsigned char example[27] = {
/* GL */ 0x17, /* (2 bytes) */ /* GL */ 0x17, /* (2 bytes) */
/* PI */ 0x02, /* Parameter Indicator - classes of procedures */ /* PI */ 0x02, /* Parameter Indicator - classes of procedures */
/* PL */ 0x02, /* Parameter Length */ /* PL */ 0x02, /* Parameter Length */
#if 0 // Example in the protocol spec looks wrong. #if 0 // Erratum: Example in the protocol spec looks wrong.
/* PV */ 0x00, /* Parameter Variable - Half Duplex, Async, Balanced Mode */ /* PV */ 0x00, /* Parameter Variable - Half Duplex, Async, Balanced Mode */
/* PV */ 0x20, /* */ /* PV */ 0x20, /* */
#else // I think it should be like this instead. #else // I think it should be like this instead.
@ -545,6 +626,11 @@ static unsigned char example[27] = {
/* PV */ 0x02, /* synchronous transmit */ /* PV */ 0x02, /* synchronous transmit */
/* PI */ 0x06, /* Parameter Indicator - Rx I field length (bits) */ /* PI */ 0x06, /* Parameter Indicator - Rx I field length (bits) */
/* PL */ 0x02, /* Parameter Length */ /* PL */ 0x02, /* Parameter Length */
// Erratum: The text does not say anything about the byte order for multibyte
// numeric values. In the example, we have two cases where 16 bit numbers are
// sent with the more significant byte first.
/* PV */ 0x04, /* Parameter Variable - 1024 bits (128 octets) */ /* PV */ 0x04, /* Parameter Variable - 1024 bits (128 octets) */
/* PV */ 0x00, /* */ /* PV */ 0x00, /* */
/* PI */ 0x08, /* Parameter Indicator - Rx window size */ /* PI */ 0x08, /* Parameter Indicator - Rx window size */
@ -565,7 +651,7 @@ int main (int argc, char *argv[]) {
struct xid_param_s param2; struct xid_param_s param2;
int n; int n;
unsigned char info[40]; // Currently max of 27 but things can change. unsigned char info[40]; // Currently max of 27 but things can change.
char desc[100]; // 80 is not adequate. char desc[150]; // I've seen 109.
/* parse example. */ /* parse example. */
@ -573,13 +659,15 @@ int main (int argc, char *argv[]) {
n = xid_parse (example, sizeof(example), &param, desc, sizeof(desc)); n = xid_parse (example, sizeof(example), &param, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG); text_color_set (DW_COLOR_DEBUG);
dw_printf ("%s\n", desc); dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
assert (n==1); assert (n==1);
assert (param.full_duplex == 0); assert (param.full_duplex == 0);
assert (param.rej == selective_reject_reject); assert (param.srej == srej_single);
assert (param.modulo == modulo_128); assert (param.modulo == modulo_128);
assert (param.i_field_length_rx == 128); assert (param.i_field_length_rx == 128);
assert (param.window_size_rx == 2); assert (param.window_size_rx == 2);
@ -588,7 +676,7 @@ int main (int argc, char *argv[]) {
/* encode and verify it comes out the same. */ /* encode and verify it comes out the same. */
n = xid_encode (&param, info); n = xid_encode (&param, info, cr_cmd);
assert (n == sizeof(example)); assert (n == sizeof(example));
n = memcmp(info, example, 27); n = memcmp(info, example, 27);
@ -599,52 +687,56 @@ int main (int argc, char *argv[]) {
assert (n == 0); assert (n == 0);
/* try a couple different values. */ /* try a couple different values, no srej. */
param.full_duplex = 1; param.full_duplex = 1;
param.rej = implicit_reject; param.srej = srej_none;
param.modulo = modulo_8; param.modulo = modulo_8;
param.i_field_length_rx = 2048; param.i_field_length_rx = 2048;
param.window_size_rx = 3; param.window_size_rx = 3;
param.ack_timer = 1234; param.ack_timer = 1234;
param.retries = 12; param.retries = 12;
n = xid_encode (&param, info); n = xid_encode (&param, info, cr_cmd);
n = xid_parse (info, n, &param2, desc, sizeof(desc)); n = xid_parse (info, n, &param2, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG); text_color_set (DW_COLOR_DEBUG);
dw_printf ("%s\n", desc); dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
assert (param2.full_duplex == 1); assert (param2.full_duplex == 1);
assert (param2.rej == implicit_reject); assert (param2.srej == srej_none);
assert (param2.modulo == modulo_8); assert (param2.modulo == modulo_8);
assert (param2.i_field_length_rx == 2048); assert (param2.i_field_length_rx == 2048);
assert (param2.window_size_rx == 3); assert (param2.window_size_rx == 3);
assert (param2.ack_timer == 1234); assert (param2.ack_timer == 1234);
assert (param2.retries == 12); assert (param2.retries == 12);
/* The third possbility for rej. We don't use this. */ /* Other values, single srej. */
param.full_duplex = 0; param.full_duplex = 0;
param.rej = selective_reject; param.srej = srej_single;
param.modulo = modulo_8; param.modulo = modulo_8;
param.i_field_length_rx = 61; param.i_field_length_rx = 61;
param.window_size_rx = 4; param.window_size_rx = 4;
param.ack_timer = 5555; param.ack_timer = 5555;
param.retries = 9; param.retries = 9;
n = xid_encode (&param, info); n = xid_encode (&param, info, cr_cmd);
n = xid_parse (info, n, &param2, desc, sizeof(desc)); n = xid_parse (info, n, &param2, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG); text_color_set (DW_COLOR_DEBUG);
dw_printf ("%s\n", desc); dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
assert (param2.full_duplex == 0); assert (param2.full_duplex == 0);
assert (param2.rej == selective_reject); assert (param2.srej == srej_single);
assert (param2.modulo == modulo_8); assert (param2.modulo == modulo_8);
assert (param2.i_field_length_rx == 61); assert (param2.i_field_length_rx == 61);
assert (param2.window_size_rx == 4); assert (param2.window_size_rx == 4);
@ -652,26 +744,57 @@ int main (int argc, char *argv[]) {
assert (param2.retries == 9); assert (param2.retries == 9);
/* Other values, multi srej. */
param.full_duplex = 0;
param.srej = srej_multi;
param.modulo = modulo_128;
param.i_field_length_rx = 61;
param.window_size_rx = 4;
param.ack_timer = 5555;
param.retries = 9;
n = xid_encode (&param, info, cr_cmd);
n = xid_parse (info, n, &param2, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG);
dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR);
assert (param2.full_duplex == 0);
assert (param2.srej == srej_multi);
assert (param2.modulo == modulo_128);
assert (param2.i_field_length_rx == 61);
assert (param2.window_size_rx == 4);
assert (param2.ack_timer == 5555);
assert (param2.retries == 9);
/* Specify some and not others. */ /* Specify some and not others. */
param.full_duplex = 0; param.full_duplex = 0;
param.rej = selective_reject; param.srej = srej_single;
param.modulo = modulo_8; param.modulo = modulo_8;
param.i_field_length_rx = G_UNKNOWN; param.i_field_length_rx = G_UNKNOWN;
param.window_size_rx = G_UNKNOWN; param.window_size_rx = G_UNKNOWN;
param.ack_timer = 999; param.ack_timer = 999;
param.retries = G_UNKNOWN; param.retries = G_UNKNOWN;
n = xid_encode (&param, info); n = xid_encode (&param, info, cr_cmd);
n = xid_parse (info, n, &param2, desc, sizeof(desc)); n = xid_parse (info, n, &param2, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG); text_color_set (DW_COLOR_DEBUG);
dw_printf ("%s\n", desc); dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
assert (param2.full_duplex == 0); assert (param2.full_duplex == 0);
assert (param2.rej == selective_reject); assert (param2.srej == srej_single);
assert (param2.modulo == modulo_8); assert (param2.modulo == modulo_8);
assert (param2.i_field_length_rx == G_UNKNOWN); assert (param2.i_field_length_rx == G_UNKNOWN);
assert (param2.window_size_rx == G_UNKNOWN); assert (param2.window_size_rx == G_UNKNOWN);
@ -684,12 +807,14 @@ int main (int argc, char *argv[]) {
n = xid_parse (info, n, &param2, desc, sizeof(desc)); n = xid_parse (info, n, &param2, desc, sizeof(desc));
text_color_set (DW_COLOR_DEBUG); text_color_set (DW_COLOR_DEBUG);
dw_printf ("%s\n", desc); dw_printf ("%d: %s\n", __LINE__, desc);
fflush (stdout);
SLEEP_SEC (1);
text_color_set (DW_COLOR_ERROR); text_color_set (DW_COLOR_ERROR);
assert (param2.full_duplex == G_UNKNOWN); assert (param2.full_duplex == G_UNKNOWN);
assert (param2.rej == unknown_reject); assert (param2.srej == srej_not_specified);
assert (param2.modulo == modulo_unknown); assert (param2.modulo == modulo_unknown);
assert (param2.i_field_length_rx == G_UNKNOWN); assert (param2.i_field_length_rx == G_UNKNOWN);
assert (param2.window_size_rx == G_UNKNOWN); assert (param2.window_size_rx == G_UNKNOWN);

9
xid.h
View File

@ -2,6 +2,7 @@
/* xid.h */ /* xid.h */
#include "ax25_pad.h" // for enum ax25_modulo_e #include "ax25_pad.h" // for enum ax25_modulo_e
@ -9,10 +10,10 @@ struct xid_param_s {
int full_duplex; int full_duplex;
// Order is important because negotiation keeps the lower value. // Order is important because negotiation keeps the lower value of
// We will support only 1 & 2. // REJ (srej_none), SREJ (default without negotiation), Multi-SREJ (if both agree).
enum rej_e {unknown_reject=0, implicit_reject=1, selective_reject=2, selective_reject_reject=3 } rej; enum srej_e { srej_none=0, srej_single=1, srej_multi=2, srej_not_specified=3 } srej;
enum ax25_modulo_e modulo; enum ax25_modulo_e modulo;
@ -28,4 +29,4 @@ struct xid_param_s {
int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, char *desc, int desc_size); int xid_parse (unsigned char *info, int info_len, struct xid_param_s *result, char *desc, int desc_size);
int xid_encode (struct xid_param_s *param, unsigned char *info); int xid_encode (struct xid_param_s *param, unsigned char *info, cmdres_t cr);