mirror of https://github.com/wb2osz/direwolf.git
More efficient and reliable connected mode lost frame recovery.
This commit is contained in:
parent
3611971fe7
commit
9cd305950f
667
ax25_link.c
667
ax25_link.c
File diff suppressed because it is too large
Load Diff
60
ax25_pad2.c
60
ax25_pad2.c
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
205
xid.c
205
xid.c
|
@ -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) {
|
||||||
|
// 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;
|
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), ¶m, desc, sizeof(desc));
|
n = xid_parse (example, sizeof(example), ¶m, 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 (¶m, info);
|
n = xid_encode (¶m, 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 (¶m, info);
|
n = xid_encode (¶m, info, cr_cmd);
|
||||||
n = xid_parse (info, n, ¶m2, desc, sizeof(desc));
|
n = xid_parse (info, n, ¶m2, 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 (¶m, info);
|
n = xid_encode (¶m, info, cr_cmd);
|
||||||
n = xid_parse (info, n, ¶m2, desc, sizeof(desc));
|
n = xid_parse (info, n, ¶m2, 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 (¶m, info, cr_cmd);
|
||||||
|
n = xid_parse (info, n, ¶m2, 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 (¶m, info);
|
n = xid_encode (¶m, info, cr_cmd);
|
||||||
n = xid_parse (info, n, ¶m2, desc, sizeof(desc));
|
n = xid_parse (info, n, ¶m2, 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, ¶m2, desc, sizeof(desc));
|
n = xid_parse (info, n, ¶m2, 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
9
xid.h
|
@ -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);
|
Loading…
Reference in New Issue