Attempt to negotiate remote connections with XID

Implement the AX.25 v2.2 XID parameter exchange as a preamble for
initiating connections with peers, with the following workflow:

    * Upon a connect() call, send an XID frame to the peer

    * When a DM is received, assume the peer is unable to accept a
      connection

    * When a FRMR is received, assume the peer does not adhere to the
      AX.25 v2.2 standard, and attempt to initiate a connection with a
      SABM frame instead

    * When an XID is received, adapt local parameters to meet the
      needs of the peer, and respond with an SABM or an SABME frame,
      depending on which mode is indicated
This commit is contained in:
XANTRONIX Development 2020-07-19 23:00:57 -04:00 committed by XANTRONIX Industrial
parent c2550d075a
commit 5371f92cd9

View file

@ -769,21 +769,24 @@ static int server_connect(patty_ax25_server *server,
}
/*
* TODO: Send SABM(E) frame; set timer, and await response from peer.
* We will need to know what client to send a response to when either the
* timeout has been exceeded or the peer has sent a UA frame to
* acknowledge and establish the connection.
* Send an XID frame, to attempt to negotiate AX.25 v2.2 and its default
* parameters.
*/
if (patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL) < 0) {
if (patty_ax25_sock_send_xid(sock) < 0) {
response.ret = -1;
response.eno = EIO;
response.eno = errno;
goto error_sock_send_sabm;
goto error_sock_send_xid;
}
/*
* At this point, we will wait for a DM, FRMR or XID response, which
* will help us determine what version of AX.25 to apply for this socket,
* or whether the peer is not accepting connections.
*/
return 0;
error_sock_send_sabm:
error_sock_send_xid:
error_network_down:
error_invalid_status:
error_sock_by_fd:
@ -1040,6 +1043,20 @@ static int reply_ua(patty_ax25_if *iface,
return reply_to(iface, frame, &reply);
}
static int handle_frmr(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
patty_ax25_sock *sock;
if ((sock = sock_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src)) == NULL) {
return 0;
}
return patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL);
}
static int handle_sabm(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
@ -1310,30 +1327,87 @@ error_sock_resend:
}
static int handle_xid(patty_ax25_server *server,
patty_ax25_sock *sock,
patty_ax25_if *iface,
patty_ax25_frame *frame,
void *buf,
size_t offset,
size_t len) {
patty_ax25_params params;
patty_ax25_sock *local,
*remote;
if (patty_ax25_frame_decode_xid(&params, buf, offset, len) < 0) {
goto error_io;
}
/*
* Since we've received an XID packet, we can assume that the remote
* station is capable of speaking AX.25 v2.2. Therefore, we should
* upgrade the socket defaults accordingly, and negotiate downwards
* as necessary.
* First, check if this XID packet is for a pending outbound connection.
*/
patty_ax25_sock_upgrade(sock);
if ((remote = sock_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src)) != NULL) {
/*
* Since we've received an XID packet, we can assume that the remote
* station is capable of speaking AX.25 v2.2. Therefore, we should
* upgrade the socket defaults accordingly, and negotiate downwards
* as necessary.
*/
patty_ax25_sock_upgrade(remote);
if (patty_ax25_sock_params_set(sock, &params) < 0) {
goto error_sock_params_set;
if (patty_ax25_sock_params_set(remote, &params) < 0) {
goto error_sock_params_set;
}
/*
* Since this XID frame is for a socket that is awaiting outbound
* connection, we can send an SABM or SABME packet, as necessary.
*/
if (params.hdlc & PATTY_AX25_PARAM_HDLC_MODULO_128) {
remote->mode = PATTY_AX25_SOCK_SABME;
return patty_ax25_sock_send_sabme(remote, PATTY_AX25_FRAME_POLL);
} else {
return patty_ax25_sock_send_sabm(remote, PATTY_AX25_FRAME_POLL);
}
}
return 0;
/*
* Second, check if this XID packet is for a socket pending accept.
*/
if ((local = sock_by_addr(server->socks_pending_accept,
&frame->dest)) != NULL) {
if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) {
goto error_sock_new;
}
remote->status = PATTY_AX25_SOCK_PENDING_ACCEPT;
if (params.hdlc & PATTY_AX25_PARAM_HDLC_MODULO_128) {
remote->mode = PATTY_AX25_SOCK_SABME;
}
patty_ax25_sock_bind_if(remote, iface);
patty_ax25_sock_upgrade(remote);
if (patty_ax25_sock_params_set(remote, &params) < 0) {
goto error_sock_params_set;
}
save_reply_addr(remote, frame);
if (sock_save_by_fd(server->socks_by_fd, remote) < 0) {
goto error_sock_save_by_fd;
}
return patty_ax25_sock_send_xid(remote);
}
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
error_sock_save_by_fd:
error_sock_new:
error_sock_params_set:
error_io:
return -1;
@ -1380,8 +1454,8 @@ static int handle_frame(patty_ax25_server *server,
case PATTY_AX25_FRAME_I: return handle_i(server, iface, sock, &frame);
case PATTY_AX25_FRAME_REJ: return handle_rej(server, sock, &frame);
case PATTY_AX25_FRAME_SREJ: return handle_srej(server, sock, &frame);
case PATTY_AX25_FRAME_XID: return handle_xid(server, sock, buf, offset, len);
case PATTY_AX25_FRAME_FRMR: return 0;
case PATTY_AX25_FRAME_XID: return handle_xid(server, iface, &frame, buf, offset, len);
case PATTY_AX25_FRAME_FRMR: return handle_frmr(server, iface, &frame);
default:
break;