Fix numerous XID negotiation bugs

Changes:

    * Fix Classes of Operations and HDLC parameter bit flags in
      include/patty/ax25.h to match the documentation after more careful
      analysis; resolve issues with byte order

    * Add support for previously missing HDLC parameters to function
      patty_print_params()

    * Fix Info TX/RX field encodings to be in bits, rather than bytes

    * Implement patty_ax25_sock_realloc_bufs() to reallocate buffers
      based on current window and I frame sizes

    * Implement patty_ax25_sock_params_upgrade() to upgrade a socket's
      parameters to the AX.25 v2.2 documented defaults; this will not
      change parameters if the socket is already set to v2.2

    * Implement patty_ax25_sock_params_max() to upgrade a socket's
      parameters to the highest values supported by patty

    * Reimplement patty_ax25_sock_send_xid() to send highest desired
      parameters, rather than the values currently set on the socket

    * When receiving XID frames destined to listening sockets, use
      patty_ax25_sock_params_max() to negotiate from high to low
      parameters

    * When receiving SABME flags, use patty_ax25_sock_params_upgrade()
      to ensure at least base AX.25 v2.2 parameter defaults are set

    * Fix issue where outbound connections initiated with XID were
      unable to time out after N retries
This commit is contained in:
XANTRONIX 2020-08-03 02:54:49 -04:00 committed by XANTRONIX Industrial
parent c287eb7a61
commit 575adc5d31
5 changed files with 125 additions and 82 deletions

View file

@ -60,20 +60,29 @@ enum patty_ax25_param_type {
PATTY_AX25_PARAM_RETRY = 10
};
/*
* Note: These values are byte swapped from their listed order as per
* AX.25 v2.2 Section 4.3.37 "Exchange Identification (XID) Frame"; bits 0-7
* are in the first byte, 8-15 in the second, and 16-23 in the third.
* The bit positions are shown in their original order (plus one) in the
* aforementioned figure in the AX.25 v2.2 spec.
*/
enum patty_ax25_param_classes {
PATTY_AX25_PARAM_CLASSES_ABM = (1 << 0),
PATTY_AX25_PARAM_CLASSES_HALF_DUPLEX = (1 << 5),
PATTY_AX25_PARAM_CLASSES_FULL_DUPLEX = (1 << 6)
PATTY_AX25_PARAM_CLASSES_ABM = (1 << 0) << 8,
PATTY_AX25_PARAM_CLASSES_HALF_DUPLEX = (1 << 5) << 8,
PATTY_AX25_PARAM_CLASSES_FULL_DUPLEX = (1 << 6) << 8
};
enum patty_ax25_param_hdlc {
PATTY_AX25_PARAM_HDLC_REJ = (1 << 1),
PATTY_AX25_PARAM_HDLC_SREJ = (1 << 2),
PATTY_AX25_PARAM_HDLC_XADDR = (1 << 8),
PATTY_AX25_PARAM_HDLC_MODULO_8 = (1 << 11),
PATTY_AX25_PARAM_HDLC_MODULO_128 = (1 << 12),
PATTY_AX25_PARAM_HDLC_TEST = (1 << 14),
PATTY_AX25_PARAM_HDLC_SYNC_TX = (1 << 18)
PATTY_AX25_PARAM_HDLC_REJ = (1 << 1) << 16,
PATTY_AX25_PARAM_HDLC_SREJ = (1 << 2) << 16,
PATTY_AX25_PARAM_HDLC_XADDR = (1 << 7) << 16,
PATTY_AX25_PARAM_HDLC_MODULO_8 = (1 << 10),
PATTY_AX25_PARAM_HDLC_MODULO_128 = (1 << 11),
PATTY_AX25_PARAM_HDLC_TEST = (1 << 13),
PATTY_AX25_PARAM_HDLC_FCS_16 = (1 << 15),
PATTY_AX25_PARAM_HDLC_SYNC_TX = (1 << 17) >> 16,
PATTY_AX25_PARAM_HDLC_SREJ_MULTI = (1 << 21) >> 16
};
typedef struct _patty_ax25_params {

View file

@ -15,18 +15,27 @@
| PATTY_AX25_PARAM_HDLC_TEST | PATTY_AX25_PARAM_HDLC_SYNC_TX)
#define PATTY_AX25_SOCK_2_2_DEFAULT_HDLC \
(PATTY_AX25_PARAM_HDLC_REJ | PATTY_AX25_PARAM_HDLC_SREJ \
| PATTY_AX25_PARAM_HDLC_XADDR | PATTY_AX25_PARAM_HDLC_MODULO_128 \
| PATTY_AX25_PARAM_HDLC_TEST | PATTY_AX25_PARAM_HDLC_SYNC_TX)
(PATTY_AX25_PARAM_HDLC_REJ | PATTY_AX25_PARAM_HDLC_SREJ \
| PATTY_AX25_PARAM_HDLC_XADDR | PATTY_AX25_PARAM_HDLC_MODULO_128 \
| PATTY_AX25_PARAM_HDLC_TEST | PATTY_AX25_PARAM_HDLC_FCS_16 \
| PATTY_AX25_PARAM_HDLC_SYNC_TX)
#define PATTY_AX25_SOCK_DEFAULT_MAXLEN 256
#define PATTY_AX25_SOCK_DEFAULT_WINDOW 4
#define PATTY_AX25_SOCK_DEFAULT_WINDOW_SABME 32
#define PATTY_AX25_SOCK_DEFAULT_RETRY 10
#define PATTY_AX25_SOCK_DEFAULT_ACK 3000
#define PATTY_AX25_SOCK_2_2_MAX_HDLC \
(PATTY_AX25_PARAM_HDLC_REJ | PATTY_AX25_PARAM_HDLC_SREJ \
| PATTY_AX25_PARAM_HDLC_XADDR | PATTY_AX25_PARAM_HDLC_MODULO_128 \
| PATTY_AX25_PARAM_HDLC_TEST | PATTY_AX25_PARAM_HDLC_FCS_16 \
| PATTY_AX25_PARAM_HDLC_SYNC_TX | PATTY_AX25_PARAM_HDLC_SREJ_MULTI)
#define PATTY_AX25_SOCK_2_2_DEFAULT_MAXLEN 4096
#define PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW 127
#define PATTY_AX25_SOCK_DEFAULT_I_LEN 256
#define PATTY_AX25_SOCK_DEFAULT_WINDOW 4
#define PATTY_AX25_SOCK_DEFAULT_RETRY 10
#define PATTY_AX25_SOCK_DEFAULT_ACK 3000
#define PATTY_AX25_SOCK_2_2_DEFAULT_I_LEN 256
#define PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW 32
#define PATTY_AX25_SOCK_2_2_MAX_I_LEN 1536
#define PATTY_AX25_SOCK_2_2_MAX_WINDOW 127
enum patty_ax25_sock_type {
PATTY_AX25_SOCK_STREAM,
@ -97,20 +106,23 @@ typedef struct _patty_ax25_sock {
unsigned int hops;
} patty_ax25_sock;
void patty_ax25_sock_init(patty_ax25_sock *sock);
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_proto proto,
enum patty_ax25_sock_type type);
void patty_ax25_sock_destroy(patty_ax25_sock *sock);
int patty_ax25_sock_reset(patty_ax25_sock *sock);
void patty_ax25_sock_init(patty_ax25_sock *sock);
int patty_ax25_sock_upgrade(patty_ax25_sock *sock,
enum patty_ax25_version version);
void patty_ax25_sock_reset(patty_ax25_sock *sock);
int patty_ax25_sock_params_set(patty_ax25_sock *sock,
patty_ax25_params *params);
void patty_ax25_sock_params_upgrade(patty_ax25_sock *sock);
void patty_ax25_sock_params_max(patty_ax25_sock *sock);
int patty_ax25_sock_params_negotiate(patty_ax25_sock *sock,
patty_ax25_params *params);
int patty_ax25_sock_realloc_bufs(patty_ax25_sock *sock);
char *patty_ax25_sock_pty(patty_ax25_sock *sock);

View file

@ -158,7 +158,9 @@ int patty_print_params(FILE *fh,
{ PATTY_AX25_PARAM_HDLC_MODULO_8, "modulo 8" },
{ PATTY_AX25_PARAM_HDLC_MODULO_128, "modulo 128" },
{ PATTY_AX25_PARAM_HDLC_TEST, "TEST" },
{ PATTY_AX25_PARAM_HDLC_FCS_16, "16-bit FCS" },
{ PATTY_AX25_PARAM_HDLC_SYNC_TX, "synchronous TX" },
{ PATTY_AX25_PARAM_HDLC_SREJ_MULTI, "multiple SREJ" },
{ 0, NULL }
};

View file

@ -1213,8 +1213,18 @@ static int handle_sabm(patty_ax25_server *server,
}
remote->status = PATTY_AX25_SOCK_ESTABLISHED;
remote->mode = (frame->type == PATTY_AX25_FRAME_SABME)?
PATTY_AX25_SOCK_SABME: PATTY_AX25_SOCK_SABM;
if (frame->type == PATTY_AX25_FRAME_SABME) {
patty_ax25_sock_params_upgrade(remote);
remote->mode = PATTY_AX25_SOCK_SABME;
} else {
remote->mode = PATTY_AX25_SOCK_SABM;
}
if (patty_ax25_sock_realloc_bufs(remote) < 0) {
goto error_sock_realloc_bufs;
}
patty_ax25_sock_bind_if(remote, iface);
@ -1235,6 +1245,7 @@ static int handle_sabm(patty_ax25_server *server,
return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL);
error_respond_accept:
error_sock_realloc_bufs:
error_sock_save:
patty_ax25_sock_destroy(remote);
@ -1273,6 +1284,10 @@ static int handle_ua(patty_ax25_server *server,
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
}
if (patty_ax25_sock_realloc_bufs(sock) < 0) {
goto error_sock_realloc_bufs;
}
patty_timer_stop(&sock->timer_t1);
patty_timer_start(&sock->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE);
@ -1292,8 +1307,7 @@ static int handle_ua(patty_ax25_server *server,
return respond_connect(client, 0, 0);
error_sock_save:
patty_ax25_sock_destroy(sock);
error_sock_realloc_bufs:
error_client_by_sock:
return -1;
}
@ -1482,17 +1496,14 @@ static int handle_xid(patty_ax25_server *server,
* upgrade the socket defaults accordingly, and negotiate downwards
* as necessary.
*/
if (patty_ax25_sock_upgrade(remote, PATTY_AX25_2_2) < 0) {
goto error_sock_upgrade;
}
if (patty_ax25_sock_params_set(remote, &params) < 0) {
if (patty_ax25_sock_params_negotiate(remote, &params) < 0) {
int client;
if ((client = client_by_sock(server, remote)) < 0) {
goto error_client_by_sock;
}
patty_ax25_sock_init(remote);
patty_ax25_sock_reset(remote);
return respond_connect(client, -1, errno);
@ -1540,9 +1551,9 @@ static int handle_xid(patty_ax25_server *server,
patty_ax25_sock_bind_if(remote, iface);
patty_ax25_sock_upgrade(remote, PATTY_AX25_2_2);
patty_ax25_sock_params_max(remote);
if (patty_ax25_sock_params_set(remote, &params) < 0) {
if (patty_ax25_sock_params_negotiate(remote, &params) < 0) {
patty_ax25_sock_destroy(remote);
return respond_accept(client, -1, errno, NULL, NULL);
@ -1563,7 +1574,6 @@ reply_dm:
error_sock_save:
error_sock_new:
error_client_by_sock:
error_sock_upgrade:
error_io:
return -1;
}
@ -1699,9 +1709,16 @@ static int handle_sock(uint32_t key,
return ret;
} else {
(void)sock_shutdown(server, sock);
int client;
return sock_close(server, sock);
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
}
(void)sock_shutdown(server, sock);
(void)sock_close(server, sock);
return respond_connect(client, -1, ETIMEDOUT);
}
}
@ -1795,6 +1812,7 @@ static int handle_sock(uint32_t key,
done:
return 0;
error_client_by_sock:
error_sock_write:
error_io:
return -1;

View file

@ -93,17 +93,6 @@ error_realloc_tx_buf:
return -1;
}
void patty_ax25_sock_init(patty_ax25_sock *sock) {
sock->status = PATTY_AX25_SOCK_CLOSED;
sock->mode = PATTY_AX25_SOCK_DM;
sock->n_maxlen_tx = PATTY_AX25_SOCK_DEFAULT_MAXLEN;
sock->n_maxlen_rx = PATTY_AX25_SOCK_DEFAULT_MAXLEN;
sock->n_window_tx = PATTY_AX25_SOCK_DEFAULT_WINDOW;
sock->n_window_rx = PATTY_AX25_SOCK_DEFAULT_WINDOW;
sock->n_ack = PATTY_AX25_SOCK_DEFAULT_ACK;
sock->n_retry = PATTY_AX25_SOCK_DEFAULT_RETRY;
}
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_proto proto,
enum patty_ax25_sock_type type) {
patty_ax25_sock *sock;
@ -159,10 +148,23 @@ void patty_ax25_sock_destroy(patty_ax25_sock *sock) {
free(sock);
}
void patty_ax25_sock_init(patty_ax25_sock *sock) {
sock->status = PATTY_AX25_SOCK_CLOSED;
sock->mode = PATTY_AX25_SOCK_DM;
sock->n_maxlen_tx = PATTY_AX25_SOCK_DEFAULT_I_LEN;
sock->n_maxlen_rx = PATTY_AX25_SOCK_DEFAULT_I_LEN;
sock->n_window_tx = PATTY_AX25_SOCK_DEFAULT_WINDOW;
sock->n_window_rx = PATTY_AX25_SOCK_DEFAULT_WINDOW;
sock->n_ack = PATTY_AX25_SOCK_DEFAULT_ACK;
sock->n_retry = PATTY_AX25_SOCK_DEFAULT_RETRY;
sock->retries = PATTY_AX25_SOCK_DEFAULT_RETRY;
sock->pending = 0;
}
/*
* AX.25 v2.2 Specification, Section 6.5 "Resetting Procedure"
*/
int patty_ax25_sock_reset(patty_ax25_sock *sock) {
void patty_ax25_sock_reset(patty_ax25_sock *sock) {
sock->seq_send = 0;
sock->seq_recv = 0;
sock->retries = sock->n_retry;
@ -171,36 +173,32 @@ int patty_ax25_sock_reset(patty_ax25_sock *sock) {
patty_timer_clear(&sock->timer_t1);
patty_timer_clear(&sock->timer_t2);
patty_timer_clear(&sock->timer_t3);
return 0;
}
int patty_ax25_sock_upgrade(patty_ax25_sock *sock,
enum patty_ax25_version version) {
if (sock->version >= version) {
return 0;
void patty_ax25_sock_params_upgrade(patty_ax25_sock *sock) {
if (sock->version >= PATTY_AX25_2_2) {
return;
}
switch (version) {
case PATTY_AX25_OLD:
case PATTY_AX25_2_0:
break;
case PATTY_AX25_2_2:
sock->flags_hdlc = PATTY_AX25_SOCK_2_2_DEFAULT_HDLC;
sock->n_maxlen_tx = PATTY_AX25_SOCK_2_2_DEFAULT_MAXLEN;
sock->n_maxlen_rx = PATTY_AX25_SOCK_2_2_DEFAULT_MAXLEN;
sock->n_window_tx = PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW;
sock->n_window_rx = PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW;
}
sock->version = version;
return init_bufs(sock);
sock->version = PATTY_AX25_2_2;
sock->flags_hdlc = PATTY_AX25_SOCK_2_2_DEFAULT_HDLC;
sock->n_maxlen_tx = PATTY_AX25_SOCK_2_2_DEFAULT_I_LEN;
sock->n_maxlen_rx = PATTY_AX25_SOCK_2_2_DEFAULT_I_LEN;
sock->n_window_tx = PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW;
sock->n_window_rx = PATTY_AX25_SOCK_2_2_DEFAULT_WINDOW;
}
int patty_ax25_sock_params_set(patty_ax25_sock *sock,
patty_ax25_params *params) {
void patty_ax25_sock_params_max(patty_ax25_sock *sock) {
sock->version = PATTY_AX25_2_2;
sock->flags_hdlc = PATTY_AX25_SOCK_2_2_MAX_HDLC;
sock->n_maxlen_tx = PATTY_AX25_SOCK_2_2_MAX_I_LEN;
sock->n_maxlen_rx = PATTY_AX25_SOCK_2_2_MAX_I_LEN;
sock->n_window_tx = PATTY_AX25_SOCK_2_2_MAX_WINDOW;
sock->n_window_rx = PATTY_AX25_SOCK_2_2_MAX_WINDOW;
}
int patty_ax25_sock_params_negotiate(patty_ax25_sock *sock,
patty_ax25_params *params) {
if (params->flags & PATTY_AX25_PARAM_CLASSES) {
if (!(params->classes & PATTY_AX25_PARAM_CLASSES_ABM)) {
goto error_notsup;
@ -251,7 +249,7 @@ int patty_ax25_sock_params_set(patty_ax25_sock *sock,
}
if (params->flags & PATTY_AX25_PARAM_INFO_RX) {
if (sock->n_maxlen_tx > params->info_rx) {
if (sock->n_maxlen_tx > params->info_rx >> 3) {
sock->n_maxlen_tx = params->info_rx >> 3;
}
}
@ -274,7 +272,7 @@ int patty_ax25_sock_params_set(patty_ax25_sock *sock,
}
}
return init_bufs(sock);
return 0;
error_notsup:
errno = ENOTSUP;
@ -287,6 +285,10 @@ error_invalid:
return -1;
}
int patty_ax25_sock_realloc_bufs(patty_ax25_sock *sock) {
return init_bufs(sock);
}
char *patty_ax25_sock_pty(patty_ax25_sock *sock) {
return sock->pty;
}
@ -559,9 +561,9 @@ ssize_t patty_ax25_sock_send_xid(patty_ax25_sock *sock,
| (1 << PATTY_AX25_PARAM_RETRY);
params.classes = sock->flags_classes;
params.hdlc = sock->flags_hdlc;
params.info_rx = sock->n_maxlen_rx << 3;
params.window_rx = sock->n_window_rx;
params.hdlc = PATTY_AX25_SOCK_2_2_MAX_HDLC;
params.info_rx = PATTY_AX25_SOCK_2_2_MAX_I_LEN << 3;
params.window_rx = PATTY_AX25_SOCK_2_2_MAX_WINDOW;
params.ack = sock->n_ack;
params.retry = sock->n_retry;