diff --git a/include/patty/ax25.h b/include/patty/ax25.h index aa74e4c..929f721 100644 --- a/include/patty/ax25.h +++ b/include/patty/ax25.h @@ -1,6 +1,13 @@ #ifndef _PATTY_AX25_H #define _PATTY_AX25_H +#include +#include + +#include + +#define PATTY_AX25_MAX_HOPS 8 + enum patty_ax25_proto { PATTY_AX25_PROTO_ISO_8208 = 0x01, PATTY_AX25_PROTO_TCP_VJ_COMPR = 0x06, @@ -18,120 +25,16 @@ enum patty_ax25_proto { PATTY_AX25_PROTO_ESCAPE = 0xff }; -typedef struct _patty_ax25_address { - char callsign[6]; - unsigned int extension :1; - unsigned int ssid :4; - unsigned int reserved :2; - unsigned int repeated :1; -} patty_ax25_address; +enum patty_ax25_frame_type { + PATTY_AX25_FRAME_INFO, + PATTY_AX25_FRAME_SUPER, + PATTY_AX25_FRAME_UNNUMBERED +}; -#define PATTY_AX25_CONTROL_INFO(c) \ - ((c & 0x01) == 0) +typedef struct _patty_ax25_address patty_ax25_address; -#define PATTY_AX25_CONTROL_INFO_RESET(c) \ - (c = 0x00) +typedef struct _patty_ax25_frame patty_ax25_frame; -#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_SABM(c) \ - (((c & 0xe0) == 0x10) && ((c & 0x0f) == 0x0f)) - -#define PATTY_AX25_CONTROL_UNNUMBERED_DISC(c) \ - (((c & 0xe0) == 0x20) && ((c & 0x0f) == 0x03)) - -#define PATTY_AX25_CONTROL_UNNUMBERED_DM(c) \ - (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x0f)) - -#define PATTY_AX25_CONTROL_UNNUMBERED_UA(c) \ - (((c & 0xe0) == 0x30) && ((c & 0x0f) == 0x03)) - -#define PATTY_AX25_CONTROL_UNNUMBERED_FRMR(c) \ - (((c & 0xe0) == 0x40) && ((c & 0x0f) == 0x07)) - -#define PATTY_AX25_CONTROL_UNNUMBERED_UI(c) \ - (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x02)) - -#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]) - -typedef struct _patty_ax25_control_info { - unsigned int control :1; - unsigned int seq_send :3; - unsigned int poll :1; - unsigned int seq_recv :3; -} patty_ax25_control_info; - -typedef struct _patty_ax25_control_super { - unsigned int control :2; - unsigned int function :2; - unsigned int poll :1; - unsigned int seq_recv :3; -} patty_ax25_control_super; - -typedef struct _patty_ax25_control_unnumbered { - unsigned int control :2; - unsigned int modifier :2; - unsigned int poll :1; - unsigned int modifier2 :3; -} patty_ax25_control_unnumbered; - -typedef struct _patty_ax25_packet { - patty_ax25_address dest; - patty_ax25_address src; - patty_ax25_address hops[8]; -} patty_ax25_packet; +int patty_ax25_frame_decode(patty_ax25_frame *frame, void *data, size_t len); #endif /* _PATTY_AX25_H */ diff --git a/include/patty/ax25/macros.h b/include/patty/ax25/macros.h new file mode 100644 index 0000000..9cf75dd --- /dev/null +++ b/include/patty/ax25/macros.h @@ -0,0 +1,97 @@ +#ifndef _PATTY_AX25_MACROS_H +#define _PATTY_AX25_MACROS_H + +#define PATTY_AX25_ADDRESS_OCTET_VALID(c) \ + ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c == ' ')) + +#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_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_SABM(c) \ + (((c & 0xe0) == 0x10) && ((c & 0x0f) == 0x0f)) + +#define PATTY_AX25_CONTROL_UNNUMBERED_DISC(c) \ + (((c & 0xe0) == 0x20) && ((c & 0x0f) == 0x03)) + +#define PATTY_AX25_CONTROL_UNNUMBERED_DM(c) \ + (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x0f)) + +#define PATTY_AX25_CONTROL_UNNUMBERED_UA(c) \ + (((c & 0xe0) == 0x30) && ((c & 0x0f) == 0x03)) + +#define PATTY_AX25_CONTROL_UNNUMBERED_FRMR(c) \ + (((c & 0xe0) == 0x40) && ((c & 0x0f) == 0x07)) + +#define PATTY_AX25_CONTROL_UNNUMBERED_UI(c) \ + (((c & 0xe0) == 0x00) && ((c & 0x0f) == 0x02)) + +#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/src/Makefile b/src/Makefile index 3603db3..1c9c224 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,7 +8,7 @@ CFLAGS = $(CGFLAGS) -fPIC -Wall -O2 -I$(INCLUDE_PATH) LDFLAGS = HEADERS = kiss.h ax25.h -OBJS = kiss.o test.o +OBJS = kiss.o ax25.o test.o PROGRAM = test diff --git a/src/ax25.c b/src/ax25.c new file mode 100644 index 0000000..fc2791e --- /dev/null +++ b/src/ax25.c @@ -0,0 +1,147 @@ +#include +#include + +#include + +struct _patty_ax25_address { + char callsign[7]; + + int ssid; + int last; + int repeated; +}; + +struct _patty_ax25_frame { + struct _patty_ax25_address dest; + struct _patty_ax25_address src; + struct _patty_ax25_address repeaters[8]; + + int hops; + int repeated; + + enum patty_ax25_frame_type type; + enum patty_ax25_proto proto; + + uint8_t control; + uint8_t pid; + void * info; + uint16_t fcs; +}; + +static ssize_t frame_decode_address(patty_ax25_address *address, void *data, off_t offset) { + int i, space = 0; + uint8_t *info = (uint8_t *)data; + + /* + * First, unpack each callsign octet, ensuring all are within the 7 bit + * ASCII space and do not have the extended bit set to 1. + */ + for (i=0; i<6; i++) { + uint8_t c = (((uint8_t *)data) + offset)[i]; + + if (!PATTY_AX25_ADDRESS_OCTET_VALID(c) || !PATTY_AX25_ADDRESS_OCTET_LAST(c)) { + errno = EINVAL; + + goto error; + } + + if (c == ' ') { + /* + * Take note if we have reached the end of the call sign. + */ + if (space == 0) { + space = 1; + } + + address->callsign[i] = '\0'; + } else { + /* + * If we have already reached the end of the callsign, and a + * non-space character is encountered, then the address is + * erroneous. + */ + if (space) { + errno = EINVAL; + + goto error; + } + + address->callsign[i] = c >> 1; + } + } + + /* + * Now, unpack the data from the SSID field. + */ + address->repeated = PATTY_AX25_ADDRESS_SSID_REPEATED(info[7]); + address->ssid = PATTY_AX25_ADDRESS_SSID_NUMBER(info[7]); + address->last = PATTY_AX25_ADDRESS_OCTET_LAST(info[7]); + + return 7; + +error: + return -1; +} + +int patty_ax25_frame_decode(patty_ax25_frame *frame, void *data, size_t len) { + ssize_t decoded; + off_t offset = 0; + + memset(frame, '\0', sizeof(*frame)); + + if ((decoded = frame_decode_address(&frame->dest, data, offset)) < 0) { + goto error_decode_dest; + } else { + offset += decoded; + } + + /* + * It would be considered erroneous if the destination address did have the + * extension bit set to 1. + */ + + if ((decoded = frame_decode_address(&frame->src, data, offset)) < 0) { + goto error_decode_src; + } else { + offset += decoded; + } + + /* + * Now, if the source address is not the final address in the frame, then + * begin decoding repeater addresses. + */ + if (!frame->src.last) { + int i; + + for (i=0; irepeaters[i], data, offset)) < 0) { + goto error_decode_repeater; + } + + frame->hops++; + + if (frame->repeaters[i].last) { + frame->repeated = frame->repeaters[i].repeated; + + break; + } + } + + /* + * If the last hop does not have the address extension bit set, then + * that's a big problem. + */ + if (frame->hops && !frame->repeaters[i-1].last) { + errno = EINVAL; + + goto error_decode_repeater; + } + } + + return 0; + +error_decode_repeater: +error_decode_src: +error_decode_dest: + return -1; +} diff --git a/src/kiss.c b/src/kiss.c index c760b52..d922a9f 100644 --- a/src/kiss.c +++ b/src/kiss.c @@ -111,6 +111,15 @@ static ssize_t tnc_decode(patty_kiss_tnc *tnc, void *frame, size_t *len, int *po for (i=0, b=0; ibuflen; i++) { unsigned char c = ((unsigned char *)tnc->buf)[i]; + /* + * If the first byte is not a frame end, then that's a bad thing. + */ + if (i == 0 && c != PATTY_KISS_FEND) { + errno = EIO; + + goto error_io; + } + /* * Not all KISS TNCs will emit a type byte at the start of a frame * to the host; if the low nybble has a value of zero, then presume