Skip to content

Commit 9aba4b3

Browse files
committed
AX.25 v2.2 improvements
1 parent 485ccbf commit 9aba4b3

7 files changed

Lines changed: 210 additions & 44 deletions

File tree

src/ax25_link.c

Lines changed: 146 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,6 +1265,15 @@ void dl_data_request (dlq_item_t *E)
12651265
dw_printf ("\") state=%d\n", S->state);
12661266
}
12671267

1268+
// JWL - I think we want to discard if in disconnected state.
1269+
// App could contine sending data after a disconnection.
1270+
1271+
if (S->state == state_0_disconnected) {
1272+
cdata_delete (E->txdata);
1273+
E->txdata = NULL;
1274+
return;
1275+
}
1276+
12681277
if (E->txdata->len <= S->n1_paclen) {
12691278
data_request_good_size (S, E->txdata);
12701279
E->txdata = NULL; // Now part of transmit I frame queue.
@@ -5078,9 +5087,9 @@ static void ui_frame (ax25_dlsm_t *S, cmdres_t cr, int pf)
50785087
static void xid_frame (ax25_dlsm_t *S, cmdres_t cr, int pf, unsigned char *info_ptr, int info_len)
50795088
{
50805089
struct xid_param_s param;
5081-
char desc[150];
5090+
char desc[256];
50825091
int ok;
5083-
unsigned char xinfo[40];
5092+
unsigned char xinfo[80]; // about twice max possible size
50845093
int xlen;
50855094
cmdres_t res = cr_res;
50865095
int f = 1;
@@ -5546,7 +5555,7 @@ static void tm201_expiry (ax25_dlsm_t *S)
55465555
{
55475556

55485557
struct xid_param_s param;
5549-
unsigned char xinfo[40];
5558+
unsigned char xinfo[80]; // about twice max possible size
55505559
int xlen;
55515560
cmdres_t cmd = cr_cmd;
55525561
int p = 1;
@@ -6603,8 +6612,8 @@ static void enter_new_state (ax25_dlsm_t *S, enum dlsm_state_e new_state, const
66036612
static void mdl_negotiate_request (ax25_dlsm_t *S)
66046613
{
66056614
struct xid_param_s param;
6606-
unsigned char xinfo[40];
6607-
int xlen;
6615+
unsigned char xinfo[80]; // about twice max possible size
6616+
int xlen;
66086617
cmdres_t cmd = cr_cmd;
66096618
int p = 1;
66106619
int nopid = 0;
@@ -6661,6 +6670,7 @@ static void mdl_negotiate_request (ax25_dlsm_t *S)
66616670
static void initiate_negotiation (ax25_dlsm_t *S, struct xid_param_s *param)
66626671
{
66636672
param->full_duplex = 0;
6673+
66646674
switch (S->srej_enable) {
66656675
case srej_single:
66666676
case srej_multi:
@@ -6673,20 +6683,66 @@ static void initiate_negotiation (ax25_dlsm_t *S, struct xid_param_s *param)
66736683
}
66746684

66756685
param->modulo = S->modulo;
6676-
param->i_field_length_rx = S->n1_paclen; // Hmmmm. Should we ask for what the user
6677-
// specified for PACLEN or offer the maximum
6678-
// that we can handle, AX25_N1_PACLEN_MAX?
6679-
param->window_size_rx = S->k_maxframe;
6680-
param->ack_timer = (int)(g_misc_config_p->frack * 1000);
6681-
param->retries = S->n2_retry;
6686+
6687+
/*
6688+
* I‑Field Length TX
6689+
* This is the maximum I‑frame payload size that I will transmit.
6690+
* The XID command tells the peer:
6691+
* "The largest I‑frame I will send to you is N bytes."
6692+
* This is about my outbound frame size.
6693+
*
6694+
* Note that the response could be smaller so we'd have
6695+
* to reduce working paclen.
6696+
*/
6697+
param->i_field_length_tx = S->n1_paclen; // PACLEN from configuration file.
6698+
6699+
/*
6700+
* I‑Field Length RX
6701+
* This is the maximum I‑frame payload size that I am capable of receiving.
6702+
* The XID command tells the peer:
6703+
* "The largest I‑frame I can handle from you is N bytes."
6704+
* This is about my inbound frame size.
6705+
*/
6706+
param->i_field_length_rx = AX25_N1_PACLEN_MAX;
6707+
6708+
/*
6709+
* window_size_tx
6710+
* This is the size of the transmit window that I will use when sending I‑frames.
6711+
* - The XID command tells the peer:
6712+
* "I will send up to N unacknowledged frames at a time."
6713+
* - It defines my outbound pipeline depth.
6714+
* - Larger TX window = I can send more before waiting for RR/RNR/ACK.
6715+
* This initially comes from the configuration file EMAXFRAME but
6716+
* can be scaled back by the XID exchange if the other side doesn't
6717+
* have enough buffer space. Also known as "k".
6718+
*/
6719+
param->window_size_tx = S->k_maxframe;
6720+
6721+
/*
6722+
* window_size_rx
6723+
* This is the size of the receive window that I can accept from the peer.
6724+
* - The XID command tells the peer:
6725+
* "You may send me up to N unacknowledged frames before I must ACK."
6726+
* - It defines my inbound buffering capability.
6727+
* - Larger RX window = the peer can send more before needing my RR.
6728+
* I would offer AX25_K_MAXFRAME_EXTENDED_MAX (63) because I don't have memory
6729+
* constraints. I really don't care what the peer has to say about this.
6730+
* I generate an ack, of some sort, at the end of the incoming
6731+
* transmission, i.e. when DCD drops.
6732+
*/
6733+
param->window_size_rx = AX25_K_MAXFRAME_EXTENDED_MAX;
6734+
6735+
param->ack_timer = (int)(g_misc_config_p->frack * 1000); // "T1" in milliseconds
6736+
6737+
param->retries = S->n2_retry; // "N1"
66826738
}
66836739

66846740

66856741
/*------------------------------------------------------------------------------
66866742
*
66876743
* Name: negotiation_response
66886744
*
6689-
* Purpose: Used when receiving the XID command and preparing the XID response.
6745+
* Purpose: Used when receiving the XID *command* and preparing the XID response.
66906746
*
66916747
* Description: Take what other station has asked for and reduce if we have lesser capabilities.
66926748
* For example if other end wants 8k information part we reduce it to 2k.
@@ -6711,9 +6767,11 @@ static void negotiation_response (ax25_dlsm_t *S, struct xid_param_s *param)
67116767

67126768
// Other end might want 8.
67136769
// Seems unlikely. If it implements XID it should have modulo 128.
6770+
// It would be REALLY BAD if we started out with 128, started exchanging
6771+
// I Frames, then the XID exchange wanted to change it to 8.
67146772

67156773
if (param->modulo == modulo_unknown) {
6716-
param->modulo = 8; // Not specified. Set default.
6774+
param->modulo = 128; // Not specified. Set default.
67176775
}
67186776
else {
67196777
param->modulo = MIN(param->modulo, 128);
@@ -6727,29 +6785,54 @@ static void negotiation_response (ax25_dlsm_t *S, struct xid_param_s *param)
67276785
param->srej = (param->modulo == 128) ? srej_single : srej_none; // not specified, set default
67286786
}
67296787

6730-
// We can currently do up to 2k.
6788+
// i_field_length_TX is what other station wants for it's outgoing paclen.
6789+
// We can currently handle up to 2k.
67316790
// Take minimum of that and what other guy asks for.
67326791

6792+
if (param->i_field_length_tx == G_UNKNOWN) {
6793+
param->i_field_length_tx = AX25_N1_PACLEN_DEFAULT; // Not specified, take default.
6794+
}
6795+
else {
6796+
param->i_field_length_tx = MIN(param->i_field_length_tx, AX25_N1_PACLEN_MAX);
6797+
}
6798+
6799+
// i_field_length_RX is what other station is capable of receiving.
6800+
// Take minimum of our desired paclen and capability other station to receive.
6801+
67336802
if (param->i_field_length_rx == G_UNKNOWN) {
6734-
param->i_field_length_rx = 256; // Not specified, take default.
6803+
param->i_field_length_rx = AX25_N1_PACLEN_DEFAULT; // Not specified, take default.
67356804
}
67366805
else {
6737-
param->i_field_length_rx = MIN(param->i_field_length_rx, AX25_N1_PACLEN_MAX);
6806+
param->i_field_length_rx = MIN(param->i_field_length_rx, S->n1_paclen);
67386807
}
67396808

6740-
// In theory extended mode can have window size of 127 but
6809+
// window_size_TX is what the other end has requested.
6810+
// In theory extended mode can have window size of 127 (for REJ) but
67416811
// I'm limiting it to 63 for the reason mentioned in the SREJ logic.
67426812

6743-
if (param->window_size_rx == G_UNKNOWN) {
6744-
param->window_size_rx = (param->modulo == 128) ? 32 : 4; // not specified, set default.
6813+
if (param->window_size_tx == G_UNKNOWN) {
6814+
param->window_size_tx = (param->modulo == 128) ?
6815+
AX25_K_MAXFRAME_EXTENDED_DEFAULT : AX25_K_MAXFRAME_BASIC_DEFAULT; // not specified, set default.
67456816
}
67466817
else {
67476818
if (param->modulo == 128)
6748-
param->window_size_rx = MIN(param->window_size_rx, AX25_K_MAXFRAME_EXTENDED_MAX);
6819+
param->window_size_tx = MIN(param->window_size_tx, AX25_K_MAXFRAME_EXTENDED_MAX);
67496820
else
6750-
param->window_size_rx = MIN(param->window_size_rx, AX25_K_MAXFRAME_BASIC_MAX);
6821+
param->window_size_tx = MIN(param->window_size_tx, AX25_K_MAXFRAME_BASIC_MAX);
67516822
}
67526823

6824+
// window_size_RX is what the other end is capable of.
6825+
// We should not exceed that for our outgoing I frames.
6826+
6827+
if (param->window_size_rx == G_UNKNOWN) {
6828+
param->window_size_rx = (param->modulo == 128) ?
6829+
AX25_K_MAXFRAME_EXTENDED_DEFAULT : AX25_K_MAXFRAME_BASIC_DEFAULT; // not specified, assume default.
6830+
}
6831+
else {
6832+
param->window_size_rx = MIN(param->window_size_rx, S->k_maxframe);
6833+
}
6834+
6835+
67536836
// Erratum: Unclear. Is the Acknowledgement Timer before or after compensating for digipeaters
67546837
// in the path? e.g. Typically TNCs use the FRACK parameter for this and it often defaults to 3.
67556838
// However, the actual timeout value might be something like FRACK*(2*m+1) where m is the number of
@@ -6801,14 +6884,46 @@ static void complete_negotiation (ax25_dlsm_t *S, struct xid_param_s *param)
68016884
S->modulo = param->modulo;
68026885
}
68036886

6887+
// i_field_length_TX is from viewpoint of other station.
6888+
// Do anything with this?
6889+
6890+
//if (param->i_field_length_tx != G_UNKNOWN) {
6891+
// ...
6892+
//}
6893+
6894+
// i_field_length_RX is from viewpoint of other station.
6895+
// We might need to reduce our paclen value if other station has lower limit.
6896+
68046897
if (param->i_field_length_rx != G_UNKNOWN) {
6805-
S->n1_paclen = param->i_field_length_rx;
6898+
if (S->n1_paclen > param->i_field_length_rx) {
6899+
text_color_set (DW_COLOR_INFO);
6900+
dw_printf ("Reducing our PACLEN from %d to %d as result of XID exchange.\n",
6901+
S->n1_paclen, param->i_field_length_rx);
6902+
S->n1_paclen = param->i_field_length_rx;
6903+
}
68066904
}
68076905

6906+
// window_size_TX from view point of other station. What it wants to send.
6907+
// Do anything with this?
6908+
6909+
//if (param->window_size_tx != G_UNKNOWN) {
6910+
// ...
6911+
//}
6912+
6913+
// window_size_RX from view point of other station.
6914+
// We might need to reduce our maxframe value if other station has lower limit.
6915+
68086916
if (param->window_size_rx != G_UNKNOWN) {
6809-
S->k_maxframe = param->window_size_rx;
6917+
if (S->k_maxframe > param->window_size_rx) {
6918+
text_color_set (DW_COLOR_INFO);
6919+
dw_printf ("Reducing our EMAXFRAME from %d to %d as result of XID exchange.\n",
6920+
S->k_maxframe, param->window_size_rx);
6921+
S->k_maxframe = param->window_size_rx;
6922+
}
68106923
}
68116924

6925+
// FIXME: revisit this.
6926+
68126927
if (param->ack_timer != G_UNKNOWN) {
68136928
S->t1v = param->ack_timer * 0.001;
68146929
}
@@ -6952,6 +7067,14 @@ static void resume_t1 (ax25_dlsm_t *S, const char *from_func, int from_line)
69527067
text_color_set(DW_COLOR_DEBUG);
69537068
dw_printf ("Resumed T1 after pausing for %.3f sec, %.3f still remaining, [now=%.3f]\n", paused_for_sec, S->t1_exp - now, now - S->start_time);
69547069
}
7070+
7071+
// Did it expire already?
7072+
if (S->t1_exp <= now) {
7073+
S->t1_exp = 0;
7074+
S->t1_paused_at = 0;
7075+
S->t1_had_expired = 1;
7076+
t1_expiry (S);
7077+
}
69557078
}
69567079

69577080
} /* end resume_t1 */

src/ax25_link.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
#define AX25_N2_RETRY_MIN 1 // Number of times to retry before giving up.
2525
#define AX25_N2_RETRY_DEFAULT 10
26-
#define AX25_N2_RETRY_MAX 15
26+
#define AX25_N2_RETRY_MAX 20
2727

2828

2929
#define AX25_T1V_FRACK_MIN 2 // Number of seconds to wait before retrying.

src/config.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5580,20 +5580,22 @@ void config_init (char *fname, struct audio_s *p_audio_config,
55805580
*/
55815581

55825582
else if (strcasecmp(t, "RETRY") == 0) {
5583-
int n;
55845583
t = split(NULL,0);
55855584
if (t == NULL) {
55865585
text_color_set(DW_COLOR_ERROR);
55875586
dw_printf ("Line %d: Missing value for RETRY.\n", line);
55885587
continue;
55895588
}
5590-
n = atoi(t);
5591-
if (n >= AX25_N2_RETRY_MIN && n <= AX25_N2_RETRY_MAX) {
5592-
p_misc_config->retry = n;
5589+
p_misc_config->retry = atoi(t);
5590+
if (p_misc_config->retry < AX25_N2_RETRY_MIN) {
5591+
text_color_set(DW_COLOR_ERROR);
5592+
dw_printf ("Line %d: RETRY number can't be less than %d.\n", line, AX25_N2_RETRY_MIN);
5593+
p_misc_config->retry = AX25_N2_RETRY_MIN;
55935594
}
5594-
else {
5595+
if (p_misc_config->retry > AX25_N2_RETRY_MAX) {
55955596
text_color_set(DW_COLOR_ERROR);
5596-
dw_printf ("Line %d: Invalid RETRY number. Using default %d.\n", line, p_misc_config->retry);
5597+
dw_printf ("Line %d: RETRY number can't be greater than %d.\n", line, AX25_N2_RETRY_MAX);
5598+
p_misc_config->retry = AX25_N2_RETRY_MAX;
55975599
}
55985600
}
55995601

src/direwolf.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// This file is part of Dire Wolf, an amateur radio packet TNC.
33
//
4-
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2023, 2024. 2025 John Langner, WB2OSZ
4+
// Copyright (C) 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019, 2020, 2021, 2023, 2024. 2025, 2026 John Langner, WB2OSZ
55
//
66
// This program is free software: you can redistribute it and/or modify
77
// it under the terms of the GNU General Public License as published by
@@ -299,7 +299,7 @@ int main (int argc, char *argv[])
299299

300300
// FIXME: consider case of no space between t and number.
301301

302-
// Prescan for options that are needed before ant text goes to console.
302+
// Prescan for options that are needed before any text goes to console.
303303

304304
for (j=1; j<argc-1; j++) {
305305
if (strcmp(argv[j], "-t") == 0) {
@@ -328,8 +328,9 @@ int main (int argc, char *argv[])
328328

329329
text_color_set(DW_COLOR_INFO);
330330
//dw_printf ("Dire Wolf version %d.%d (%s) BETA TEST 1\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
331-
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "B", __DATE__);
331+
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "C", __DATE__);
332332
// B = new -dq & tcp_wmem
333+
// C = AX.25 v2.2 improvements
333334
//dw_printf ("Dire Wolf Release %d.%d,%d, October 2025\n", MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION);
334335

335336

src/textcolor.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -280,13 +280,13 @@ void dw_printf_capture_init (char *o_opt, char *O_opt)
280280
exit (EXIT_FAILURE);
281281
}
282282
}
283-
printf ("DEBUG O_opt=%s, strlen=%d\n", O_opt, (int)strlen(O_opt));
283+
// printf ("DEBUG O_opt=%s, strlen=%d\n", O_opt, (int)strlen(O_opt));
284284
if (strlen(O_opt) > 0) {
285-
O_fp = fopen (o_opt, "w+");
285+
O_fp = fopen (O_opt, "w");
286286
if (O_fp == NULL) {
287287
text_color_set (DW_COLOR_ERROR);
288288
dw_printf ("Failed to open -O %s for write.\n", O_opt);
289-
dw_printf ("errno=%d\n", errno);
289+
//dw_printf ("errno=%d\n", errno);
290290
exit (EXIT_FAILURE);
291291
}
292292
}

0 commit comments

Comments
 (0)