Refactor to adhere better to AX.25 v2.2

Changes:

    * Don't use a separate dict for keeping track of sockets pending
      accept and sockets pending connect; rely more on the semantic
      meaning of the enum patty_ax25_sock_status values

    * Ensure DISC frames are acknowledged by UA frames

    * Ensure a receiving system only shuts down a connection after
      receiving a UA frame in response to a sent DISC frame

    * Ensure a sending system only shuts down a connection just prior to
      sending a UA frame in response to a received DISC frame

    * Don't use the P/F flag for the connection management U frames;
      implicitly assume the P/F flag is set to 1, and always send frames
      with a true P/F flag
This commit is contained in:
XANTRONIX Development 2020-07-22 22:02:26 -04:00 committed by XANTRONIX Industrial
parent edfc32ce33
commit 8761a4e3c2
2 changed files with 319 additions and 234 deletions

View file

@ -30,7 +30,8 @@ enum patty_ax25_sock_status {
PATTY_AX25_SOCK_LISTENING,
PATTY_AX25_SOCK_PENDING_ACCEPT,
PATTY_AX25_SOCK_PENDING_CONNECT,
PATTY_AX25_SOCK_ESTABLISHED
PATTY_AX25_SOCK_ESTABLISHED,
PATTY_AX25_SOCK_PROMISC
};
enum patty_ax25_sock_mode {

View file

@ -29,9 +29,9 @@ struct _patty_ax25_server {
patty_ax25_route_table *routes;
patty_dict *socks_by_fd,
*socks_pending_accept,
*socks_pending_connect,
*socks_established;
*socks_by_client,
*socks_local,
*socks_remote;
patty_dict *clients,
*clients_by_sock;
@ -60,16 +60,16 @@ patty_ax25_server *patty_ax25_server_new(const char *path) {
goto error_dict_new_socks_by_fd;
}
if ((server->socks_pending_accept = patty_dict_new()) == NULL) {
goto error_dict_new_socks_pending_accept;
if ((server->socks_by_client = patty_dict_new()) == NULL) {
goto error_dict_new_socks_by_client;
}
if ((server->socks_pending_connect = patty_dict_new()) == NULL) {
goto error_dict_new_socks_pending_connect;
if ((server->socks_local = patty_dict_new()) == NULL) {
goto error_dict_new_socks_local;
}
if ((server->socks_established = patty_dict_new()) == NULL) {
goto error_dict_new_socks_established;
if ((server->socks_remote = patty_dict_new()) == NULL) {
goto error_dict_new_socks_remote;
}
if ((server->clients = patty_dict_new()) == NULL) {
@ -86,15 +86,15 @@ error_dict_new_clients_by_sock:
patty_dict_destroy(server->clients);
error_dict_new_clients:
patty_dict_destroy(server->socks_established);
patty_dict_destroy(server->socks_remote);
error_dict_new_socks_established:
patty_dict_destroy(server->socks_pending_connect);
error_dict_new_socks_remote:
patty_dict_destroy(server->socks_local);
error_dict_new_socks_pending_connect:
patty_dict_destroy(server->socks_pending_accept);
error_dict_new_socks_local:
patty_dict_destroy(server->socks_by_client);
error_dict_new_socks_pending_accept:
error_dict_new_socks_by_client:
patty_dict_destroy(server->socks_by_fd);
error_dict_new_socks_by_fd:
@ -116,12 +116,19 @@ static int destroy_if(patty_ax25_if *iface, void *ctx) {
return 0;
}
static int destroy_socks_by_client_entry(uint32_t key, void *value, void *ctx) {
patty_dict_destroy((patty_dict *)value);
return 0;
}
void patty_ax25_server_destroy(patty_ax25_server *server) {
patty_dict_destroy(server->clients_by_sock);
patty_dict_destroy(server->clients);
patty_dict_destroy(server->socks_established);
patty_dict_destroy(server->socks_pending_connect);
patty_dict_destroy(server->socks_pending_accept);
patty_dict_destroy(server->socks_remote);
patty_dict_destroy(server->socks_local);
patty_dict_each(server->socks_by_client, destroy_socks_by_client_entry, NULL);
patty_dict_destroy(server->socks_by_client);
patty_dict_destroy(server->socks_by_fd);
patty_ax25_server_each_if(server, destroy_if, NULL);
@ -185,9 +192,7 @@ static patty_ax25_sock *sock_by_addrpair(patty_dict *dict,
}
static int sock_save_by_fd(patty_dict *dict, patty_ax25_sock *sock) {
if (patty_dict_set(dict,
(uint32_t)sock->fd,
sock) == NULL) {
if (patty_dict_set(dict, (uint32_t)sock->fd, sock) == NULL) {
goto error_dict_set;
}
@ -229,7 +234,8 @@ error_dict_set:
static inline int client_delete_by_sock(patty_ax25_server *server,
patty_ax25_sock *sock) {
return patty_dict_delete(server->clients_by_sock, (uint32_t)sock->fd);
return patty_dict_delete(server->clients_by_sock,
(uint32_t)sock->fd);
}
static inline uint32_t hash_addr(patty_ax25_addr *addr) {
@ -254,87 +260,132 @@ static inline uint32_t hash_addrpair(patty_ax25_addr *local,
return hash;
}
static int sock_save_by_addr(patty_dict *dict,
patty_ax25_sock *sock,
patty_ax25_addr *addr) {
uint32_t hash = hash_addr(addr);
static int sock_save_local(patty_ax25_server *server,
patty_ax25_sock *sock) {
uint32_t hash = hash_addr(&sock->local);
if (patty_dict_set(dict,
hash,
sock) == NULL) {
goto error_dict_set;
return patty_dict_set(server->socks_local, hash, sock) == NULL? -1: 0;
}
static int sock_save_remote(patty_ax25_server *server,
patty_ax25_sock *sock) {
uint32_t hash = hash_addrpair(&sock->local, &sock->remote);
return patty_dict_set(server->socks_remote, hash, sock) == NULL? -1: 0;
}
static int sock_delete_local(patty_ax25_server *server,
patty_ax25_sock *sock) {
uint32_t hash = hash_addr(&sock->local);
return patty_dict_delete(server->socks_local, hash);
}
static int sock_delete_remote(patty_ax25_server *server,
patty_ax25_sock *sock) {
uint32_t hash = hash_addrpair(&sock->local, &sock->remote);
return patty_dict_delete(server->socks_remote, hash);
}
static int sock_shutdown(patty_ax25_server *server,
patty_ax25_sock *sock) {
fd_clear(server, sock->fd);
return sock->status == PATTY_AX25_SOCK_ESTABLISHED?
patty_ax25_sock_send_disc(sock, PATTY_AX25_FRAME_POLL): 0;
}
static int sock_save(patty_ax25_server *server,
int client,
patty_ax25_sock *sock) {
patty_dict *socks;
switch (sock->status) {
case PATTY_AX25_SOCK_LISTENING:
if (sock_save_local(server, sock) < 0) {
goto error_sock_save_local;
}
break;
case PATTY_AX25_SOCK_PENDING_ACCEPT:
case PATTY_AX25_SOCK_PENDING_CONNECT:
case PATTY_AX25_SOCK_ESTABLISHED:
if (sock_save_remote(server, sock) < 0) {
goto error_sock_save_remote;
}
break;
case PATTY_AX25_SOCK_CLOSED:
case PATTY_AX25_SOCK_PROMISC:
break;
}
return 0;
error_dict_set:
return -1;
}
static int sock_save_by_addrpair(patty_dict *dict,
patty_ax25_sock *sock,
patty_ax25_addr *local,
patty_ax25_addr *remote) {
uint32_t hash = hash_addrpair(local, remote);
if (patty_dict_set(dict,
hash,
sock) == NULL) {
goto error_dict_set;
if (client_save_by_sock(server, client, sock) < 0) {
goto error_client_save_by_sock;
}
return 0;
if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) {
goto error_dict_get_socks_by_client;
}
error_dict_set:
if (sock_save_by_fd(socks, sock) < 0) {
goto error_sock_save_by_fd;
}
return sock_save_by_fd(server->socks_by_fd, sock);
error_sock_save_by_fd:
error_dict_get_socks_by_client:
error_client_save_by_sock:
error_sock_save_remote:
error_sock_save_local:
return -1;
}
static int sock_delete_by_addr(patty_dict *dict,
patty_ax25_addr *addr) {
uint32_t hash = hash_addr(addr);
return patty_dict_delete(dict, hash);
}
static int sock_delete_by_addrpair(patty_dict *dict,
patty_ax25_addr *local,
patty_ax25_addr *remote) {
uint32_t hash = hash_addrpair(local, remote);
return patty_dict_delete(dict, hash);
}
static int sock_close(patty_ax25_server *server,
patty_ax25_sock *sock) {
if (sock->status == PATTY_AX25_SOCK_ESTABLISHED) {
if (patty_ax25_sock_send_disc(sock, PATTY_AX25_FRAME_POLL) < 0) {
goto error_sock_send_disc;
}
int client;
patty_dict *socks;
if (sock_delete_by_addrpair(server->socks_established,
&sock->local,
&sock->remote) < 0) {
goto error_sock_delete_by_addrpair_established;
}
switch (sock->status) {
case PATTY_AX25_SOCK_LISTENING:
if (sock_delete_local(server, sock) < 0) {
goto error_sock_delete_local;
}
break;
case PATTY_AX25_SOCK_PENDING_ACCEPT:
case PATTY_AX25_SOCK_PENDING_CONNECT:
case PATTY_AX25_SOCK_ESTABLISHED:
if (sock_delete_remote(server, sock) < 0) {
goto error_sock_delete_remote;
}
break;
case PATTY_AX25_SOCK_CLOSED:
case PATTY_AX25_SOCK_PROMISC:
break;
}
if (sock->status == PATTY_AX25_SOCK_PENDING_CONNECT) {
if (sock_delete_by_addrpair(server->socks_pending_connect,
&sock->local,
&sock->remote) < 0) {
goto error_sock_delete_by_addrpair_pending_connect;
}
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
}
if (sock->status == PATTY_AX25_SOCK_PENDING_ACCEPT) {
if (sock_delete_by_addr(server->socks_pending_accept,
&sock->local) < 0) {
goto error_sock_delete_by_addr_pending_accept;
}
if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) {
goto error_dict_get_socks_by_client;
}
if (patty_dict_delete(socks, (uint32_t)sock->fd) < 0) {
goto error_dict_delete_by_fd_socks;
}
if (patty_dict_delete(server->socks_by_fd, (uint32_t)sock->fd) < 0) {
goto error_dict_delete_by_fd_socks;
goto error_dict_delete_by_fd_socks_by_fd;
}
(void)client_delete_by_sock(server, sock);
@ -345,11 +396,12 @@ static int sock_close(patty_ax25_server *server,
return 0;
error_dict_delete_by_fd_socks_by_fd:
error_dict_delete_by_fd_socks:
error_sock_delete_by_addr_pending_accept:
error_sock_delete_by_addrpair_pending_connect:
error_sock_delete_by_addrpair_established:
error_sock_send_disc:
error_dict_get_socks_by_client:
error_client_by_sock:
error_sock_delete_remote:
error_sock_delete_local:
return -1;
}
@ -391,16 +443,11 @@ int patty_ax25_server_delete_if(patty_ax25_server *server,
}
if ((fd = patty_kiss_tnc_fd(iface->tnc)) >= 0) {
fd_watch(server, fd);
if (patty_dict_delete(server->socks_by_fd, (uint32_t)fd) < 0) {
goto error_dict_delete;
}
fd_clear(server, fd);
}
return 0;
error_dict_delete:
error_list_splice:
return -1;
}
@ -463,15 +510,8 @@ static int server_socket(patty_ax25_server *server,
goto error_sock_new;
}
if (sock_save_by_fd(server->socks_by_fd, sock) < 0) {
response.ret = -1;
response.eno = errno;
goto error_sock_save_by_fd;
}
if (client_save_by_sock(server, client, sock) < 0) {
goto error_client_save_by_sock;
if (sock_save(server, client, sock) < 0) {
goto error_sock_save;
}
response.ret = sock->fd;
@ -481,8 +521,7 @@ static int server_socket(patty_ax25_server *server,
return write(client, &response, sizeof(response));
error_client_save_by_sock:
error_sock_save_by_fd:
error_sock_save:
patty_ax25_sock_destroy(sock);
error_sock_new:
@ -533,9 +572,7 @@ static int server_setsockopt(patty_ax25_server *server,
patty_ax25_sock_bind_if(sock, iface);
if (sock_save_by_fd(server->socks_established, sock) < 0) {
goto error_sock_save_by_fd;
}
sock->status = PATTY_AX25_SOCK_PROMISC;
fd_watch(server, sock->fd);
@ -558,7 +595,6 @@ error_invalid_type:
error_invalid_opt:
return write(client, &response, sizeof(response));
error_sock_save_by_fd:
error_read:
return -1;
}
@ -632,6 +668,10 @@ static int server_listen(patty_ax25_server *server,
sock->status = PATTY_AX25_SOCK_LISTENING;
if (sock_save_local(server, sock) < 0) {
goto error_sock_save_local;
}
response.ret = 0;
response.eno = 0;
@ -639,6 +679,7 @@ error_invalid_fd:
error_sock_by_fd:
return write(client, &response, sizeof(response));
error_sock_save_local:
error_io:
return -1;
}
@ -661,18 +702,11 @@ static int server_accept(patty_ax25_server *server,
goto error_sock_by_fd;
}
if (sock_save_by_addr(server->socks_pending_accept,
sock,
&sock->local) < 0) {
goto error_save_by_addr;
}
return 0;
error_sock_by_fd:
return write(client, &response, sizeof(response));
error_save_by_addr:
error_io:
return -1;
}
@ -759,11 +793,8 @@ static int server_connect(patty_ax25_server *server,
sock->status = PATTY_AX25_SOCK_PENDING_CONNECT;
if (sock_save_by_addrpair(server->socks_pending_connect,
sock,
&sock->local,
&sock->remote) < 0) {
goto error_sock_save_by_addrpair;
if (sock_save_remote(server, sock) < 0) {
goto error_sock_save_remote;
}
if (client_save_by_sock(server, client, sock) < 0) {
@ -795,7 +826,7 @@ error_sock_by_fd:
return write(client, &response, sizeof(response));
error_client_save_by_sock:
error_sock_save_by_addrpair:
error_sock_save_remote:
error_io:
return -1;
}
@ -806,6 +837,7 @@ static int server_close(patty_ax25_server *server,
patty_ax25_call_close_response response;
patty_ax25_sock *sock;
patty_dict *socks;
if (read(client, &request, sizeof(request)) < 0) {
goto error_io;
@ -818,17 +850,33 @@ static int server_close(patty_ax25_server *server,
goto error_sock_by_fd;
}
if ((socks = patty_dict_get(server->socks_by_client, client)) == NULL) {
response.ret = -1;
response.eno = EBADF;
goto error_dict_get_socks_by_client;
}
if (sock_shutdown(server, sock) < 0) {
response.ret = -1;
response.eno = errno;
goto error_sock_shutdown;
}
if (sock_close(server, sock) < 0) {
response.ret = -1;
response.eno = EBADF;
goto error_sock_delete;
goto error_sock_close;
}
response.ret = 0;
response.eno = 0;
error_sock_delete:
error_sock_close:
error_sock_shutdown:
error_dict_get_socks_by_client:
error_sock_by_fd:
return write(client, &response, sizeof(response));
@ -896,6 +944,7 @@ static int accept_client(patty_ax25_server *server) {
int fd;
struct sockaddr addr;
socklen_t addrlen = sizeof(addr);
patty_dict *socks;
memset(&addr, '\0', addrlen);
@ -907,8 +956,16 @@ static int accept_client(patty_ax25_server *server) {
goto error_accept;
}
if ((socks = patty_dict_new()) == NULL) {
goto error_dict_new;
}
if (patty_dict_set(server->clients, (uint32_t)fd, NULL + fd) == NULL) {
goto error_dict_set;
goto error_dict_set_clients;
}
if (patty_dict_set(server->socks_by_client, (uint32_t)fd, socks) == NULL) {
goto error_dict_set_socks_by_client;
}
fd_watch(server, fd);
@ -916,13 +973,31 @@ static int accept_client(patty_ax25_server *server) {
done:
return 0;
error_dict_set:
error_dict_set_socks_by_client:
error_dict_set_clients:
patty_dict_destroy(socks);
error_dict_new:
close(fd);
error_accept:
return -1;
}
static int client_sock_close(uint32_t key, void *value, void *ctx) {
patty_ax25_server *server = ctx;
patty_ax25_sock *sock = value;
if (sock_shutdown(server, sock) < 0) {
goto error_sock_shutdown;
}
return sock_close(server, sock);
error_sock_shutdown:
return -1;
}
static int handle_client(uint32_t key,
void *value,
void *ctx) {
@ -939,10 +1014,21 @@ static int handle_client(uint32_t key,
if ((readlen = read(client, &call, sizeof(call))) < 0) {
goto error_io;
} else if (readlen == 0) {
patty_dict *socks;
fd_clear(server, client);
if ((socks = patty_dict_get(server->socks_by_client, client)) != NULL) {
(void)patty_dict_each(socks, client_sock_close, server);
(void)patty_dict_destroy(socks);
}
if (patty_dict_delete(server->socks_by_client, key) < 0) {
goto error_dict_delete_socks_by_client;
}
if (patty_dict_delete(server->clients, key) < 0) {
goto error_dict_delete;
goto error_dict_delete_clients;
}
if (close(client) < 0) {
@ -968,7 +1054,8 @@ done:
return 0;
error_not_implemented:
error_dict_delete:
error_dict_delete_socks_by_client:
error_dict_delete_clients:
error_io:
return -1;
}
@ -1000,6 +1087,8 @@ static int reply_to(patty_ax25_if *iface,
patty_ax25_frame *reply) {
ssize_t len;
frame->cr = PATTY_AX25_FRAME_RESPONSE;
if ((len = patty_ax25_frame_encode_reply_to(frame,
reply,
iface->tx_buf,
@ -1036,11 +1125,6 @@ static int reply_ua(patty_ax25_if *iface,
.infolen = 0
};
char callsign[7];
uint8_t ssid;
patty_ax25_ntop(&frame->dest, callsign, &ssid, sizeof(callsign));
return reply_to(iface, frame, &reply);
}
@ -1049,23 +1133,26 @@ static int handle_frmr(patty_ax25_server *server,
patty_ax25_frame *frame) {
patty_ax25_sock *sock;
if ((sock = sock_by_addrpair(server->socks_pending_connect,
if ((sock = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) == NULL) {
return 0;
}
return patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL);
return sock->status == PATTY_AX25_SOCK_PENDING_CONNECT?
patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL): 0;
}
static int handle_sabm(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
int client;
int client,
created = 0;
patty_ax25_sock *local, *remote;
patty_ax25_call_accept_response response;
if ((local = sock_by_addr(server->socks_pending_accept,
if ((local = sock_by_addr(server->socks_local,
&frame->dest)) == NULL) {
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
}
@ -1074,45 +1161,41 @@ static int handle_sabm(patty_ax25_server *server,
goto error_client_by_sock;
}
if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) {
goto error_sock_new;
/*
* Look to see if there is already a remote socket created based on an XID
* packet previously received.
*/
if ((remote = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) == NULL) {
/*
* If there is no existing remote socket, we should create one, and
* associate it with the client.
*/
if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) {
goto error_sock_new;
}
save_reply_addr(remote, frame);
created = 1;
}
remote->status = PATTY_AX25_SOCK_ESTABLISHED;
remote->mode = (frame->type == PATTY_AX25_FRAME_SABM)?
PATTY_AX25_SOCK_SABM: PATTY_AX25_SOCK_SABME;
remote->mode = (frame->type == PATTY_AX25_FRAME_SABME)?
PATTY_AX25_SOCK_SABME: PATTY_AX25_SOCK_SABM;
patty_ax25_sock_bind_if(remote, iface);
save_reply_addr(remote, frame);
if (sock_save_by_fd(server->socks_by_fd, remote) < 0) {
goto error_sock_save_by_fd;
}
if (sock_save_by_addrpair(server->socks_established,
remote,
&remote->local,
&remote->remote) < 0) {
goto error_sock_save_by_addrpair;
}
if (sock_delete_by_addr(server->socks_pending_accept,
&local->local) < 0) {
goto error_sock_delete_by_addr;
}
if (frame->pf) {
if (reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL) < 0) {
goto error_reply_ua;
if (created) {
if (sock_save(server, client, remote) < 0) {
goto error_sock_save;
}
}
fd_watch(server, remote->fd);
memset(&response, '\0', sizeof(response));
response.ret = 0;
response.eno = 0;
memcpy(&response.peer, &frame->src, sizeof(patty_ax25_addr));
memcpy(&response.path, &remote->path, sizeof(response.path));
@ -1120,15 +1203,10 @@ static int handle_sabm(patty_ax25_server *server,
goto error_write;
}
fd_watch(server, remote->fd);
return 0;
return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL);
error_write:
error_reply_ua:
error_sock_delete_by_addr:
error_sock_save_by_addrpair:
error_sock_save_by_fd:
error_sock_save:
patty_ax25_sock_destroy(remote);
error_sock_new:
@ -1143,34 +1221,34 @@ static int handle_ua(patty_ax25_server *server,
patty_ax25_sock *sock;
patty_ax25_call_connect_response response;
if ((sock = sock_by_addrpair(server->socks_pending_connect,
if ((sock = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) == NULL) {
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
}
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
switch (sock->status) {
case PATTY_AX25_SOCK_PENDING_CONNECT:
break;
case PATTY_AX25_SOCK_ESTABLISHED:
return sock_close(server, sock);
default:
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
}
sock->status = PATTY_AX25_SOCK_ESTABLISHED;
if (sock->mode == PATTY_AX25_SOCK_DM) {
sock->mode = PATTY_AX25_SOCK_SABM;
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
}
if (sock_save_by_addrpair(server->socks_established,
sock,
&sock->local,
&sock->remote) < 0) {
goto error_save_by_addrpair;
if (sock_save(server, client, sock) < 0) {
goto error_sock_save;
}
if (sock_delete_by_addrpair(server->socks_pending_connect,
&sock->local,
&sock->remote) < 0) {
goto error_delete_by_addrpair;
}
fd_watch(server, sock->fd);
response.ret = 0;
response.eno = 0;
@ -1179,15 +1257,12 @@ static int handle_ua(patty_ax25_server *server,
goto error_write;
}
fd_watch(server, sock->fd);
return 0;
error_write:
error_sock_save:
patty_ax25_sock_destroy(sock);
error_delete_by_addrpair:
error_save_by_addrpair:
error_client_by_sock:
return -1;
}
@ -1199,26 +1274,18 @@ static int handle_dm(patty_ax25_server *server,
patty_ax25_sock *sock;
patty_ax25_call_connect_response response;
if ((sock = sock_by_addrpair(server->socks_established,
&frame->dest,
&frame->src)) != NULL) {
return sock_close(server, sock);
}
if ((sock = sock_by_addrpair(server->socks_pending_connect,
if ((sock = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) == NULL) {
return 0;
}
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
if (sock->status != PATTY_AX25_SOCK_PENDING_CONNECT) {
return 0;
}
if (sock_delete_by_addrpair(server->socks_pending_connect,
&frame->dest,
&frame->src) < 0) {
goto error_delete_by_addrpair;
if ((client = client_by_sock(server, sock)) < 0) {
goto error_client_by_sock;
}
response.ret = -1;
@ -1233,7 +1300,6 @@ static int handle_dm(patty_ax25_server *server,
return 0;
error_write:
error_delete_by_addrpair:
error_client_by_sock:
return -1;
}
@ -1269,25 +1335,19 @@ static int handle_disc(patty_ax25_server *server,
patty_ax25_frame *frame) {
patty_ax25_sock *sock;
if ((sock = sock_by_addrpair(server->socks_established,
if ((sock = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) == NULL) {
goto done;
return 0;
}
if (sock_close(server, sock) < 0) {
goto error_sock_delete;
if (sock->status != PATTY_AX25_SOCK_ESTABLISHED) {
return frame->pf? reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL): 0;
}
done:
if (frame->pf) {
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
}
(void)sock_close(server, sock);
return 0;
error_sock_delete:
return -1;
return reply_ua(iface, frame, PATTY_AX25_FRAME_FINAL);
}
static int handle_rej(patty_ax25_server *server,
@ -1339,18 +1399,25 @@ static int handle_xid(patty_ax25_server *server,
}
/*
* First, check if this XID packet is for a pending outbound connection.
* First, check if this XID packet is a response to an XID used to initiate
* an outbound connection.
*/
if ((remote = sock_by_addrpair(server->socks_pending_connect,
if ((remote = sock_by_addrpair(server->socks_remote,
&frame->dest,
&frame->src)) != NULL) {
if (remote->status != PATTY_AX25_SOCK_PENDING_CONNECT) {
goto reply_dm;
}
/*
* 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_upgrade(remote) < 0) {
goto error_sock_upgrade;
}
if (patty_ax25_sock_params_set(remote, &params) < 0) {
goto error_sock_params_set;
@ -1365,15 +1432,27 @@ static int handle_xid(patty_ax25_server *server,
return patty_ax25_sock_send_sabme(remote, PATTY_AX25_FRAME_POLL);
} else {
remote->mode = PATTY_AX25_SOCK_SABM;
return patty_ax25_sock_send_sabm(remote, PATTY_AX25_FRAME_POLL);
}
}
/*
* Second, check if this XID packet is for a socket pending accept.
* Second, check if this XID packet is for a listening socket.
*/
if ((local = sock_by_addr(server->socks_pending_accept,
if ((local = sock_by_addr(server->socks_local,
&frame->dest)) != NULL) {
int client;
if (local->status != PATTY_AX25_SOCK_LISTENING) {
goto reply_dm;
}
if ((client = client_by_sock(server, local)) < 0) {
goto error_client_by_sock;
}
if ((remote = patty_ax25_sock_new(local->proto, local->type)) == NULL) {
goto error_sock_new;
}
@ -1394,18 +1473,21 @@ static int handle_xid(patty_ax25_server *server,
save_reply_addr(remote, frame);
if (sock_save_by_fd(server->socks_by_fd, remote) < 0) {
goto error_sock_save_by_fd;
if (sock_save(server, client, remote) < 0) {
goto error_sock_save;
}
return patty_ax25_sock_send_xid(remote, PATTY_AX25_FRAME_RESPONSE);
}
reply_dm:
return reply_dm(iface, frame, PATTY_AX25_FRAME_FINAL);
error_sock_save_by_fd:
error_sock_save:
error_sock_new:
error_client_by_sock:
error_sock_params_set:
error_sock_upgrade:
error_io:
return -1;
}
@ -1428,7 +1510,7 @@ static int handle_frame(patty_ax25_server *server,
offset += decoded;
}
if ((sock = sock_by_addrpair(server->socks_established,
if ((sock = sock_by_addrpair(server->socks_remote,
&frame.dest,
&frame.src)) != NULL) {
if (sock->mode == PATTY_AX25_SOCK_SABME) {
@ -1469,17 +1551,19 @@ error_io:
static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) {
int fd = patty_kiss_tnc_fd(iface->tnc);
void *buf;
ssize_t readlen;
if (!FD_ISSET(fd, &server->fds_r)) {
goto done;
}
do {
void *buf;
ssize_t readlen;
if ((readlen = patty_ax25_if_recv(iface, &buf)) < 0) {
goto error_io;
} else if (readlen == 0) {
close(fd);
fd_clear(server, fd);
goto done;
@ -1530,14 +1614,14 @@ static int handle_sock(uint32_t key,
if ((len = read(sock->fd, sock->rx_buf, sock->n_maxlen_rx)) < 0) {
if (errno == EIO) {
(void)sock_close(server, sock);
(void)sock_shutdown(server, sock);
goto done;
}
goto error_io;
} else if (len == 0) {
sock_close(server, sock);
(void)sock_shutdown(server, sock);
goto done;
}
@ -1555,7 +1639,7 @@ error_io:
}
static int handle_socks(patty_ax25_server *server) {
return patty_dict_each(server->socks_established, handle_sock, server);
return patty_dict_each(server->socks_by_fd, handle_sock, server);
}
int patty_ax25_server_run(patty_ax25_server *server) {