patty/src/ax25.c

148 lines
3.4 KiB
C
Raw Normal View History

#include <string.h>
#include <errno.h>
#include <patty/ax25.h>
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; i<PATTY_AX25_MAX_HOPS; i++) {
if ((decoded = frame_decode_address(&frame->repeaters[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;
}