diff --git a/src/server.c b/src/server.c index 8512152..387f878 100644 --- a/src/server.c +++ b/src/server.c @@ -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(¶ms, 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, ¶ms) < 0) { - goto error_sock_params_set; + if (patty_ax25_sock_params_set(remote, ¶ms) < 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, ¶ms) < 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;