From a4518a839a69e6d35b59935d165d8e7ce486bd69 Mon Sep 17 00:00:00 2001 From: XANTRONIX Development Date: Fri, 10 Jul 2020 00:01:50 -0400 Subject: [PATCH] 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 --- examples/ax25dump.c | 17 ++- examples/decode.c | 19 ++- include/patty/ax25.h | 44 +++++- include/patty/ax25/frame.h | 90 ++++++++----- include/patty/ax25/macros.h | 103 -------------- include/patty/ax25/proto.h | 29 ---- include/patty/ax25/sock.h | 25 ++-- src/Makefile | 5 +- src/ax25.c | 8 +- src/frame.c | 260 +++++++++++++++++++++--------------- src/print.c | 50 +++++-- src/server.c | 104 +++++++-------- src/sock.c | 93 +++++++++++-- 13 files changed, 466 insertions(+), 381 deletions(-) delete mode 100644 include/patty/ax25/macros.h delete mode 100644 include/patty/ax25/proto.h diff --git a/examples/ax25dump.c b/examples/ax25dump.c index e762de6..4ba1a04 100644 --- a/examples/ax25dump.c +++ b/examples/ax25dump.c @@ -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: diff --git a/examples/decode.c b/examples/decode.c index 8fce493..ab355bb 100644 --- a/examples/decode.c +++ b/examples/decode.c @@ -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); diff --git a/include/patty/ax25.h b/include/patty/ax25.h index 25db698..05a1bb5 100644 --- a/include/patty/ax25.h +++ b/include/patty/ax25.h @@ -8,11 +8,36 @@ #include #include -#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 -#include #include #include #include @@ -34,6 +57,21 @@ typedef struct _patty_ax25_if patty_ax25_if; #include #include +#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); diff --git a/include/patty/ax25/frame.h b/include/patty/ax25/frame.h index 0311a19..e388414 100644 --- a/include/patty/ax25/frame.h +++ b/include/patty/ax25/frame.h @@ -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, diff --git a/include/patty/ax25/macros.h b/include/patty/ax25/macros.h deleted file mode 100644 index 724baab..0000000 --- a/include/patty/ax25/macros.h +++ /dev/null @@ -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 */ diff --git a/include/patty/ax25/proto.h b/include/patty/ax25/proto.h deleted file mode 100644 index 58c1b4b..0000000 --- a/include/patty/ax25/proto.h +++ /dev/null @@ -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 */ diff --git a/include/patty/ax25/sock.h b/include/patty/ax25/sock.h index 94d49a4..7ecb32e 100644 --- a/include/patty/ax25/sock.h +++ b/include/patty/ax25/sock.h @@ -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, diff --git a/src/Makefile b/src/Makefile index a0e17d2..f7c693a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 diff --git a/src/ax25.c b/src/ax25.c index 0dc1129..ff60609 100644 --- a/src/ax25.c +++ b/src/ax25.c @@ -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)); } diff --git a/src/frame.c b/src/frame.c index 2fd2b72..4491405 100644 --- a/src/frame.c +++ b/src/frame.c @@ -1,19 +1,27 @@ #include +#include #include #include 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> 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; irepeaters[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; } diff --git a/src/print.c b/src/print.c index d3d849c..5c56cc8 100644 --- a/src/print.c +++ b/src/print.c @@ -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; } } diff --git a/src/server.c b/src/server.c index 520afac..0838f47 100644 --- a/src/server.c +++ b/src/server.c @@ -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; diff --git a/src/sock.c b/src/sock.c index 16b4858..93b6789 100644 --- a/src/sock.c +++ b/src/sock.c @@ -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;