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 <termios.h>
|
|
|
|
#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-06-30 23:20:12 -04:00
|
|
|
static int bind_pty(patty_ax25_sock *sock) {
|
|
|
|
struct termios t;
|
|
|
|
|
|
|
|
if ((sock->fd = open("/dev/ptmx", O_RDWR)) < 0) {
|
|
|
|
goto error_open;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grantpt(sock->fd) < 0) {
|
|
|
|
goto error_grantpt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlockpt(sock->fd) < 0) {
|
|
|
|
goto error_unlockpt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptsname_r(sock->fd, sock->path, sizeof(sock->path)) < 0) {
|
|
|
|
goto error_ptsname_r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tcgetattr(sock->fd, &t) < 0) {
|
|
|
|
goto error_tcgetattr;
|
|
|
|
}
|
|
|
|
|
|
|
|
cfmakeraw(&t);
|
|
|
|
|
|
|
|
if (tcsetattr(sock->fd, TCSANOW, &t) < 0) {
|
|
|
|
goto error_tcsetattr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error_tcsetattr:
|
|
|
|
error_tcgetattr:
|
|
|
|
error_ptsname_r:
|
|
|
|
error_unlockpt:
|
|
|
|
error_grantpt:
|
|
|
|
close(sock->fd);
|
|
|
|
|
|
|
|
error_open:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-17 00:22:46 -04:00
|
|
|
static inline size_t tx_slot_size(size_t len) {
|
|
|
|
return sizeof(size_t)
|
|
|
|
+ sizeof(patty_ax25_addr) * 2
|
|
|
|
+ sizeof(patty_ax25_addr) * PATTY_AX25_MAX_HOPS
|
|
|
|
+ len;
|
|
|
|
}
|
|
|
|
|
2020-07-17 19:37:18 -04:00
|
|
|
static inline size_t tx_slots_size(patty_ax25_sock *sock) {
|
|
|
|
return sock->n_window_tx * tx_slot_size(sock->n_maxlen_tx);
|
2020-07-17 00:22:46 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void *tx_slot(void *slots, size_t i, size_t len) {
|
|
|
|
return (void *)((uint8_t *)slots + (i * tx_slot_size(len)));
|
|
|
|
}
|
|
|
|
|
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-07-17 19:37:18 -04:00
|
|
|
sock->proto = proto;
|
|
|
|
sock->type = type;
|
|
|
|
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_RX_MAXLEN;
|
|
|
|
sock->n_window_tx = PATTY_AX25_SOCK_DEFAULT_WINDOW;
|
|
|
|
sock->n_window_rx = PATTY_AX25_SOCK_RX_WINDOW;
|
|
|
|
|
|
|
|
if ((sock->buf = malloc(PATTY_AX25_FRAME_OVERHEAD + sock->n_maxlen_rx)) == NULL) {
|
|
|
|
goto error_malloc_buf;
|
2020-07-15 23:13:41 -04:00
|
|
|
}
|
|
|
|
|
2020-07-17 19:37:18 -04:00
|
|
|
if ((sock->tx_slots = malloc(tx_slots_size(sock))) == NULL) {
|
2020-07-15 23:13:41 -04:00
|
|
|
goto error_malloc_tx_slots;
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bind_pty(sock) < 0) {
|
|
|
|
goto error_bind_pty;
|
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
return sock;
|
|
|
|
|
2020-06-30 23:20:12 -04:00
|
|
|
error_bind_pty:
|
2020-07-15 23:13:41 -04:00
|
|
|
free(sock->tx_slots);
|
|
|
|
|
|
|
|
error_malloc_tx_slots:
|
2020-07-17 19:37:18 -04:00
|
|
|
free(sock->buf);
|
2020-06-30 23:20:12 -04:00
|
|
|
|
2020-07-17 19:37:18 -04:00
|
|
|
error_malloc_buf:
|
2020-06-30 23:20:12 -04:00
|
|
|
free(sock);
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
error_malloc_sock:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-06-30 23:20:12 -04:00
|
|
|
void patty_ax25_sock_reset(patty_ax25_sock *sock) {
|
2020-07-17 19:37:18 -04:00
|
|
|
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_RX_MAXLEN;
|
|
|
|
sock->n_retry = PATTY_AX25_SOCK_DEFAULT_RETRY;
|
|
|
|
sock->n_window_tx = PATTY_AX25_SOCK_RX_WINDOW;
|
2020-07-03 15:21:32 -04:00
|
|
|
sock->timer_ack = 0;
|
|
|
|
sock->timer_response = 0;
|
|
|
|
sock->timer_keepalive = 0;
|
2020-07-17 00:24:49 -04:00
|
|
|
sock->flags = 0;
|
2020-07-03 15:21:32 -04:00
|
|
|
sock->seq_send = 0;
|
|
|
|
sock->seq_recv = 0;
|
2020-06-30 23:20:12 -04:00
|
|
|
}
|
|
|
|
|
2020-06-25 20:37:12 -04:00
|
|
|
void patty_ax25_sock_destroy(patty_ax25_sock *sock) {
|
2020-06-30 23:20:12 -04:00
|
|
|
if (sock->fd) {
|
2020-07-07 17:48:18 -04:00
|
|
|
if (sock->iface) {
|
|
|
|
(void)patty_ax25_if_promisc_delete(sock->iface, sock->fd);
|
|
|
|
}
|
|
|
|
|
2020-06-30 23:20:12 -04:00
|
|
|
close(sock->fd);
|
|
|
|
}
|
|
|
|
|
2020-07-17 19:37:18 -04:00
|
|
|
free(sock->buf);
|
2020-07-15 23:13:41 -04:00
|
|
|
free(sock->tx_slots);
|
2020-06-25 20:37:12 -04:00
|
|
|
free(sock);
|
|
|
|
}
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-07-15 23:13:41 -04:00
|
|
|
int patty_ax25_sock_mode_set(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_sock_mode mode) {
|
|
|
|
if (sock->mode == mode) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock->mode = mode;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-02 16:06:51 -04:00
|
|
|
char *patty_ax25_sock_pty(patty_ax25_sock *sock) {
|
|
|
|
return sock->path;
|
|
|
|
}
|
|
|
|
|
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-07-07 17:48:18 -04:00
|
|
|
|
|
|
|
if (sock->type == PATTY_AX25_SOCK_RAW) {
|
|
|
|
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-07-08 16:25:10 -04:00
|
|
|
void patty_ax25_sock_seq_send_incr(patty_ax25_sock *sock) {
|
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABME) {
|
|
|
|
sock->seq_send = (sock->seq_send + 1) & 0x07;
|
|
|
|
} else {
|
|
|
|
sock->seq_send = (sock->seq_send + 1) & 0x7f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void patty_ax25_sock_seq_recv_incr(patty_ax25_sock *sock) {
|
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABME) {
|
|
|
|
sock->seq_recv = (sock->seq_recv + 1) & 0x07;
|
|
|
|
} else {
|
|
|
|
sock->seq_recv = (sock->seq_recv + 1) & 0x7f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-15 23:13:41 -04:00
|
|
|
static size_t addr_copy_to_buf(void *dest,
|
|
|
|
patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
|
|
|
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-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-06-28 18:11:49 -04:00
|
|
|
static inline int toobig(patty_ax25_sock *sock,
|
|
|
|
uint16_t control,
|
|
|
|
size_t infolen) {
|
2020-07-17 19:37:18 -04:00
|
|
|
return infolen > PATTY_AX25_FRAME_OVERHEAD + sock->n_maxlen_tx;
|
2020-06-28 18:11:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
enum patty_ax25_frame_cr cr,
|
2020-06-28 18:11:49 -04:00
|
|
|
uint16_t control,
|
|
|
|
void *info,
|
|
|
|
size_t infolen) {
|
2020-06-30 23:20:12 -04:00
|
|
|
size_t offset;
|
2020-07-17 00:22:46 -04:00
|
|
|
|
|
|
|
void *slot = tx_slot(sock->tx_slots,
|
|
|
|
sock->seq_send,
|
2020-07-17 19:37:18 -04:00
|
|
|
sock->n_maxlen_tx);
|
2020-07-17 00:22:46 -04:00
|
|
|
|
|
|
|
uint8_t *buf = (uint8_t *)slot + sizeof(size_t);
|
2020-06-28 18:11:49 -04:00
|
|
|
|
|
|
|
if (toobig(sock, control, infolen)) {
|
|
|
|
goto error_toobig;
|
|
|
|
}
|
|
|
|
|
2020-07-15 23:13:41 -04:00
|
|
|
offset = addr_copy_to_buf(buf, sock, cr);
|
2020-06-28 18:11:49 -04:00
|
|
|
|
|
|
|
if (sock->mode == PATTY_AX25_SOCK_SABME) {
|
2020-07-02 16:07:23 -04:00
|
|
|
buf[offset++] = (control & 0xff00) >> 8;
|
|
|
|
buf[offset++] = control & 0x00ff;
|
2020-06-28 18:11:49 -04:00
|
|
|
} else {
|
2020-07-02 16:07:23 -04:00
|
|
|
buf[offset++] = control;
|
2020-06-28 18:11:49 -04:00
|
|
|
}
|
|
|
|
|
2020-07-08 16:40:40 -04:00
|
|
|
if (info) {
|
2020-07-02 16:07:23 -04:00
|
|
|
buf[offset++] = (uint8_t)sock->proto;
|
2020-06-28 18:11:49 -04:00
|
|
|
|
2020-07-02 16:07:23 -04:00
|
|
|
memcpy(buf + offset, info, infolen);
|
2020-06-28 18:11:49 -04:00
|
|
|
offset += infolen;
|
|
|
|
}
|
|
|
|
|
2020-07-17 00:22:46 -04:00
|
|
|
*((size_t *)slot) = offset;
|
2020-07-15 23:13:41 -04:00
|
|
|
|
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
|
|
|
|
|
|
|
error_toobig:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-15 23:13:41 -04:00
|
|
|
ssize_t patty_ax25_sock_resend(patty_ax25_sock *sock,
|
|
|
|
unsigned int seq) {
|
2020-07-17 19:37:18 -04:00
|
|
|
void *slot = tx_slot(sock->tx_slots, seq, sock->n_maxlen_tx);
|
2020-07-17 00:22:46 -04:00
|
|
|
void *buf = (uint8_t *)slot + sizeof(size_t);
|
|
|
|
|
|
|
|
size_t len = *((size_t *)slot);
|
2020-07-15 23:13:41 -04:00
|
|
|
|
2020-07-17 00:22:46 -04:00
|
|
|
return patty_ax25_if_send(sock->iface, buf, len);
|
2020-07-15 23:13:41 -04:00
|
|
|
}
|
|
|
|
|
2020-07-10 00:01:50 -04:00
|
|
|
static uint16_t control_i(patty_ax25_sock *sock, int flag) {
|
|
|
|
switch (sock->mode) {
|
|
|
|
case PATTY_AX25_SOCK_SABM:
|
|
|
|
return ((sock->seq_recv & 0x07) << 5)
|
|
|
|
| ((sock->seq_send & 0x07))
|
|
|
|
| (flag << 4);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_SABME:
|
|
|
|
return ((sock->seq_recv & 0x7f) << 9)
|
|
|
|
| ((sock->seq_send & 0x7f))
|
|
|
|
| (flag << 8);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static 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->seq_recv & 0x07) << 5)
|
|
|
|
| (type & 0x0f)
|
|
|
|
| (flag << 4);
|
|
|
|
|
|
|
|
case PATTY_AX25_SOCK_SABME:
|
|
|
|
return ((sock->seq_recv & 0x7f) << 9)
|
|
|
|
| (type & 0x0f)
|
|
|
|
| (flag << 8);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t control_u(enum patty_ax25_frame_type type,
|
2020-07-18 14:19:42 -04:00
|
|
|
int pf) {
|
2020-07-10 00:01:50 -04:00
|
|
|
return (type & PATTY_AX25_FRAME_U_MASK)
|
2020-07-18 14:19:42 -04:00
|
|
|
| (pf << 4);
|
2020-07-10 00:01:50 -04:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rr(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
2020-07-10 00:01:50 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
cr,
|
2020-07-10 00:01:50 -04:00
|
|
|
control_s(sock, PATTY_AX25_FRAME_RR, 1),
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rnr(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
2020-07-10 00:01:50 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
cr,
|
2020-07-10 00:01:50 -04:00
|
|
|
control_s(sock, PATTY_AX25_FRAME_RNR, 1),
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
ssize_t patty_ax25_sock_send_rej(patty_ax25_sock *sock,
|
|
|
|
enum patty_ax25_frame_cr cr) {
|
2020-07-10 00:01:50 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
cr,
|
2020-07-10 00:01:50 -04:00
|
|
|
control_s(sock, PATTY_AX25_FRAME_REJ, 1),
|
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
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-06-28 18:11:49 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
cr,
|
2020-07-10 00:01:50 -04:00
|
|
|
control_s(sock, PATTY_AX25_FRAME_SREJ, 1),
|
2020-06-28 18:11:49 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2020-07-18 14:19:42 -04:00
|
|
|
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int pf) {
|
2020-06-30 23:20:12 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-07-18 14:19:42 -04:00
|
|
|
control_u(PATTY_AX25_FRAME_SABM, pf),
|
2020-06-30 23:20:12 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2020-07-18 14:19:42 -04:00
|
|
|
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int pf) {
|
2020-06-30 23:20:12 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-07-18 14:19:42 -04:00
|
|
|
control_u(PATTY_AX25_FRAME_SABME, pf),
|
2020-07-10 00:01:50 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
2020-07-18 14:19:42 -04:00
|
|
|
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int pf) {
|
2020-07-10 00:01:50 -04:00
|
|
|
return patty_ax25_sock_send(sock,
|
2020-07-14 17:04:49 -04:00
|
|
|
PATTY_AX25_FRAME_COMMAND,
|
2020-07-18 14:19:42 -04:00
|
|
|
control_u(PATTY_AX25_FRAME_DISC, pf),
|
2020-06-30 23:20:12 -04:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
uint16_t control;
|
2020-06-30 23:20:12 -04:00
|
|
|
|
2020-07-03 15:21:32 -04:00
|
|
|
if (sock->type == PATTY_AX25_SOCK_RAW) {
|
2020-07-02 16:07:23 -04:00
|
|
|
return patty_ax25_if_send(sock->iface, buf, 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-07-10 00:01:50 -04:00
|
|
|
control = control_i(sock, 0);
|
2020-07-08 16:25:10 -04:00
|
|
|
|
2020-07-14 17:04:49 -04:00
|
|
|
if (patty_ax25_sock_send(sock, PATTY_AX25_FRAME_RESPONSE, control, buf, len) < 0) {
|
2020-06-28 18:11:49 -04:00
|
|
|
goto error_send;
|
|
|
|
}
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-07-08 16:40:40 -04:00
|
|
|
patty_ax25_sock_seq_send_incr(sock);
|
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
return len;
|
2020-06-26 22:44:19 -04:00
|
|
|
|
2020-06-28 18:11:49 -04:00
|
|
|
error_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
|
|
|
}
|