patty/src/ax25.c

225 lines
5.2 KiB
C
Raw Normal View History

#include <string.h>
#include <errno.h>
#include <patty/ax25.h>
2015-07-18 02:22:25 -05:00
static ssize_t frame_decode_station(patty_ax25_address *address, void *data, off_t offset) {
int i, space = 0;
uint8_t ssid = ((uint8_t *)data + offset)[6];
/*
* 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 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;
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;
}
}
/*
* Now, unpack the data from the SSID field.
*/
address->c = PATTY_AX25_ADDRESS_SSID_C(ssid);
address->ssid = PATTY_AX25_ADDRESS_SSID_NUMBER(ssid);
address->last = PATTY_AX25_ADDRESS_OCTET_LAST(ssid);
return 7;
error:
return -1;
}
static ssize_t frame_decode_hops(patty_ax25_frame *frame, void *data, off_t start) {
ssize_t decoded;
off_t offset = start;
int i;
/*
* Try to decode the AX.25-specified maximum number of hops in the current
* frame.
*/
for (i=0; i<PATTY_AX25_MAX_HOPS; i++) {
2015-07-18 02:22:25 -05:00
if ((decoded = frame_decode_station(&frame->repeaters[i], data, offset)) < 0) {
goto error;
} else {
offset += decoded;
}
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[frame->hops-1].last) {
errno = EINVAL;
goto error;
}
return offset - start;
error:
return -1;
}
2015-07-18 02:22:25 -05:00
static ssize_t frame_decode_address(patty_ax25_frame *frame, void *data, off_t start) {
off_t offset = start;
ssize_t decoded;
if ((decoded = frame_decode_station(&frame->dest, data, offset)) < 0) {
goto error;
} else {
offset += decoded;
}
/*
* It would be considered erroneous if the destination address did have the
* extension bit set to 1.
*/
if ((decoded = frame_decode_station(&frame->src, data, offset)) < 0) {
goto error;
} else {
offset += decoded;
}
/*
* If the source address is not the final address in the frame, begin
* decoding repeater addresses.
*/
if (!frame->src.last) {
if ((decoded = frame_decode_hops(frame, data, offset)) < 0) {
goto error;
} else {
offset += decoded;
}
}
return offset - start;
error:
return -1;
}
2015-07-17 20:21:00 -05:00
static ssize_t frame_decode_payload(patty_ax25_frame *frame, void *data, off_t offset) {
uint8_t control = ((uint8_t *)data + offset)[0];
size_t decoded = 0;
int info = 0;
frame->control = control;
decoded++;
if (PATTY_AX25_CONTROL_INFO(control)) {
frame->type = PATTY_AX25_FRAME_INFO;
info = 1;
} else if (PATTY_AX25_CONTROL_SUPER(control)) {
frame->type = PATTY_AX25_FRAME_SUPER;
} else if (PATTY_AX25_CONTROL_UNNUMBERED(control)) {
frame->type = PATTY_AX25_FRAME_UNNUMBERED;
if (PATTY_AX25_CONTROL_UNNUMBERED_INFO(control)) {
info = 1;
}
} else {
frame->type = PATTY_AX25_FRAME_UNKNOWN;
errno = EINVAL;
goto error;
}
/*
* 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->payload = (void *)((uint8_t *)data + offset + decoded);
frame->payloadsz = frame->size - offset - decoded;
decoded += frame->payloadsz;
}
return decoded;
error:
return -1;
}
int patty_ax25_frame_decode(patty_ax25_frame *frame, void *data, size_t size) {
ssize_t decoded;
off_t offset = 0;
memset(frame, '\0', sizeof(*frame));
frame->size = size;
/*
2015-07-18 02:22:25 -05:00
* First, decode the variable-length Address field.
*/
2015-07-18 02:22:25 -05:00
if ((decoded = frame_decode_address(frame, data, offset)) < 0) {
goto error_decode;
} else {
offset += decoded;
}
/*
2015-07-17 20:21:00 -05:00
* Now, decode the remaining Control Field, optional Protocol Identifier
* field, and payload that may follow.
*/
2015-07-17 20:21:00 -05:00
if ((decoded = frame_decode_payload(frame, data, offset)) < 0) {
goto error_decode;
} else {
offset += decoded;
}
return offset;
error_decode:
return -1;
}