148 lines
3.4 KiB
C
148 lines
3.4 KiB
C
|
#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;
|
||
|
}
|