Implement better modulo-128 I and S frame support

Changes:

    * Split patty_ax25_frame_decode() into the following:

      - patty_ax25_frame_decode_address()
      - patty_ax25_frame_decode_control()

      This allows for look up an established socket for a given address
      pair, to determine if an SABME session is in progress,
      necessitating modulo-128 control decoding

    * Decode I and S N(R), N(S) sequence numbers, poll/final
      bits properly in both modulo-8 and modulo-128 mode

    * Perform better frame control validation

    * Implement the following functions in src/sock.c:

      - patty_ax25_sock_send_rr()
      - patty_ax25_sock_send_rnr()
      - patty_ax25_sock_send_rej()
      - patty_ax25_sock_send_srej()

      Corresponding functions have been removed from src/server.c

    * Implement better functions in src/sock.c for encoding frame
      control, with send/receive sequences associated with the socket,
      with modulo-128 encoding for SABME sessions

Other changes:

    * Move or delete macros from include/patty/ax25/macros.h into
      include/patty/ax25.h and include/patty/ax25/frame.h

    * Move definitions from include/patty/ax25/proto.h to header file
      include/patty/ax25.h

    * Perform better bounds checking while decoding frames

    * Improve frame control printing in src/print.c; display frame
      type names, N(R), (NS) sequence numbers, and poll/final bits
This commit is contained in:
XANTRONIX Development 2020-07-10 00:01:50 -04:00 committed by XANTRONIX Industrial
parent c2766a4405
commit a4518a839a
13 changed files with 466 additions and 381 deletions

View file

@ -89,12 +89,20 @@ int main(int argc, char **argv) {
while ((readlen = patty_kiss_tnc_recv(raw, buf, sizeof(buf), NULL)) > 0) {
patty_ax25_frame frame;
ssize_t decoded;
if (patty_ax25_frame_decode(&frame, PATTY_AX25_FRAME_NORMAL, buf, readlen) < 0) {
if ((decoded = patty_ax25_frame_decode_address(&frame, buf, readlen)) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_frame_decode()", strerror(errno));
argv[0], "patty_ax25_frame_decode_address()", strerror(errno));
goto error_ax25_frame_decode;
goto error_ax25_frame_decode_address;
}
if (patty_ax25_frame_decode_control(&frame, PATTY_AX25_FRAME_NORMAL, buf, decoded, readlen) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_frame_decode_control()", strerror(errno));
goto error_ax25_frame_decode_control;
}
if (patty_print_frame(stdout, &frame, buf, readlen) < 0) {
@ -114,7 +122,8 @@ int main(int argc, char **argv) {
return 0;
error_print_frame:
error_ax25_frame_decode:
error_ax25_frame_decode_control:
error_ax25_frame_decode_address:
patty_kiss_tnc_destroy(raw);
error_kiss_tnc_new:

View file

@ -49,7 +49,8 @@ int main(int argc, char **argv) {
}
while (1) {
ssize_t len;
ssize_t len,
decoded;
patty_ax25_frame frame;
if ((len = patty_kiss_tnc_recv(tnc, buf, PATTY_KISS_BUFSZ, &port)) < 0) {
@ -61,11 +62,18 @@ int main(int argc, char **argv) {
break;
}
if (patty_ax25_frame_decode(&frame, PATTY_AX25_FRAME_NORMAL, buf, len) < 0) {
if ((decoded = patty_ax25_frame_decode_address(&frame, buf, len)) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_frame_decode()", strerror(errno));
argv[0], "patty_ax25_frame_decode_address()", strerror(errno));
goto error_ax25_frame_decode;
goto error_ax25_frame_decode_address;
}
if (patty_ax25_frame_decode_control(&frame, PATTY_AX25_FRAME_NORMAL, buf, decoded, len) < 0) {
fprintf(stderr, "%s: %s: %s\n",
argv[0], "patty_ax25_frame_decode_control()", strerror(errno));
goto error_ax25_frame_decode_control;
}
if (patty_print_frame(stdout, &frame, buf, len) < 0) {
@ -83,7 +91,8 @@ int main(int argc, char **argv) {
return 0;
error_print_frame:
error_ax25_frame_decode:
error_ax25_frame_decode_control:
error_ax25_frame_decode_address:
error_kiss_tnc_recv:
free(buf);

View file

@ -8,11 +8,36 @@
#include <patty/list.h>
#include <patty/dict.h>
#define PATTY_AX25_ADDRESS_SIZE 7
#define PATTY_AX25_ADDR_SIZE 7
#define PATTY_AX25_CALLSIGN_LEN 6
#define PATTY_AX25_IF_NAME_SIZE 8
#define PATTY_AX25_MAX_HOPS 8
#define PATTY_AX25_SOCK_PATH_SIZE 256
enum patty_ax25_version {
PATTY_AX25_OLD,
PATTY_AX25_2_0,
PATTY_AX25_2_2
};
enum patty_ax25_proto {
PATTY_AX25_PROTO_UNKNOWN = 0x00,
PATTY_AX25_PROTO_ISO_8208 = 0x01,
PATTY_AX25_PROTO_TCP_VJ_COMPR = 0x06,
PATTY_AX25_PROTO_TCP_VJ = 0x07,
PATTY_AX25_PROTO_FRAGMENT = 0x08,
PATTY_AX25_PROTO_TEXNET = 0xc3,
PATTY_AX25_PROTO_LQP = 0xc4,
PATTY_AX25_PROTO_APPLETALK = 0xca,
PATTY_AX25_PROTO_APPLETALK_ARP = 0xcb,
PATTY_AX25_PROTO_INET = 0xcc,
PATTY_AX25_PROTO_INET_ARP = 0xcd,
PATTY_AX25_PROTO_FLEXNET = 0xce,
PATTY_AX25_PROTO_NETROM = 0xcf,
PATTY_AX25_PROTO_NONE = 0xf0,
PATTY_AX25_PROTO_ESCAPE = 0xff
};
#pragma pack(push)
#pragma pack(1)
@ -25,8 +50,6 @@ typedef struct _patty_ax25_addr {
typedef struct _patty_ax25_if patty_ax25_if;
#include <patty/ax25/macros.h>
#include <patty/ax25/proto.h>
#include <patty/ax25/frame.h>
#include <patty/ax25/call.h>
#include <patty/ax25/if.h>
@ -34,6 +57,21 @@ typedef struct _patty_ax25_if patty_ax25_if;
#include <patty/ax25/sock.h>
#include <patty/ax25/server.h>
#define PATTY_AX25_ADDR_CHAR_VALID(c) \
((c >= 0x20 && c <= 0x5a))
#define PATTY_AX25_ADDR_OCTET_LAST(c) \
((c & 0x01) == 0x01)
#define PATTY_AX25_ADDR_SSID_NUMBER(c) \
((c & 0x1e) >> 1)
#define PATTY_AX25_ADDR_SSID_C(c) \
((c & 0x80) == 0x80)
#define PATTY_AX25_ADDR_SSID_REPEATED(c) \
((c & 0x80) == 0x80)
int patty_ax25_pton(const char *callsign,
uint8_t ssid,
patty_ax25_addr *addr);

View file

@ -7,66 +7,88 @@
#define PATTY_AX25_FRAME_DEFAULT_MAXLEN 256
#define PATTY_AX25_FRAME_DEFAULT_WINDOW 8
#define PATTY_AX25_FRAME_SIZE(format, hops, c, infolen) \
(((2 + hops) * sizeof(patty_ax25_addr)) \
+ (format == PATTY_AX25_FRAME_EXTENDED? 2: 1) \
+ (PATTY_AX25_CONTROL_INFO(c)? 1 + infolen: 0))
enum patty_ax25_frame_format {
PATTY_AX25_FRAME_NORMAL,
PATTY_AX25_FRAME_EXTENDED
};
enum patty_ax25_frame_type {
PATTY_AX25_FRAME_INFO = 0x00,
PATTY_AX25_FRAME_SUPER = 0x01,
PATTY_AX25_FRAME_UNNUMBERED = 0x03,
PATTY_AX25_FRAME_UNKNOWN = 0xff
};
enum patty_ax25_frame_flags {
PATTY_AX25_FRAME_POLL = (1 << 4),
PATTY_AX25_FRAME_FINAL = (1 << 4)
};
enum patty_ax25_frame_cr {
PATTY_AX25_FRAME_COMMAND,
PATTY_AX25_FRAME_RESPONSE
};
enum patty_ax25_frame_s_type {
PATTY_AX25_FRAME_S_RR = 0x01,
PATTY_AX25_FRAME_S_RNR = 0x05,
PATTY_AX25_FRAME_S_REJ = 0x09,
PATTY_AX25_FRAME_S_SREJ = 0x0d
enum patty_ax25_frame_flag {
PATTY_AX25_FRAME_POLL = 1,
PATTY_AX25_FRAME_FINAL = 1
};
enum patty_ax25_frame_u_type {
PATTY_AX25_FRAME_U_SABME = 0x6f,
PATTY_AX25_FRAME_U_SABM = 0x2f,
PATTY_AX25_FRAME_U_DISC = 0x43,
PATTY_AX25_FRAME_U_DM = 0x0f,
PATTY_AX25_FRAME_U_UA = 0x63,
PATTY_AX25_FRAME_U_FRMR = 0x87,
PATTY_AX25_FRAME_U_UI = 0x03,
PATTY_AX25_FRAME_U_XID = 0x8f,
PATTY_AX25_FRAME_U_TEST = 0xe3
#define PATTY_AX25_FRAME_CONTROL_I(c) \
((c & 0x1) == 0x00)
#define PATTY_AX25_FRAME_CONTROL_S(c) \
((c & 0x03) == 0x01)
#define PATTY_AX25_FRAME_CONTROL_U(c) \
((c & 0x03) == 0x03)
#define PATTY_AX25_FRAME_CONTROL_UI(c) \
((c & 0xef) == 0x03)
#define PATTY_AX25_FRAME_CONTROL_FLAG(c) \
((c & 0x01) >> 4)
#define PATTY_AX25_FRAME_SIZE(format, hops, c, infolen) \
(((2 + hops) * sizeof(patty_ax25_addr)) \
+ (format == PATTY_AX25_FRAME_EXTENDED? 2: 1) \
+ (PATTY_AX25_FRAME_CONTROL_I(c)? 1 + infolen: 0))
#define PATTY_AX25_FRAME_S_MASK 0x0f
#define PATTY_AX25_FRAME_U_MASK 0xef
enum patty_ax25_frame_type {
PATTY_AX25_FRAME_I = 0x00,
PATTY_AX25_FRAME_RR = 0x01,
PATTY_AX25_FRAME_RNR = 0x05,
PATTY_AX25_FRAME_REJ = 0x09,
PATTY_AX25_FRAME_SREJ = 0x0d,
PATTY_AX25_FRAME_SABM = 0x2f,
PATTY_AX25_FRAME_SABME = 0x6f,
PATTY_AX25_FRAME_DISC = 0x43,
PATTY_AX25_FRAME_DM = 0x0f,
PATTY_AX25_FRAME_UA = 0x63,
PATTY_AX25_FRAME_FRMR = 0x87,
PATTY_AX25_FRAME_UI = 0x03,
PATTY_AX25_FRAME_XID = 0x8f,
PATTY_AX25_FRAME_TEST = 0xe3,
PATTY_AX25_FRAME_UNKNOWN = 0xff
};
typedef struct _patty_ax25_frame {
patty_ax25_addr dest,
src,
repeaters[7];
repeaters[PATTY_AX25_MAX_HOPS];
unsigned int hops;
uint16_t control;
uint8_t proto;
uint8_t nr, ns, pf;
enum patty_ax25_frame_type type;
uint8_t proto;
void *info;
size_t infolen;
} patty_ax25_frame;
ssize_t patty_ax25_frame_decode_address(patty_ax25_frame *frame,
void *buf,
size_t len);
ssize_t patty_ax25_frame_decode_control(patty_ax25_frame *frame,
enum patty_ax25_frame_format format,
void *buf,
size_t offset,
size_t len);
ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame,
enum patty_ax25_frame_format format,
void *buf,

View file

@ -1,103 +0,0 @@
#ifndef _PATTY_AX25_MACROS_H
#define _PATTY_AX25_MACROS_H
#define PATTY_AX25_ADDRESS_CHAR_VALID(c) \
((c >= 0x20 && c <= 0x5a))
#define PATTY_AX25_ADDRESS_OCTET_LAST(c) \
((c & 0x01) == 0x01)
#define PATTY_AX25_ADDRESS_SSID_NUMBER(c) \
((c & 0x1e) >> 1)
#define PATTY_AX25_ADDRESS_SSID_C(c) \
((c & 0x80) == 0x80)
#define PATTY_AX25_ADDRESS_SSID_REPEATED(c) \
((c & 0x80) == 0x80)
#define PATTY_AX25_CONTROL_INFO(c) \
((c & 0x01) == 0)
#define PATTY_AX25_CONTROL_INFO_RESET(c) \
(c = 0x00)
#define PATTY_AX25_CONTROL_SUPER(c) \
((c & 0x03) == 0x01)
#define PATTY_AX25_CONTROL_SUPER_RESET(c) \
(c = 0x01)
#define PATTY_AX25_CONTROL_SUPER_RR(c) \
((c & 0x0f) == 0x01)
#define PATTY_AX25_CONTROL_SUPER_RNR(c) \
((c & 0x0f) == 0x05)
#define PATTY_AX25_CONTROL_SUPER_REJ(c) \
((c & 0x0f) == 0x09)
#define PATTY_AX25_CONTROL_UNNUMBERED(c) \
((c & 0x03) == 0x03)
#define PATTY_AX25_CONTROL_UNNUMBERED_RESET(c) \
(c = 0x03)
#define PATTY_AX25_CONTROL_UNNUMBERED_MODIFIER(c) \
((c & 0xe0) >> 5)
#define PATTY_AX25_CONTROL_UNNUMBERED_SABM(c) \
((c & 0xef) == 0x2f)
#define PATTY_AX25_CONTROL_UNNUMBERED_DISC(c) \
((c & 0xef) == 0x43)
#define PATTY_AX25_CONTROL_UNNUMBERED_DM(c) \
((c & 0xef) == 0x0f)
#define PATTY_AX25_CONTROL_UNNUMBERED_UA(c) \
((c & 0xef) == 0x63)
#define PATTY_AX25_CONTROL_UNNUMBERED_FRMR(c) \
((c & 0xef) == 0x47)
#define PATTY_AX25_CONTROL_UNNUMBERED_INFO(c) \
((c & 0xef) == 0x03)
#define PATTY_AX25_CONTROL_SEQ_SEND(c) \
((c & 0x0e) >> 1)
#define PATTY_AX25_CONTROL_SEQ_RECV(c) \
((c & 0xe0) >> 5)
#define PATTY_AX25_CONTROL_POLL(c) \
((c & 0x10) >> 4)
#define PATTY_AX25_CONTROL_FINAL(c) \
PATTY_AX25_CONTROL_POLL(c)
#define PATTY_AX25_FRMR_Z(frmr) \
((frmr[0] & 0x08) >> 3)
#define PATTY_AX25_FRMR_Y(frmr) \
((frmr[0] & 0x04) >> 2)
#define PATTY_AX25_FRMR_X(frmr) \
((frmr[0] & 0x02) >> 1)
#define PATTY_AX25_FRMR_W(frmr) \
(frmr[0] & 0x01)
#define PATTY_AX25_FRMR_VR(frmr) \
((frmr[1] & 0xe0) >> 5)
#define PATTY_AX25_FRMR_CR(frmr) \
((frmr[1] & 0x10) >> 4)
#define PATTY_AX25_FRMR_VS(frmr) \
((frmr[1] & 0x0e) >> 1)
#define PATTY_AX25_FRMR_CTRL(frmr) \
(frmr[2])
#endif /* _PATTY_AX25_MACROS_H */

View file

@ -1,29 +0,0 @@
#ifndef _PATTY_AX25_PROTO_H
#define _PATTY_AX25_PROTO_H
#define PATTY_AX25_MAX_HOPS 8
enum patty_ax25_version {
PATTY_AX25_OLD,
PATTY_AX25_2_0
};
enum patty_ax25_proto {
PATTY_AX25_PROTO_UNKNOWN = 0x00,
PATTY_AX25_PROTO_ISO_8208 = 0x01,
PATTY_AX25_PROTO_TCP_VJ_COMPR = 0x06,
PATTY_AX25_PROTO_TCP_VJ = 0x07,
PATTY_AX25_PROTO_FRAGMENT = 0x08,
PATTY_AX25_PROTO_TEXNET = 0xc3,
PATTY_AX25_PROTO_LQP = 0xc4,
PATTY_AX25_PROTO_APPLETALK = 0xca,
PATTY_AX25_PROTO_APPLETALK_ARP = 0xcb,
PATTY_AX25_PROTO_INET = 0xcc,
PATTY_AX25_PROTO_INET_ARP = 0xcd,
PATTY_AX25_PROTO_FLEXNET = 0xce,
PATTY_AX25_PROTO_NETROM = 0xcf,
PATTY_AX25_PROTO_NONE = 0xf0,
PATTY_AX25_PROTO_ESCAPE = 0xff
};
#endif /* _PATTY_AX25_PROTO_H */

View file

@ -58,17 +58,6 @@ typedef struct _patty_ax25_sock {
unsigned int hops;
} patty_ax25_sock;
#define PATTY_AX25_SOCK_CONTROL_SABM(sock, pf) \
(((sock->seq_recv & 0x07) << 7) | (pf << 4) | (sock->seq_send & 0x07))
#define PATTY_AX25_SOCK_CONTROL_SABME(sock, pf) \
(((sock->seq_recv & 0x7f) << 15) | (pf << 7) | (sock->seq_send & 0x7f))
#define PATTY_AX25_SOCK_CONTROL(sock, pf) \
(sock->mode == PATTY_AX25_SOCK_SABME? \
PATTY_AX25_SOCK_CONTROL_SABME(sock, pf): \
PATTY_AX25_SOCK_CONTROL_SABM(sock, pf))
patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_proto proto,
enum patty_ax25_sock_type type);
@ -90,11 +79,19 @@ ssize_t patty_ax25_sock_send(patty_ax25_sock *sock,
void *info,
size_t infolen);
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_send_rr(patty_ax25_sock *sock);
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_send_rnr(patty_ax25_sock *sock);
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int poll);
ssize_t patty_ax25_sock_send_rej(patty_ax25_sock *sock);
ssize_t patty_ax25_sock_send_srej(patty_ax25_sock *sock);
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int flag);
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int flag);
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int flag);
ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
void *buf,

View file

@ -7,9 +7,8 @@ CC = $(CROSS)cc
CFLAGS = $(CGFLAGS) -fPIC -Wall -O2 -I$(INCLUDE_PATH)
LDFLAGS =
HEADERS = kiss.h ax25.h ax25/if.h ax25/macros.h ax25/proto.h \
ax25/call.h ax25/frame.h ax25/sock.h ax25/route.h \
ax25/server.h list.h hash.h dict.h print.h
HEADERS = kiss.h ax25.h ax25/if.h ax25/call.h ax25/frame.h ax25/sock.h \
ax25/route.h ax25/server.h list.h hash.h dict.h print.h
OBJS = kiss.o ax25.o if.o call.o frame.o sock.o route.o server.o \
list.o hash.o dict.o print.o

View file

@ -21,7 +21,7 @@ int patty_ax25_pton(const char *callsign,
end = 1;
} else {
if (!PATTY_AX25_ADDRESS_CHAR_VALID(callsign[i])) {
if (!PATTY_AX25_ADDR_CHAR_VALID(callsign[i])) {
errno = EINVAL;
goto error_invalid_callsign;
@ -58,7 +58,7 @@ int patty_ax25_ntop(const patty_ax25_addr *addr,
break;
}
if (PATTY_AX25_ADDRESS_OCTET_LAST(addr->callsign[i])) {
if (PATTY_AX25_ADDR_OCTET_LAST(addr->callsign[i])) {
errno = EINVAL;
goto error_invalid_args;
@ -66,7 +66,7 @@ int patty_ax25_ntop(const patty_ax25_addr *addr,
c = (addr->callsign[i] & 0xfe) >> 1;
if (!PATTY_AX25_ADDRESS_CHAR_VALID(c)) {
if (!PATTY_AX25_ADDR_CHAR_VALID(c)) {
errno = EINVAL;
goto error_invalid_args;
@ -104,5 +104,5 @@ void patty_ax25_addr_hash(uint32_t *hash, const patty_ax25_addr *addr) {
hash_byte(hash, addr->callsign[i] >> 1);
}
hash_byte(hash, PATTY_AX25_ADDRESS_SSID_NUMBER(addr->ssid));
hash_byte(hash, PATTY_AX25_ADDR_SSID_NUMBER(addr->ssid));
}

View file

@ -1,19 +1,27 @@
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#include <patty/ax25.h>
static ssize_t decode_station(patty_ax25_addr *addr,
void *data,
off_t offset) {
size_t offset,
size_t len) {
int i, space = 0;
if (len < offset + sizeof(patty_ax25_addr)) {
errno = EIO;
goto error;
}
for (i=0; i<PATTY_AX25_CALLSIGN_LEN; i++) {
uint8_t b = ((uint8_t *)data + offset)[i];
uint8_t c = b >> 1;
if (!PATTY_AX25_ADDRESS_CHAR_VALID(c) || PATTY_AX25_ADDRESS_OCTET_LAST(b)) {
errno = EINVAL;
if (!PATTY_AX25_ADDR_CHAR_VALID(c) || PATTY_AX25_ADDR_OCTET_LAST(b)) {
errno = EIO;
goto error;
}
@ -21,7 +29,7 @@ static ssize_t decode_station(patty_ax25_addr *addr,
if (c == ' ' && !space) {
space = 1;
} else if (c != ' ' && space) {
errno = EINVAL;
errno = EIO;
goto error;
}
@ -29,7 +37,7 @@ static ssize_t decode_station(patty_ax25_addr *addr,
memcpy(addr, ((uint8_t *)data) + offset, sizeof(*addr));
return PATTY_AX25_ADDRESS_SIZE;
return PATTY_AX25_ADDR_SIZE;
error:
return -1;
@ -37,22 +45,24 @@ error:
static ssize_t decode_hops(patty_ax25_frame *frame,
void *data,
off_t start) {
ssize_t decoded;
off_t offset = start;
int i;
size_t offset,
size_t len) {
ssize_t start = offset;
patty_ax25_addr *addr = NULL;
int i;
/*
* Try to count the AX.25-specified maximum number of hops in the current
* frame.
*/
for (i=0; i<PATTY_AX25_MAX_HOPS; i++) {
ssize_t decoded;
addr = (patty_ax25_addr *)((uint8_t *)data + offset);
if ((decoded = decode_station(&frame->repeaters[i], data, offset)) < 0) {
if ((decoded = decode_station(&frame->repeaters[i], data, offset, len)) < 0) {
goto error;
} else {
offset += decoded;
@ -60,7 +70,7 @@ static ssize_t decode_hops(patty_ax25_frame *frame,
frame->hops++;
if (PATTY_AX25_ADDRESS_OCTET_LAST(addr->ssid)) {
if (PATTY_AX25_ADDR_OCTET_LAST(addr->ssid)) {
break;
}
}
@ -69,8 +79,8 @@ static ssize_t decode_hops(patty_ax25_frame *frame,
* If the last hop does not have the address extension bit set, then
* that's a big problem.
*/
if (addr && !PATTY_AX25_ADDRESS_OCTET_LAST(addr->ssid)) {
errno = EINVAL;
if (addr && !PATTY_AX25_ADDR_OCTET_LAST(addr->ssid)) {
errno = EIO;
goto error;
}
@ -81,19 +91,19 @@ error:
return -1;
}
static ssize_t decode_address(patty_ax25_frame *frame,
void *data,
off_t start) {
off_t offset = start;
ssize_t patty_ax25_frame_decode_address(patty_ax25_frame *frame,
void *buf,
size_t len) {
size_t offset = 0;
ssize_t decoded;
if ((decoded = decode_station(&frame->dest, data, offset)) < 0) {
if ((decoded = decode_station(&frame->dest, buf, offset, len)) < 0) {
goto error;
} else {
offset += decoded;
}
if ((decoded = decode_station(&frame->src, data, offset)) < 0) {
if ((decoded = decode_station(&frame->src, buf, offset, len)) < 0) {
goto error;
} else {
offset += decoded;
@ -103,104 +113,152 @@ static ssize_t decode_address(patty_ax25_frame *frame,
* If the source address is not the final address in the frame, begin
* decoding repeater addresses.
*/
if (!PATTY_AX25_ADDRESS_OCTET_LAST(frame->src.ssid)) {
if ((decoded = decode_hops(frame, data, offset)) < 0) {
frame->hops = 0;
if (!PATTY_AX25_ADDR_OCTET_LAST(frame->src.ssid)) {
if ((decoded = decode_hops(frame, buf, offset, len)) < 0) {
goto error;
} else {
offset += decoded;
}
}
return offset - start;
return offset;
error:
return -1;
}
static ssize_t decode_info(patty_ax25_frame *frame,
void *data,
off_t offset,
size_t size) {
uint8_t control = ((uint8_t *)data + offset)[0];
size_t decoded = 0;
static inline uint8_t decode_nr(uint16_t control,
enum patty_ax25_frame_format format) {
switch (format) {
case PATTY_AX25_FRAME_NORMAL: return (control & 0x00e0) >> 5;
case PATTY_AX25_FRAME_EXTENDED: return (control & 0x7e00) >> 9;
}
int info = 0;
return 0;
}
if (PATTY_AX25_CONTROL_INFO(control)) {
info = 1;
} else if (PATTY_AX25_CONTROL_UNNUMBERED(control)) {
if (PATTY_AX25_CONTROL_UNNUMBERED_INFO(control)) {
info = 1;
static inline uint8_t decode_ns(uint16_t control,
enum patty_ax25_frame_format format) {
switch (format) {
case PATTY_AX25_FRAME_NORMAL: return (control & 0x000e) >> 1;
case PATTY_AX25_FRAME_EXTENDED: return (control & 0x007e) >> 1;
}
return 0;
}
static inline uint8_t decode_pf(uint16_t control,
enum patty_ax25_frame_format format) {
switch (format) {
case PATTY_AX25_FRAME_NORMAL: return (control & 0x0010) >> 4;
case PATTY_AX25_FRAME_EXTENDED: return (control & 0x0100) >> 8;
}
return 0;
}
ssize_t patty_ax25_frame_decode_control(patty_ax25_frame *frame,
enum patty_ax25_frame_format format,
void *data,
size_t offset,
size_t len) {
uint8_t *buf = data;
size_t start = offset;
frame->control = 0;
frame->nr = 0;
frame->ns = 0;
frame->pf = 0;
frame->type = PATTY_AX25_FRAME_UNKNOWN;
frame->proto = PATTY_AX25_PROTO_UNKNOWN;
frame->info = NULL;
frame->infolen = 0;
switch (format) {
case PATTY_AX25_FRAME_NORMAL:
frame->control = (uint16_t)(buf[offset++]);
break;
case PATTY_AX25_FRAME_EXTENDED:
frame->control = (uint16_t)(buf[offset++] << 8);
frame->control |= (uint16_t)(buf[offset++]);
if (PATTY_AX25_FRAME_CONTROL_U(frame->control)) {
errno = EIO;
goto error;
}
}
if (PATTY_AX25_FRAME_CONTROL_I(frame->control)) {
frame->type = PATTY_AX25_FRAME_I;
frame->nr = decode_nr(frame->control, format);
frame->ns = decode_ns(frame->control, format);
frame->pf = decode_pf(frame->control, format);
} else if (PATTY_AX25_FRAME_CONTROL_S(frame->control)) {
uint16_t c = frame->control & PATTY_AX25_FRAME_S_MASK;
switch (c) {
case PATTY_AX25_FRAME_RR:
case PATTY_AX25_FRAME_RNR:
case PATTY_AX25_FRAME_REJ:
case PATTY_AX25_FRAME_SREJ:
frame->type = c;
frame->nr = decode_nr(frame->control, format);
frame->pf = decode_pf(frame->control, format);
default:
break;
}
} else if (!PATTY_AX25_CONTROL_SUPER(control)) {
errno = EINVAL;
} else if (PATTY_AX25_FRAME_CONTROL_U(frame->control)) {
uint16_t c = frame->control & PATTY_AX25_FRAME_U_MASK;
switch (c) {
case PATTY_AX25_FRAME_SABME:
case PATTY_AX25_FRAME_SABM:
case PATTY_AX25_FRAME_DISC:
case PATTY_AX25_FRAME_DM:
case PATTY_AX25_FRAME_UA:
case PATTY_AX25_FRAME_FRMR:
case PATTY_AX25_FRAME_UI:
case PATTY_AX25_FRAME_XID:
case PATTY_AX25_FRAME_TEST:
frame->type = c;
frame->pf = decode_pf(frame->control, format);
default:
break;
}
} else {
errno = EIO;
goto error;
}
frame->control = control;
switch (frame->type) {
case PATTY_AX25_FRAME_I:
case PATTY_AX25_FRAME_UI:
frame->proto = buf[offset++];
frame->info = buf + offset;
frame->infolen = len - offset;
decoded++;
offset = len;
/*
* If we've received either an Info or Unnumbered Info frame, then decode
* the Protocol Identifier field, and calculate the location and size of
* the payload as well.
*/
if (info) {
decoded++;
frame->proto = ((uint8_t *)data + offset)[1];
frame->info = (void *)((uint8_t *)data + offset + decoded);
frame->infolen = size - offset - decoded;
decoded += frame->infolen;
default:
break;
}
return decoded;
errno = 0;
return offset - start;
error:
return -1;
}
ssize_t patty_ax25_frame_decode(patty_ax25_frame *frame,
enum patty_ax25_frame_format format,
void *buf,
size_t size) {
ssize_t decoded;
off_t offset = 0;
memset(frame, '\0', sizeof(*frame));
/*
* First, decode the variable-length Address field.
*/
if ((decoded = decode_address(frame, buf, offset)) < 0) {
errno = EIO;
goto error_decode;
} else {
offset += decoded;
}
/*
* Next, decode the remaining Control Field, optional Protocol Identifier
* field, and Info payload that may follow.
*/
if ((decoded = decode_info(frame, buf, offset, size)) < 0) {
errno = EIO;
goto error_decode;
} else {
offset += decoded;
}
return offset;
error_decode:
return -1;
}
static ssize_t encode_address(void *buf,
patty_ax25_addr *dest,
patty_ax25_addr *src,
@ -316,7 +374,7 @@ ssize_t patty_ax25_frame_encode(patty_ax25_frame *frame,
break;
}
if (PATTY_AX25_CONTROL_INFO(frame->control)) {
if (PATTY_AX25_FRAME_CONTROL_I(frame->control) || PATTY_AX25_FRAME_CONTROL_UI(frame->control)) {
if (1 + offset + frame->infolen > len) {
goto error_toobig;
}
@ -358,7 +416,7 @@ ssize_t patty_ax25_frame_encode_reply_to(patty_ax25_frame *frame,
break;
}
if (PATTY_AX25_CONTROL_INFO(reply->control)) {
if (PATTY_AX25_FRAME_CONTROL_I(reply->control)) {
if (len < 1 + offset + reply->infolen) {
goto error_toobig;
}
@ -377,25 +435,17 @@ error_toobig:
}
enum patty_ax25_version patty_ax25_frame_version(patty_ax25_frame *frame) {
return PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid) ==
PATTY_AX25_ADDRESS_SSID_C(frame->dest.ssid)?
return PATTY_AX25_ADDR_SSID_C(frame->src.ssid) ==
PATTY_AX25_ADDR_SSID_C(frame->dest.ssid)?
PATTY_AX25_2_0: PATTY_AX25_OLD;
}
enum patty_ax25_frame_type patty_ax25_frame_type(patty_ax25_frame *frame) {
if (PATTY_AX25_CONTROL_INFO(frame->control)) {
return PATTY_AX25_FRAME_INFO;
} else if (PATTY_AX25_CONTROL_SUPER(frame->control)) {
return PATTY_AX25_FRAME_SUPER;
} else if (PATTY_AX25_CONTROL_UNNUMBERED(frame->control)) {
return PATTY_AX25_FRAME_UNNUMBERED;
}
return PATTY_AX25_FRAME_UNKNOWN;
return frame->type;
}
enum patty_ax25_frame_cr patty_ax25_frame_cr(patty_ax25_frame *frame) {
return PATTY_AX25_ADDRESS_SSID_C(frame->src.ssid)?
return PATTY_AX25_ADDR_SSID_C(frame->src.ssid)?
PATTY_AX25_FRAME_RESPONSE:
PATTY_AX25_FRAME_COMMAND;
}

View file

@ -7,6 +7,30 @@
#define printable(c) \
(c >= 0x20 && c < 0x7f)
static char *frame_type_name(enum patty_ax25_frame_type type) {
switch (type) {
case PATTY_AX25_FRAME_I: return "I";
case PATTY_AX25_FRAME_RR: return "RR";
case PATTY_AX25_FRAME_RNR: return "RNR";
case PATTY_AX25_FRAME_REJ: return "REJ";
case PATTY_AX25_FRAME_SREJ: return "SREJ";
case PATTY_AX25_FRAME_SABM: return "SABM";
case PATTY_AX25_FRAME_SABME: return "SABME";
case PATTY_AX25_FRAME_DISC: return "DISC";
case PATTY_AX25_FRAME_DM: return "DM";
case PATTY_AX25_FRAME_UA: return "UA";
case PATTY_AX25_FRAME_FRMR: return "FRMR";
case PATTY_AX25_FRAME_UI: return "UI";
case PATTY_AX25_FRAME_XID: return "XID";
case PATTY_AX25_FRAME_TEST: return "TEST";
default:
break;
}
return "unknown";
}
int patty_print_hexdump(FILE *fh, void *data, size_t len) {
size_t i;
@ -103,26 +127,32 @@ int patty_print_frame(FILE *fh,
goto error_io;
}
if (PATTY_AX25_CONTROL_INFO(frame->control)) {
if (fprintf(fh, " type I poll %d ns %d nr %d info %zu bytes",
PATTY_AX25_CONTROL_POLL(frame->control),
PATTY_AX25_CONTROL_SEQ_SEND(frame->control),
PATTY_AX25_CONTROL_SEQ_RECV(frame->control),
if (PATTY_AX25_FRAME_CONTROL_I(frame->control)) {
if (fprintf(fh, " type I (%s) nr %d ns %d pf %d info %zu bytes",
frame_type_name(frame->type),
(int)frame->nr,
(int)frame->ns,
(int)frame->pf,
frame->infolen) < 0) {
goto error_io;
}
} else if (PATTY_AX25_CONTROL_UNNUMBERED(frame->control)) {
if (fprintf(fh, " type U") < 0) {
} else if (PATTY_AX25_FRAME_CONTROL_U(frame->control)) {
if (fprintf(fh, " type U (%s) pf %d",
frame_type_name(frame->type),
(int)frame->pf) < 0) {
goto error_io;
}
if (PATTY_AX25_CONTROL_UNNUMBERED_INFO(frame->control)) {
if (PATTY_AX25_FRAME_CONTROL_UI(frame->control)) {
if (fprintf(fh, " info %zu bytes", frame->infolen) < 0) {
goto error_io;
}
}
} else if (PATTY_AX25_CONTROL_SUPER(frame->control)) {
if (fprintf(fh, " type S") < 0) {
} else if (PATTY_AX25_FRAME_CONTROL_S(frame->control)) {
if (fprintf(fh, " type S (%s) nr %d pf %d",
frame_type_name(frame->type),
(int)frame->nr,
(int)frame->pf) < 0) {
goto error_io;
}
}

View file

@ -305,7 +305,7 @@ static int sock_delete_by_addrpair(patty_dict *dict,
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, 1) < 0) {
if (patty_ax25_sock_send_disc(sock, PATTY_AX25_FRAME_POLL) < 0) {
goto error_sock_send_disc;
}
@ -774,7 +774,7 @@ static int server_connect(patty_ax25_server *server,
* timeout has been exceeded or the peer has sent a UA frame to
* acknowledge and establish the connection.
*/
if (patty_ax25_sock_send_sabm(sock, 1) < 0) {
if (patty_ax25_sock_send_sabm(sock, PATTY_AX25_FRAME_POLL) < 0) {
response.ret = -1;
response.eno = EIO;
@ -992,8 +992,7 @@ static void save_reply_addr(patty_ax25_sock *sock,
static int reply_to(patty_ax25_if *iface,
patty_ax25_frame *frame,
patty_ax25_frame *reply,
enum patty_ax25_frame_format format) {
patty_ax25_frame *reply) {
ssize_t len;
if ((len = patty_ax25_frame_encode_reply_to(frame,
@ -1012,22 +1011,22 @@ error_toobig:
static int reply_dm(patty_ax25_if *iface,
patty_ax25_frame *frame,
enum patty_ax25_frame_flags flags) {
int flag) {
patty_ax25_frame reply = {
.control = PATTY_AX25_FRAME_U_DM | flags,
.control = PATTY_AX25_FRAME_DM | (flag << 4),
.proto = PATTY_AX25_PROTO_NONE,
.info = NULL,
.infolen = 0
};
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
return reply_to(iface, frame, &reply);
}
static int reply_ua(patty_ax25_if *iface,
patty_ax25_frame *frame,
enum patty_ax25_frame_flags flags) {
int flag) {
patty_ax25_frame reply = {
.control = PATTY_AX25_FRAME_U_UA | flags,
.control = PATTY_AX25_FRAME_UA | (flag << 4),
.proto = PATTY_AX25_PROTO_NONE,
.info = NULL,
.infolen = 0
@ -1038,33 +1037,20 @@ static int reply_ua(patty_ax25_if *iface,
patty_ax25_ntop(&frame->dest, callsign, &ssid, sizeof(callsign));
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
return reply_to(iface, frame, &reply);
}
static int reply_frmr(patty_ax25_if *iface,
patty_ax25_frame *frame,
enum patty_ax25_frame_flags flags) {
int flag) {
patty_ax25_frame reply = {
.control = PATTY_AX25_FRAME_U_FRMR | flags,
.control = PATTY_AX25_FRAME_FRMR | (flag << 4),
.proto = PATTY_AX25_PROTO_NONE,
.info = NULL,
.infolen = 0
};
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
}
static int reply_rej(patty_ax25_if *iface,
patty_ax25_frame *frame,
enum patty_ax25_frame_flags flags) {
patty_ax25_frame reply = {
.control = PATTY_AX25_FRAME_U_FRMR | flags,
.proto = PATTY_AX25_PROTO_NONE,
.info = NULL,
.infolen = 0
};
return reply_to(iface, frame, &reply, PATTY_AX25_FRAME_NORMAL);
return reply_to(iface, frame, &reply);
}
static int handle_sabm(patty_ax25_server *server,
@ -1240,18 +1226,11 @@ error_client_by_sock:
return -1;
}
static int handle_info(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_frame *frame) {
patty_ax25_sock *sock;
if ((sock = sock_by_addrpair(server->socks_established,
&frame->dest,
&frame->src)) == NULL) {
/*
* TODO: Figure out how to respond to a packet sent outside of an
* active session
*/
static int handle_i(patty_ax25_server *server,
patty_ax25_if *iface,
patty_ax25_sock *sock,
patty_ax25_frame *frame) {
if (sock == NULL) {
return 0;
}
@ -1266,10 +1245,10 @@ static int handle_info(patty_ax25_server *server,
/*
* TODO: Validate RX and TX sequence numbers
*/
if (sock->seq_recv == PATTY_AX25_CONTROL_SEQ_SEND(frame->control)) {
if (sock->seq_recv == frame->ns) {
patty_ax25_sock_seq_recv_incr(sock);
} else {
return reply_rej(iface, frame, PATTY_AX25_FRAME_FINAL);
return patty_ax25_sock_send_rej(sock);
}
return write(sock->fd, frame->info, frame->infolen);
@ -1301,29 +1280,44 @@ static int handle_frame(patty_ax25_server *server,
void *buf,
size_t len) {
patty_ax25_frame frame;
enum patty_ax25_frame_format format = PATTY_AX25_FRAME_NORMAL;
if (patty_ax25_frame_decode(&frame,
PATTY_AX25_FRAME_NORMAL,
buf,
len) < 0) {
ssize_t decoded;
patty_ax25_sock *sock;
if ((decoded = patty_ax25_frame_decode_address(&frame, buf, len)) < 0) {
iface->stats.dropped++;
goto error_io;
}
if (PATTY_AX25_CONTROL_UNNUMBERED_SABM(frame.control)) {
return handle_sabm(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_UNNUMBERED_UA(frame.control)) {
return handle_ua(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_UNNUMBERED_DM(frame.control)) {
return handle_dm(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_INFO(frame.control)) {
return handle_info(server, iface, &frame);
} else if (PATTY_AX25_CONTROL_UNNUMBERED_DISC(frame.control)) {
return handle_disc(server, iface, &frame);
if ((sock = sock_by_addrpair(server->socks_established,
&frame.dest,
&frame.src)) != NULL) {
if (sock->mode == PATTY_AX25_SOCK_SABME) {
format = PATTY_AX25_FRAME_EXTENDED;
}
}
return 0;
if (patty_ax25_frame_decode_control(&frame, format, buf, decoded, len) < 0) {
iface->stats.dropped++;
goto error_io;
}
switch (frame.type) {
case PATTY_AX25_FRAME_I: return handle_i(server, iface, sock, &frame);
case PATTY_AX25_FRAME_SABM: return handle_sabm(server, iface, &frame);
case PATTY_AX25_FRAME_UA: return handle_ua(server, iface, &frame);
case PATTY_AX25_FRAME_DM: return handle_dm(server, iface, &frame);
case PATTY_AX25_FRAME_DISC: return handle_disc(server, iface, &frame);
case PATTY_AX25_FRAME_FRMR: return 0;
default:
break;
}
return reply_frmr(iface, &frame, PATTY_AX25_FRAME_FINAL);
error_io:
return -1;

View file

@ -228,26 +228,93 @@ error_toobig:
return -1;
}
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int poll) {
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,
int flag) {
return (type & PATTY_AX25_FRAME_U_MASK)
| (flag << 4);
}
ssize_t patty_ax25_sock_send_rr(patty_ax25_sock *sock) {
return patty_ax25_sock_send(sock,
PATTY_AX25_FRAME_U_SABM
| PATTY_AX25_FRAME_POLL,
control_s(sock, PATTY_AX25_FRAME_RR, 1),
NULL,
0);
}
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int poll) {
ssize_t patty_ax25_sock_send_rnr(patty_ax25_sock *sock) {
return patty_ax25_sock_send(sock,
PATTY_AX25_FRAME_U_SABME
| PATTY_AX25_FRAME_POLL,
control_s(sock, PATTY_AX25_FRAME_RNR, 1),
NULL,
0);
}
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int poll) {
ssize_t patty_ax25_sock_send_rej(patty_ax25_sock *sock) {
return patty_ax25_sock_send(sock,
PATTY_AX25_FRAME_U_DISC
| PATTY_AX25_FRAME_POLL,
control_s(sock, PATTY_AX25_FRAME_REJ, 1),
NULL,
0);
}
ssize_t patty_ax25_sock_send_srej(patty_ax25_sock *sock) {
return patty_ax25_sock_send(sock,
control_s(sock, PATTY_AX25_FRAME_SREJ, 1),
NULL,
0);
}
ssize_t patty_ax25_sock_send_sabm(patty_ax25_sock *sock, int flag) {
return patty_ax25_sock_send(sock,
control_u(PATTY_AX25_FRAME_SABM, flag),
NULL,
0);
}
ssize_t patty_ax25_sock_send_sabme(patty_ax25_sock *sock, int flag) {
return patty_ax25_sock_send(sock,
control_u(PATTY_AX25_FRAME_SABME, flag),
NULL,
0);
}
ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int flag) {
return patty_ax25_sock_send(sock,
control_u(PATTY_AX25_FRAME_DISC, flag),
NULL,
0);
}
@ -255,17 +322,19 @@ ssize_t patty_ax25_sock_send_disc(patty_ax25_sock *sock, int poll) {
ssize_t patty_ax25_sock_write(patty_ax25_sock *sock,
void *buf,
size_t len) {
uint16_t control = 0x0000;
uint16_t control;
if (sock->type == PATTY_AX25_SOCK_RAW) {
return patty_ax25_if_send(sock->iface, buf, len);
} else if (sock->mode == PATTY_AX25_SOCK_DM) {
}
if (sock->mode == PATTY_AX25_SOCK_DM) {
errno = EBADF;
goto error_invalid_mode;
}
control = PATTY_AX25_SOCK_CONTROL(sock, 0);
control = control_i(sock, 0);
if (patty_ax25_sock_send(sock, control, buf, len) < 0) {
goto error_send;