2020-06-30 23:20:12 -04:00
|
|
|
#define _GNU_SOURCE
|
2020-06-25 20:37:12 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2020-06-26 22:44:19 -04:00
|
|
|
#include <unistd.h>
|
2020-06-30 23:20:12 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
2020-06-25 20:37:12 -04:00
|
|
|
|
|
|
|
#include <patty/ax25.h>
|
|
|
|
|
2020-08-17 18:53:55 -04:00
|
|
|
struct slot {
|
|
|
|
size_t len;
|
|
|
|
int ack;
|
|
|
|
};
|
|
|
|
|
2020-06-30 23:20:12 -04:00
|
|
|
static int bind_pty(patty_ax25_sock *sock) {
|
2020-07-26 18:42:49 -04:00
|
|
|
char *pty;
|
2020-06-30 23:20:12 -04:00
|
|
|
|
2020-09-02 21:29:57 -04:00
|
|
|
if ((sock->fd = posix_openpt(O_RDWR | O_NOCTTY)) < 0) {
|
2020-06-30 23:20:12 -04:00
|
|
|
goto error_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grantpt(sock->fd) < 0) {
|
|
|
|
goto error_grantpt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlockpt(sock->fd) < 0) {
|
|
|
|
goto error_unlockpt;
|
|
|
|
}
|
|
|
|
|
2020-07-26 18:42:49 -04:00
|
|
|
if ((pty = ptsname(sock->fd)) == NULL) {
|
|
|
|
goto error_ptsname;
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
2020-08-07 17:59:16 -04:00
|
|
|
(void)strncpy(sock->pty, pty, sizeof(sock->pty)-1);
|
2020-07-26 18:42:49 -04:00
|
|
|
|
2020-06-30 23:20:12 -04:00
|
|
|
return 0;
|
|
|
|
|
2020-07-26 18:42:49 -04:00
|
|
|
error_ptsname:
|
2020-06-30 23:20:12 -04:00
|
|
|
error_unlockpt:
|
|
|
|
error_grantpt:
|
|
|
|
close(sock->fd);
|
|
|
|
|
|
|
|
error_open:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-26 01:55:21 -04:00
|
|
|
static inline size_t tx_bufsz(patty_ax25_sock *sock) {
|
2020-07-21 01:38:23 -04:00
|
|
|
return PATTY_AX25_FRAME_OVERHEAD + sock->n_maxlen_tx;
|
|
|
|
}
|
|
|
|
|
2020-08-23 21:01:07 -05:00
|
|
|
static inline size_t io_bufsz(patty_ax25_sock *sock) {
|
|
|
|
return PATTY_AX25_FRAME_OVERHEAD + sock->n_maxlen_tx;
|
2020-07-26 01:55:21 -04:00
|
|
|
}
|
|
|
|
|
2020-08-20 22:50:10 -05:00
|
|
|
static inline size_t tx_slots(patty_ax25_sock *sock) {
|
|
|
|
return sock->mode == PATTY_AX25_SOCK_SABME? 128: 8;
|
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
static inline size_t tx_slot_size(patty_ax25_sock *sock) {
|
2020-08-21 00:41:51 -05:00
|
|
|
return sizeof(struct slot) + sock->n_maxlen_tx;
|
2020-07-17 00:22:46 -04:00
|
|
|
}
|
|
|
|
|
2020-07-17 19:37:18 -04:00
|
|
|
static inline size_t tx_slots_size(patty_ax25_sock *sock) {
|
2020-08-20 22:50:10 -05:00
|
|
|
return tx_slots(sock) * tx_slot_size(sock);
|
2020-07-17 00:22:46 -04:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:53:55 -04:00
|
|
|
static inline int tx_seq(patty_ax25_sock *sock, int seq) {
|
2020-08-20 22:50:10 -05:00
|
|
|
return seq % tx_slots(sock);
|
2020-07-21 01:38:23 -04:00
|
|
|
}
|
|
|
|
|
2020-08-17 18:53:55 -04:00
|
|
|
static inline struct slot *tx_slot(patty_ax25_sock *sock, int seq) {
|
2020-08-19 22:32:05 -04:00
|
|
|
int i = tx_seq(sock, seq);
|
2020-08-03 15:09:32 -04:00
|
|
|
|
2020-08-17 18:53:55 -04:00
|
|
|
return (struct slot *)
|
|
|
|
((uint8_t *)sock->tx_slots + (i * tx_slot_size(sock)));
|
2020-08-03 15:09:32 -04:00
|
|
|
}
|
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
static inline void tx_slot_save(patty_ax25_sock *sock, void *buf, size_t len) {
|
|
|
|
struct slot *slot = tx_slot(sock, sock->vs);
|
|
|
|
|
|
|
|
slot->len = len;
|
|
|
|
slot->ack = 0;
|
|
|
|
|
|
|
|
memcpy(slot + 1, buf, len);
|
2020-08-03 15:09:32 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
static int init_bufs(patty_ax25_sock *sock) {
|
2020-08-23 22:36:59 -05:00
|
|
|
size_t slots = tx_slots(sock),
|
|
|
|
i;
|
2020-08-03 15:09:32 -04:00
|
|
|
|
2020-07-26 01:55:21 -04:00
|
|
|
if ((sock->tx_buf = realloc(sock->tx_buf, tx_bufsz(sock))) == NULL) {
|
2020-07-22 19:45:20 -04:00
|
|
|
goto error_realloc_tx_buf;
|
|
|
|
}
|
|
|
|
|
2020-08-23 21:01:07 -05:00
|
|
|
if ((sock->io_buf = realloc(sock->io_buf, io_bufsz(sock))) == NULL) {
|
|
|
|
goto error_realloc_io_buf;
|
2020-07-21 01:38:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((sock->tx_slots = realloc(sock->tx_slots, tx_slots_size(sock))) == NULL) {
|
|
|
|
goto error_realloc_tx_slots;
|
|
|
|
}
|
|
|
|
|
2020-08-19 22:32:05 -04:00
|
|
|
for (i=0; i<slots; i++) {
|
2020-08-17 18:53:55 -04:00
|
|
|
struct slot *slot = tx_slot(sock, i);
|
|
|
|
|
|
|
|
slot->len = 0;
|
2020-08-20 18:54:03 -05:00
|
|
|
slot->ack = 0;
|
2020-08-03 15:09:32 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_realloc_tx_slots:
|
2020-08-23 21:01:07 -05:00
|
|
|
free(sock->io_buf);
|
|
|
|
sock->io_buf = NULL;
|
2020-07-21 01:38:23 -04:00
|
|
|
|
2020-08-23 21:01:07 -05:00
|
|
|
error_realloc_io_buf:
|
2020-07-22 19:45:20 -04:00
|
|
|
free(sock->tx_buf);
|
|
|
|
sock->tx_buf = NULL;
|
2020-07-21 01:38:23 -04:00
|
|
|
|
2020-07-22 19:45:20 -04:00
|
|
|
error_realloc_tx_buf:
|
2020-07-21 01:38:23 -04:00
|
|
|
return -1;
|
2020-07-17 00:22:46 -04:00
|
|
|
}
|
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
static patty_ax25_sock *init_dgram(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_proto proto) {
|
|
|
|
sock->proto = proto;
|
|
|
|
sock->type = PATTY_AX25_SOCK_DGRAM;
|
2020-08-05 02:05:15 -04:00
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
static patty_ax25_sock *init_raw(patty_ax25_sock *sock) {
|
2020-08-25 00:14:52 -05:00
|
|
|
if ((sock->raw = patty_kiss_tnc_new_fd(sock->fd, NULL)) == NULL) {
|
2020-08-05 02:05:15 -04:00
|
|
|
goto error_kiss_tnc_new_fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->proto = PATTY_AX25_PROTO_NONE;
|
|
|
|
sock->type = PATTY_AX25_SOCK_RAW;
|
2020-08-07 18:17:36 -04:00
|
|
|
sock->state = PATTY_AX25_SOCK_ESTABLISHED;
|
2020-08-05 02:05:15 -04:00
|
|
|
|
|
|
|
return sock;
|
|
|
|
|
|
|
|
error_kiss_tnc_new_fd:
|
|
|
|
(void)close(sock->fd);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-03 15:21:32 -04:00
|
|
|
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_proto proto,
|
|
|
|
enum patty_ax25_sock_type type) {
|
2020-06-25 20:37:12 -04:00
|
|
|
patty_ax25_sock *sock;
|
|
|
|
|
|
|
|
if ((sock = malloc(sizeof(*sock))) == NULL) {
|
|
|
|
goto error_malloc_sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(sock, '\0', sizeof(*sock));
|
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
if (bind_pty(sock) < 0) {
|
|
|
|
goto error_bind_pty;
|
2020-08-05 02:05:15 -04:00
|
|
|
}
|
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
switch (type) {
|
|
|
|
case PATTY_AX25_SOCK_DGRAM:
|
|
|
|
return init_dgram(sock, proto);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_RAW:
|
|
|
|
return init_raw(sock);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_STREAM:
|
|
|
|
patty_ax25_sock_init(sock);
|
|
|
|
}
|
2020-07-18 15:07:28 -04:00
|
|
|
|
2020-07-19 01:38:36 -04:00
|
|
|
sock->proto = proto;
|
|
|
|
sock->type = type;
|
|
|
|
sock->version = PATTY_AX25_2_0;
|
2020-07-24 19:33:20 -04:00
|
|
|
sock->flags_classes = PATTY_AX25_SOCK_DEFAULT_CLASSES;
|
2020-07-19 01:38:36 -04:00
|
|
|
sock->flags_hdlc = PATTY_AX25_SOCK_DEFAULT_HDLC;
|
2020-07-17 19:37:18 -04:00
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if (init_bufs(sock) < 0) {
|
|
|
|
goto error_init_bufs;
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
return sock;
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
error_init_bufs:
|
|
|
|
if (sock->tx_slots) free(sock->tx_slots);
|
2020-08-23 21:01:07 -05:00
|
|
|
if (sock->io_buf) free(sock->io_buf);
|
2020-07-22 19:45:20 -04:00
|
|
|
if (sock->tx_buf) free(sock->tx_buf);
|
2020-07-15 23:13:41 -04:00
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
error_bind_pty:
|
2020-06-30 23:20:12 -04:00
|
|
|
free(sock);
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
error_malloc_sock:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void patty_ax25_sock_destroy(patty_ax25_sock *sock) {
|
2020-08-11 02:01:31 -04:00
|
|
|
if (sock->type == PATTY_AX25_SOCK_RAW) {
|
|
|
|
if (sock->state == PATTY_AX25_SOCK_PROMISC) {
|
2020-07-07 17:48:18 -04:00
|
|
|
(void)patty_ax25_if_promisc_delete(sock->iface, sock->fd);
|
|
|
|
}
|
|
|
|
|
2020-08-11 02:01:31 -04:00
|
|
|
patty_kiss_tnc_destroy(sock->raw);
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
2020-08-11 02:01:31 -04:00
|
|
|
if (sock->fd > 0) {
|
|
|
|
(void)close(sock->fd);
|
2020-08-05 02:05:15 -04:00
|
|
|
}
|
|
|
|
|
2020-08-14 22:24:17 -04:00
|
|
|
if (sock->assembler) {
|
|
|
|
free(sock->assembler);
|
|
|
|
}
|
|
|
|
|
2020-08-14 17:38:16 -04:00
|
|
|
if (sock->tx_slots) {
|
|
|
|
free(sock->tx_slots);
|
|
|
|
}
|
|
|
|
|
2020-08-23 21:01:07 -05:00
|
|
|
if (sock->io_buf) {
|
|
|
|
free(sock->io_buf);
|
2020-08-14 17:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->tx_buf) {
|
|
|
|
free(sock->tx_buf);
|
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
free(sock);
|
|
|
|
}
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
void patty_ax25_sock_init(patty_ax25_sock *sock) {
|
2020-08-07 17:58:13 -04:00
|
|
|
sock->state = PATTY_AX25_SOCK_CLOSED;
|
2020-08-03 02:54:49 -04:00
|
|
|
sock->mode = PATTY_AX25_SOCK_DM;
|
2020-08-05 21:51:51 -04:00
|
|
|
sock->flow = PATTY_AX25_SOCK_WAIT;
|
2020-08-03 02:54:49 -04:00
|
|
|
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;
|
2020-08-19 22:09:56 -04:00
|
|
|
sock->rx_pending = 0;
|
2020-08-19 22:06:39 -04:00
|
|
|
|
|
|
|
patty_timer_init(&sock->timer_t1, sock->n_ack);
|
|
|
|
patty_timer_init(&sock->timer_t2, PATTY_AX25_SOCK_DEFAULT_DELAY);
|
|
|
|
patty_timer_init(&sock->timer_t3, PATTY_AX25_SOCK_DEFAULT_KEEPALIVE);
|
2020-08-03 02:54:49 -04:00
|
|
|
}
|
|
|
|
|
2020-07-26 02:37:17 -04:00
|
|
|
/*
|
2020-08-05 21:51:51 -04:00
|
|
|
* AX.25 v2.2, Section 6.5 "Resetting Procedure"
|
2020-07-26 02:37:17 -04:00
|
|
|
*/
|
2020-08-03 02:54:49 -04:00
|
|
|
void patty_ax25_sock_reset(patty_ax25_sock *sock) {
|
2020-08-20 22:50:50 -05:00
|
|
|
int i,
|
|
|
|
slots = tx_slots(sock);
|
|
|
|
|
2020-08-19 22:09:56 -04:00
|
|
|
sock->flow = PATTY_AX25_SOCK_READY;
|
|
|
|
sock->vs = 0;
|
|
|
|
sock->vr = 0;
|
|
|
|
sock->va = 0;
|
|
|
|
sock->retries = sock->n_retry;
|
|
|
|
sock->rx_pending = 0;
|
2020-07-27 00:43:48 -04:00
|
|
|
|
2020-08-20 22:50:50 -05:00
|
|
|
for (i=0; i<slots; i++) {
|
|
|
|
struct slot *slot = tx_slot(sock, i);
|
|
|
|
|
|
|
|
slot->len = 0;
|
|
|
|
slot->ack = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
patty_timer_start(&sock->timer_t1);
|
2020-08-01 16:37:39 -04:00
|
|
|
patty_timer_clear(&sock->timer_t2);
|
|
|
|
patty_timer_clear(&sock->timer_t3);
|
2020-07-26 02:37:17 -04:00
|
|
|
}
|
|
|
|
|
2020-08-05 22:38:49 -04:00
|
|
|
void patty_ax25_sock_mtu_set(patty_ax25_sock *sock, size_t mtu) {
|
|
|
|
sock->n_maxlen_tx = mtu;
|
|
|
|
}
|
|
|
|
|
2020-08-05 22:53:26 -04:00
|
|
|
void patty_ax25_sock_ack_set(patty_ax25_sock *sock, time_t ack) {
|
|
|
|
sock->n_ack = (time_t)ack;
|
|
|
|
}
|
|
|
|
|
2020-08-05 22:38:49 -04:00
|
|
|
void patty_ax25_sock_window_set(patty_ax25_sock *sock, size_t window) {
|
|
|
|
sock->n_window_tx = window;
|
|
|
|
}
|
|
|
|
|
2020-08-06 00:34:13 -04:00
|
|
|
void patty_ax25_sock_retry_set(patty_ax25_sock *sock, size_t retry) {
|
|
|
|
sock->n_retry = retry;
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
void patty_ax25_sock_params_upgrade(patty_ax25_sock *sock) {
|
|
|
|
if (sock->version >= PATTY_AX25_2_2) {
|
|
|
|
return;
|
2020-07-26 00:55:47 -04:00
|
|
|
}
|
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
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;
|
|
|
|
}
|
2020-07-22 19:45:20 -04:00
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
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;
|
2020-07-22 19:45:20 -04:00
|
|
|
}
|
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
int patty_ax25_sock_params_negotiate(patty_ax25_sock *sock,
|
|
|
|
patty_ax25_params *params) {
|
2020-07-19 01:44:16 -04:00
|
|
|
if (params->flags & PATTY_AX25_PARAM_CLASSES) {
|
|
|
|
if (!(params->classes & PATTY_AX25_PARAM_CLASSES_ABM)) {
|
2020-07-24 21:04:14 -04:00
|
|
|
goto error_notsup;
|
2020-07-19 01:44:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->classes & PATTY_AX25_PARAM_CLASSES_HALF_DUPLEX)) {
|
2020-07-24 21:04:14 -04:00
|
|
|
goto error_notsup;
|
2020-07-19 01:44:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (params->classes & PATTY_AX25_PARAM_CLASSES_FULL_DUPLEX) {
|
2020-07-24 21:04:14 -04:00
|
|
|
goto error_notsup;
|
2020-07-19 01:44:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params->flags & PATTY_AX25_PARAM_HDLC) {
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_REJ)) {
|
|
|
|
sock->flags_hdlc &= ~PATTY_AX25_PARAM_HDLC_REJ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_SREJ)) {
|
|
|
|
sock->flags_hdlc &= ~PATTY_AX25_PARAM_HDLC_SREJ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_XADDR)) {
|
|
|
|
goto error_invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_MODULO_8)) {
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_MODULO_128)) {
|
|
|
|
goto error_invalid;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_MODULO_128)) {
|
|
|
|
goto error_invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
params->hdlc &= ~PATTY_AX25_PARAM_HDLC_MODULO_8;
|
|
|
|
params->hdlc |= PATTY_AX25_PARAM_HDLC_MODULO_128;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_TEST)) {
|
|
|
|
params->hdlc &= ~PATTY_AX25_PARAM_HDLC_TEST;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(params->hdlc & PATTY_AX25_PARAM_HDLC_SYNC_TX)) {
|
|
|
|
goto error_invalid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params->flags & PATTY_AX25_PARAM_INFO_RX) {
|
2020-08-03 02:54:49 -04:00
|
|
|
if (sock->n_maxlen_tx > params->info_rx >> 3) {
|
2020-08-02 19:14:57 -04:00
|
|
|
sock->n_maxlen_tx = params->info_rx >> 3;
|
2020-07-19 01:44:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params->flags & PATTY_AX25_PARAM_WINDOW_RX) {
|
|
|
|
if (sock->n_window_tx > params->window_rx) {
|
|
|
|
sock->n_window_tx = params->window_rx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params->flags & PATTY_AX25_PARAM_ACK) {
|
|
|
|
if (sock->n_ack < params->ack) {
|
|
|
|
sock->n_ack = params->ack;
|
2020-08-19 22:06:39 -04:00
|
|
|
|
|
|
|
patty_timer_init(&sock->timer_t1, params->ack);
|
2020-07-19 01:44:16 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params->flags & PATTY_AX25_PARAM_RETRY) {
|
|
|
|
if (sock->n_retry < params->retry) {
|
|
|
|
sock->n_retry = params->retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
return 0;
|
2020-07-19 01:44:16 -04:00
|
|
|
|
2020-07-24 21:04:14 -04:00
|
|
|
error_notsup:
|
|
|
|
errno = ENOTSUP;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
2020-07-19 01:44:16 -04:00
|
|
|
error_invalid:
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-08-03 02:54:49 -04:00
|
|
|
int patty_ax25_sock_realloc_bufs(patty_ax25_sock *sock) {
|
|
|
|
return init_bufs(sock);
|
|
|
|
}
|
|
|
|
|
2020-07-02 16:06:51 -04:00
|
|
|
char *patty_ax25_sock_pty(patty_ax25_sock *sock) {
|
2020-07-26 18:42:49 -04:00
|
|
|
return sock->pty;
|
2020-07-02 16:06:51 -04:00
|
|
|
}
|
|
|
|
|
2020-07-07 17:48:18 -04:00
|
|
|
int patty_ax25_sock_bind_if(patty_ax25_sock *sock,
|
|
|
|
patty_ax25_if *iface) {
|
2020-07-02 16:06:51 -04:00
|
|
|
sock->iface = iface;
|
2020-08-05 02:05:15 -04:00
|
|
|
sock->flags_classes |= iface->flags_classes;
|
2020-07-07 17:48:18 -04:00
|
|
|
|
2020-08-07 17:58:13 -04:00
|
|
|
if (sock->state == PATTY_AX25_SOCK_PROMISC) {
|
2020-07-07 17:48:18 -04:00
|
|
|
if (patty_ax25_if_promisc_add(iface, sock->fd) < 0) {
|
|
|
|
goto error_if_promisc_add;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_if_promisc_add:
|
|
|
|
return -1;
|
2020-07-02 16:06:51 -04:00
|
|
|
}
|
|
|
|
|
2020-08-03 18:47:48 -04:00
|
|
|
void patty_ax25_sock_vs_incr(patty_ax25_sock *sock) {
|
2020-07-18 19:53:32 -04:00
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABM) {
|
2020-08-03 18:47:48 -04:00
|
|
|
sock->vs = (sock->vs + 1) & 0x07;
|
2020-07-08 16:25:10 -04:00
|
|
|
} else {
|
2020-08-03 18:47:48 -04:00
|
|
|
sock->vs = (sock->vs + 1) & 0x7f;
|
2020-07-08 16:25:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-03 18:47:48 -04:00
|
|
|
void patty_ax25_sock_vr_incr(patty_ax25_sock *sock) {
|
2020-07-18 19:53:32 -04:00
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABM) {
|
2020-08-03 18:47:48 -04:00
|
|
|
sock->vr = (sock->vr + 1) & 0x07;
|
2020-07-08 16:25:10 -04:00
|
|
|
} else {
|
2020-08-03 18:47:48 -04:00
|
|
|
sock->vr = (sock->vr + 1) & 0x7f;
|
2020-07-08 16:25:10 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-14 22:24:17 -04:00
|
|
|
int patty_ax25_sock_assembler_init(patty_ax25_sock *sock, size_t total) {
|
|
|
|
if (total < 2) {
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->assembler == NULL || sock->assembler->total < total) {
|
|
|
|
size_t size = sizeof(patty_ax25_sock_assembler)
|
|
|
|
+ total * sock->n_maxlen_rx;
|
|
|
|
|
|
|
|
if ((sock->assembler = malloc(size)) == NULL) {
|
|
|
|
goto error_malloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->assembler->total = total;
|
|
|
|
sock->assembler->remaining = total;
|
|
|
|
sock->assembler->offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_malloc:
|
|
|
|
error_invalid:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_ax25_sock_assembler_ready(patty_ax25_sock *sock, size_t remaining) {
|
|
|
|
if (sock->assembler == NULL || sock->assembler->total == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return remaining + 1 == sock->assembler->remaining? 1: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void patty_ax25_sock_assembler_stop(patty_ax25_sock *sock) {
|
|
|
|
if (sock->assembler == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->assembler->remaining = 0;
|
|
|
|
sock->assembler->total = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_assembler_save(patty_ax25_sock *sock,
|
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
|
|
|
uint8_t *dest = (uint8_t *)(sock->assembler + 1);
|
|
|
|
|
|
|
|
if (len > sock->n_maxlen_rx - 1) {
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
|
|
|
goto error_overflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->assembler->remaining == 0) {
|
|
|
|
errno = EIO;
|
|
|
|
|
|
|
|
goto error_underflow;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(dest + sock->assembler->offset, buf, len);
|
|
|
|
|
|
|
|
sock->assembler->offset += len;
|
|
|
|
sock->assembler->remaining--;
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
error_underflow:
|
|
|
|
error_overflow:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *patty_ax25_sock_assembler_read(patty_ax25_sock *sock,
|
|
|
|
uint8_t *proto,
|
|
|
|
size_t *len) {
|
|
|
|
uint8_t *buf = (uint8_t *)(sock->assembler + 1);
|
|
|
|
|
|
|
|
if (sock->assembler == NULL) {
|
|
|
|
if (proto) *proto = 0;
|
|
|
|
if (len) *len = 0;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proto) *proto = buf[0];
|
|
|
|
if (len) *len = sock->assembler->offset - 1;
|
|
|
|
|
|
|
|
return buf + 1;
|
|
|
|
}
|
|
|
|
|
2020-08-23 00:26:17 -05:00
|
|
|
int patty_ax25_sock_flow_left(patty_ax25_sock *sock) {
|
2020-08-19 22:32:05 -04:00
|
|
|
/*
|
|
|
|
* 6.4.1 Sending I Frames
|
|
|
|
*
|
|
|
|
* The TNC does not transmit any more I frames if its send state variable
|
|
|
|
* V(S) equals the last received N(R) from the other side of the link plus
|
|
|
|
* k. If the TNC sent more I frames, the flow control window would be
|
|
|
|
* exceeded and errors could result.
|
|
|
|
*/
|
2020-08-23 00:37:13 -05:00
|
|
|
if (sock->n_window_tx == 1) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return sock->vs - tx_seq(sock, sock->va + sock->n_window_tx);
|
2020-08-16 18:15:11 -05:00
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
static inline int toobig(patty_ax25_sock *sock,
|
|
|
|
size_t infolen) {
|
|
|
|
return infolen > PATTY_AX25_FRAME_OVERHEAD + sock->n_maxlen_tx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t encode_address(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
void *dest,
|
|
|
|
size_t len) {
|
2020-07-15 23:13:41 -04:00
|
|
|
uint8_t *buf = (uint8_t *)dest;
|
2020-06-28 18:11:49 -04:00
|
|
|
size_t offset = 0;
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
uint8_t flags_remote = 0x00,
|
|
|
|
flags_local = 0x00;
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
unsigned int i;
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if ((2 + sock->hops) * sizeof(patty_ax25_addr) > len) {
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
switch (cr) {
|
|
|
|
case PATTY_AX25_FRAME_COMMAND: flags_remote = 0x80; break;
|
|
|
|
case PATTY_AX25_FRAME_RESPONSE: flags_local = 0x80; break;
|
|
|
|
case PATTY_AX25_FRAME_OLD: break;
|
|
|
|
}
|
2020-06-28 22:54:46 -04:00
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
offset += patty_ax25_addr_copy(buf + offset, &sock->remote, flags_remote);
|
|
|
|
offset += patty_ax25_addr_copy(buf + offset, &sock->local, flags_local);
|
2020-06-28 22:54:46 -04:00
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
for (i=0; i<sock->hops; i++) {
|
|
|
|
offset += patty_ax25_addr_copy(buf + offset, &sock->repeaters[i], 0);
|
2020-06-26 22:44:19 -04:00
|
|
|
}
|
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
((uint8_t *)buf)[offset-1] |= 1;
|
2020-06-26 23:03:00 -04:00
|
|
|
|
2020-06-26 22:44:19 -04:00
|
|
|
return offset;
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
error_toobig:
|
|
|
|
return -1;
|
2020-06-28 18:11:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
|
2020-08-05 21:47:08 -04:00
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
|
|
|
if (sock->type != PATTY_AX25_SOCK_RAW) {
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->iface == NULL) {
|
|
|
|
errno = ENETDOWN;
|
|
|
|
|
|
|
|
goto error_noif;
|
|
|
|
}
|
|
|
|
|
|
|
|
return patty_ax25_if_send(sock->iface, buf, len);
|
|
|
|
|
|
|
|
error_noif:
|
|
|
|
error_invalid_type:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_recv(patty_ax25_sock *sock,
|
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
|
|
|
int port;
|
|
|
|
|
|
|
|
if (sock->type != PATTY_AX25_SOCK_RAW) {
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return patty_kiss_tnc_recv(sock->raw, buf, len, &port);
|
|
|
|
|
|
|
|
error_invalid_type:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_recv_pending(patty_ax25_sock *sock) {
|
|
|
|
if (sock->type != PATTY_AX25_SOCK_RAW) {
|
|
|
|
errno = EINVAL;
|
|
|
|
|
|
|
|
goto error_invalid_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
return patty_kiss_tnc_pending(sock->raw);
|
|
|
|
|
|
|
|
error_invalid_type:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-08-22 22:51:53 -05:00
|
|
|
static inline uint16_t control_i(patty_ax25_sock *sock, int ns) {
|
2020-08-23 00:26:17 -05:00
|
|
|
int flag = patty_ax25_sock_flow_left(sock) == 1? 1: 0;
|
2020-08-22 22:51:53 -05:00
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
switch (sock->mode) {
|
|
|
|
case PATTY_AX25_SOCK_SABM:
|
|
|
|
return ((sock->vr & 0x07) << 5)
|
|
|
|
| (( ns & 0x07) << 1)
|
|
|
|
| (flag << 4);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_SABME:
|
|
|
|
return ((sock->vr & 0x7f) << 9)
|
|
|
|
| (( ns & 0x7f) << 1)
|
|
|
|
| (flag << 8);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t control_ui(int flag) {
|
|
|
|
return PATTY_AX25_FRAME_UI | (flag << 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t control_s(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_type type,
|
|
|
|
int flag) {
|
|
|
|
switch (sock->mode) {
|
|
|
|
case PATTY_AX25_SOCK_SABM:
|
|
|
|
return ((sock->vr & 0x07) << 5)
|
|
|
|
| (type & 0x0f)
|
|
|
|
| (flag << 4);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_SABME:
|
|
|
|
return ((sock->vr & 0x7f) << 9)
|
|
|
|
| (type & 0x0f)
|
|
|
|
| (flag << 8);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t control_u(enum patty_ax25_frame_type type,
|
|
|
|
int pf) {
|
|
|
|
return (type & PATTY_AX25_FRAME_U_MASK)
|
|
|
|
| (pf << 4);
|
|
|
|
}
|
|
|
|
|
2020-08-05 21:47:08 -04:00
|
|
|
static ssize_t frame_send(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
uint16_t control,
|
2020-08-14 17:40:13 -04:00
|
|
|
uint8_t proto,
|
2020-08-05 21:47:08 -04:00
|
|
|
void *info,
|
|
|
|
size_t infolen) {
|
2020-07-21 01:38:23 -04:00
|
|
|
size_t offset = 0;
|
|
|
|
ssize_t encoded;
|
2020-07-17 00:22:46 -04:00
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
uint8_t *buf = sock->tx_buf;
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-07-24 19:36:55 -04:00
|
|
|
if (sock->iface == NULL) {
|
|
|
|
errno = ENETDOWN;
|
|
|
|
|
|
|
|
goto error_noif;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->remote.callsign[0] == '\0') {
|
|
|
|
errno = EBADF;
|
|
|
|
|
|
|
|
goto error_nopeer;
|
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if (toobig(sock, infolen)) {
|
2020-06-28 18:11:49 -04:00
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
2020-07-26 01:55:21 -04:00
|
|
|
if ((encoded = encode_address(sock, cr, buf, tx_bufsz(sock))) < 0) {
|
2020-07-21 01:38:23 -04:00
|
|
|
goto error_encode_address;
|
|
|
|
} else {
|
|
|
|
offset += encoded;
|
|
|
|
}
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
buf[offset++] = control & 0x00ff;
|
2020-07-19 20:27:56 -04:00
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABME && !PATTY_AX25_FRAME_CONTROL_U(control)) {
|
|
|
|
buf[offset++] = (control & 0xff00) >> 8;
|
2020-06-28 18:11:49 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if (info && infolen) {
|
2020-07-19 20:27:56 -04:00
|
|
|
if (PATTY_AX25_FRAME_CONTROL_I(control)) {
|
2020-08-14 17:40:13 -04:00
|
|
|
buf[offset++] = proto;
|
2020-07-19 20:27:56 -04:00
|
|
|
}
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-07-02 16:07:23 -04:00
|
|
|
memcpy(buf + offset, info, infolen);
|
2020-07-21 01:38:23 -04:00
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
offset += infolen;
|
|
|
|
}
|
|
|
|
|
2020-07-02 16:07:23 -04:00
|
|
|
return patty_ax25_if_send(sock->iface, buf, offset);
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
error_encode_address:
|
2020-06-28 18:11:49 -04:00
|
|
|
error_toobig:
|
2020-07-24 19:36:55 -04:00
|
|
|
error_nopeer:
|
|
|
|
error_noif:
|
2020-06-28 18:11:49 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-08-17 18:53:55 -04:00
|
|
|
ssize_t patty_ax25_sock_resend(patty_ax25_sock *sock, int seq) {
|
|
|
|
struct slot *slot = tx_slot(sock, seq);
|
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
return slot->len > 0? frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-08-22 22:51:53 -05:00
|
|
|
control_i(sock, seq),
|
2020-08-21 00:41:51 -05:00
|
|
|
sock->proto,
|
|
|
|
slot + 1,
|
|
|
|
slot->len): 0;
|
2020-08-19 22:32:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_resend_pending(patty_ax25_sock *sock) {
|
|
|
|
struct slot *slot = tx_slot(sock, sock->vs);
|
|
|
|
|
|
|
|
if (slot->len > 0 && !slot->ack) {
|
|
|
|
ssize_t len;
|
|
|
|
|
|
|
|
if ((len = patty_ax25_sock_resend(sock, sock->vs)) < 0) {
|
|
|
|
goto error_resend;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->vs = tx_seq(sock, sock->vs + 1);
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_resend:
|
|
|
|
return -1;
|
2020-08-17 18:53:55 -04:00
|
|
|
}
|
|
|
|
|
2020-08-19 22:23:27 -04:00
|
|
|
int patty_ax25_sock_ack(patty_ax25_sock *sock, int nr) {
|
2020-08-18 19:07:43 -05:00
|
|
|
int ret = 0,
|
2020-08-19 22:23:27 -04:00
|
|
|
min = sock->va,
|
|
|
|
max = nr,
|
2020-08-18 19:07:43 -05:00
|
|
|
i;
|
2020-07-17 00:22:46 -04:00
|
|
|
|
2020-08-23 17:35:42 -05:00
|
|
|
if (min == max) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2020-08-19 22:23:27 -04:00
|
|
|
if (max < min) {
|
|
|
|
max += sock->mode == PATTY_AX25_SOCK_SABME? 128: 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=min; i<max; i++) {
|
|
|
|
struct slot *slot = tx_slot(sock, i);
|
2020-08-17 18:53:55 -04:00
|
|
|
|
2020-08-19 22:23:27 -04:00
|
|
|
if (slot->len > 0 && !slot->ack) {
|
2020-08-17 18:53:55 -04:00
|
|
|
slot->ack = 1;
|
2020-08-19 22:23:27 -04:00
|
|
|
|
2020-08-19 22:32:05 -04:00
|
|
|
sock->va = tx_seq(sock, i + 1);
|
2020-08-19 22:23:27 -04:00
|
|
|
|
2020-08-18 19:07:43 -05:00
|
|
|
ret++;
|
2020-08-17 18:53:55 -04:00
|
|
|
}
|
|
|
|
}
|
2020-07-15 23:13:41 -04:00
|
|
|
|
2020-08-18 19:07:43 -05:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int patty_ax25_sock_ack_pending(patty_ax25_sock *sock) {
|
2020-08-23 22:36:59 -05:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
size_t slots = tx_slots(sock),
|
|
|
|
i;
|
2020-08-18 19:07:43 -05:00
|
|
|
|
2020-08-19 22:32:05 -04:00
|
|
|
for (i=0; i<slots; i++) {
|
2020-08-18 19:07:43 -05:00
|
|
|
struct slot *slot = tx_slot(sock, i);
|
|
|
|
|
2020-08-19 22:25:12 -04:00
|
|
|
if (slot->len > 0 && !slot->ack) {
|
2020-08-18 19:07:43 -05:00
|
|
|
ret++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2020-07-15 23:13:41 -04:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rr(patty_ax25_sock *sock,
|
2020-07-26 02:26:12 -04:00
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
int pf) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
cr,
|
|
|
|
control_s(sock, PATTY_AX25_FRAME_RR, pf),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-07-10 00:01:50 -04:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rnr(patty_ax25_sock *sock,
|
2020-07-26 02:26:12 -04:00
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
int pf) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
cr,
|
|
|
|
control_s(sock, PATTY_AX25_FRAME_RNR, pf),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-07-10 00:01:50 -04:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rej(patty_ax25_sock *sock,
|
2020-07-26 02:26:12 -04:00
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
int pf) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
cr,
|
|
|
|
control_s(sock, PATTY_AX25_FRAME_REJ, pf),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-07-10 00:01:50 -04:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_srej(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
cr,
|
|
|
|
control_s(sock, PATTY_AX25_FRAME_SREJ, 1),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-06-28 18:11:49 -04:00
|
|
|
}
|
|
|
|
|
2020-07-18 14:19:42 -04:00
|
|
|
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int pf) {
|
2020-07-27 00:37:04 -04:00
|
|
|
enum patty_ax25_frame_type type = (sock->mode == PATTY_AX25_SOCK_SABME)?
|
|
|
|
PATTY_AX25_FRAME_SABME:
|
|
|
|
PATTY_AX25_FRAME_SABM;
|
2020-06-30 23:20:12 -04:00
|
|
|
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
|
|
|
control_u(type, pf),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-07-10 00:01:50 -04:00
|
|
|
}
|
|
|
|
|
2020-07-18 14:19:42 -04:00
|
|
|
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int pf) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
|
|
|
control_u(PATTY_AX25_FRAME_DISC, pf),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
2020-07-21 01:41:32 -04:00
|
|
|
ssize_t patty_ax25_sock_send_xid(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
2020-07-18 15:10:13 -04:00
|
|
|
patty_ax25_params params;
|
2020-07-21 01:38:23 -04:00
|
|
|
char buf[256];
|
2020-07-19 22:48:48 -04:00
|
|
|
|
2020-07-18 15:10:13 -04:00
|
|
|
ssize_t encoded;
|
|
|
|
|
2020-07-24 19:48:22 -04:00
|
|
|
if (sock->iface == NULL) {
|
|
|
|
errno = ENETDOWN;
|
|
|
|
|
|
|
|
goto error_noif;
|
2020-07-18 15:10:13 -04:00
|
|
|
}
|
|
|
|
|
2020-07-19 22:48:48 -04:00
|
|
|
params.flags = (1 << PATTY_AX25_PARAM_CLASSES)
|
|
|
|
| (1 << PATTY_AX25_PARAM_HDLC)
|
|
|
|
| (1 << PATTY_AX25_PARAM_INFO_RX)
|
|
|
|
| (1 << PATTY_AX25_PARAM_WINDOW_RX)
|
|
|
|
| (1 << PATTY_AX25_PARAM_ACK)
|
|
|
|
| (1 << PATTY_AX25_PARAM_RETRY);
|
2020-07-18 15:10:13 -04:00
|
|
|
|
2020-07-24 19:33:20 -04:00
|
|
|
params.classes = sock->flags_classes;
|
2020-08-03 02:54:49 -04:00
|
|
|
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;
|
2020-07-18 15:10:13 -04:00
|
|
|
params.ack = sock->n_ack;
|
|
|
|
params.retry = sock->n_retry;
|
|
|
|
|
2020-07-21 01:38:23 -04:00
|
|
|
if ((encoded = patty_ax25_frame_encode_xid(¶ms, buf, sizeof(buf))) < 0) {
|
2020-07-18 15:10:13 -04:00
|
|
|
goto error_frame_encode_xid;
|
|
|
|
}
|
|
|
|
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
cr,
|
|
|
|
control_u(PATTY_AX25_FRAME_XID, 0),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
buf,
|
|
|
|
encoded);
|
2020-07-18 15:10:13 -04:00
|
|
|
|
|
|
|
error_frame_encode_xid:
|
2020-07-24 19:48:22 -04:00
|
|
|
error_noif:
|
2020-07-18 15:10:13 -04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-08-01 16:55:31 -04:00
|
|
|
ssize_t patty_ax25_sock_send_test(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr,
|
|
|
|
void *info,
|
|
|
|
size_t infolen) {
|
2020-08-05 21:47:08 -04:00
|
|
|
return frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
|
|
|
control_u(PATTY_AX25_FRAME_TEST, 1),
|
2020-08-14 17:40:13 -04:00
|
|
|
0,
|
2020-08-05 21:47:08 -04:00
|
|
|
info,
|
|
|
|
infolen);
|
2020-08-01 16:55:31 -04:00
|
|
|
}
|
|
|
|
|
2020-08-14 22:24:17 -04:00
|
|
|
static ssize_t write_segmented(patty_ax25_sock *sock,
|
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
|
|
|
size_t segments,
|
|
|
|
seglen;
|
|
|
|
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
int first = 1;
|
|
|
|
|
|
|
|
if (sock->n_maxlen_tx < 2) {
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
|
|
|
seglen = sock->n_maxlen_tx - 1;
|
|
|
|
segments = (len + 1) / seglen;
|
|
|
|
|
|
|
|
if (len % seglen) {
|
|
|
|
segments++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (segments > PATTY_AX25_SOCK_SEGMENTS_MAX) {
|
|
|
|
errno = EOVERFLOW;
|
|
|
|
|
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (segments--) {
|
2020-08-21 00:41:51 -05:00
|
|
|
uint8_t *dest = (uint8_t *)sock->tx_buf;
|
2020-08-14 22:24:17 -04:00
|
|
|
uint8_t header = (uint8_t)(segments & 0xff);
|
|
|
|
|
|
|
|
size_t copylen = segments == 0?
|
|
|
|
len - (len % seglen):
|
|
|
|
seglen & 0xff;
|
|
|
|
|
|
|
|
size_t o = 0;
|
|
|
|
|
|
|
|
uint16_t control = sock->type == PATTY_AX25_SOCK_STREAM?
|
2020-08-22 22:51:53 -05:00
|
|
|
control_i(sock, sock->vs):
|
2020-08-14 22:24:17 -04:00
|
|
|
control_ui(0);
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
header |= 0x80;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest[o++] = header;
|
|
|
|
|
|
|
|
if (first) {
|
|
|
|
dest[o++] = sock->proto;
|
|
|
|
copylen--;
|
|
|
|
first = 0;
|
|
|
|
}
|
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
tx_slot_save(sock, buf + i, copylen);
|
|
|
|
|
2020-08-14 22:24:17 -04:00
|
|
|
memcpy(dest + o, (uint8_t *)buf + i, copylen);
|
|
|
|
|
|
|
|
i += copylen;
|
|
|
|
o += copylen;
|
|
|
|
|
|
|
|
if (frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
|
|
|
control,
|
|
|
|
PATTY_AX25_PROTO_FRAGMENT,
|
|
|
|
sock->tx_buf,
|
|
|
|
o) < 0) {
|
|
|
|
goto error_frame_send;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sock->type == PATTY_AX25_SOCK_STREAM) {
|
|
|
|
patty_ax25_sock_vs_incr(sock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
error_frame_send:
|
|
|
|
error_toobig:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
|
|
|
|
void *buf,
|
|
|
|
size_t len) {
|
2020-07-10 00:01:50 -04:00
|
|
|
if (sock->mode == PATTY_AX25_SOCK_DM) {
|
2020-07-08 16:25:10 -04:00
|
|
|
errno = EBADF;
|
2020-06-30 23:20:12 -04:00
|
|
|
|
2020-07-08 16:25:10 -04:00
|
|
|
goto error_invalid_mode;
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-08-07 18:17:36 -04:00
|
|
|
switch (sock->type) {
|
2020-08-21 00:41:51 -05:00
|
|
|
case PATTY_AX25_SOCK_STREAM:{
|
2020-08-14 22:24:17 -04:00
|
|
|
if (len > sock->n_maxlen_tx) {
|
|
|
|
return write_segmented(sock, buf, len);
|
|
|
|
}
|
2020-07-08 16:25:10 -04:00
|
|
|
|
2020-08-21 00:41:51 -05:00
|
|
|
tx_slot_save(sock, buf, len);
|
|
|
|
|
2020-08-14 17:40:13 -04:00
|
|
|
if (frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-08-22 22:51:53 -05:00
|
|
|
control_i(sock, sock->vs),
|
2020-08-14 17:40:13 -04:00
|
|
|
sock->proto,
|
|
|
|
buf,
|
|
|
|
len) < 0) {
|
2020-08-07 18:17:36 -04:00
|
|
|
goto error_frame_send;
|
|
|
|
}
|
|
|
|
|
|
|
|
patty_ax25_sock_vs_incr(sock);
|
|
|
|
|
|
|
|
break;
|
2020-08-21 00:41:51 -05:00
|
|
|
}
|
2020-08-07 18:17:36 -04:00
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_DGRAM:
|
2020-08-14 22:24:17 -04:00
|
|
|
if (len > sock->n_maxlen_tx) {
|
|
|
|
return write_segmented(sock, buf, len);
|
|
|
|
}
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-08-14 17:40:13 -04:00
|
|
|
if (frame_send(sock,
|
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-08-14 22:24:17 -04:00
|
|
|
control_ui(0),
|
2020-08-14 17:40:13 -04:00
|
|
|
sock->proto,
|
|
|
|
buf,
|
|
|
|
len) < 0) {
|
2020-08-07 18:17:36 -04:00
|
|
|
goto error_frame_send;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_RAW:
|
|
|
|
return patty_ax25_if_send(sock->iface, buf, len);
|
|
|
|
}
|
2020-07-08 16:40:40 -04:00
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
return len;
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-08-05 21:47:08 -04:00
|
|
|
error_frame_send:
|
2020-06-30 23:20:12 -04:00
|
|
|
error_invalid_mode:
|
2020-06-28 18:11:49 -04:00
|
|
|
return -1;
|
2020-06-26 22:44:19 -04:00
|
|
|
}
|