patty/src/ax25.c

198 lines
3.9 KiB
C
Raw Normal View History

2015-07-20 23:21:45 -05:00
#include <stdlib.h>
2015-07-20 22:33:59 -05:00
#include <string.h>
2015-07-20 23:21:45 -05:00
#include <errno.h>
#include <sys/select.h>
2015-07-20 22:33:59 -05:00
#include <patty/ax25.h>
enum addr_state {
ADDR_NONE,
ADDR_CALLSIGN,
ADDR_SSID
};
2020-06-07 02:46:12 -04:00
int patty_ax25_pton(const char *callsign,
patty_ax25_addr *addr) {
size_t len = strlen(callsign),
max = PATTY_AX25_CALLSIGN_LEN + 3; /* Account for SSID suffixes */
2020-06-07 02:46:12 -04:00
int i,
o = 0,
digits = 0;
2020-06-07 02:46:12 -04:00
int ssid = 0;
2020-06-07 02:46:12 -04:00
enum addr_state state = ADDR_NONE;
2020-06-07 02:46:12 -04:00
if (len == 0) {
goto error_invalid_callsign;
} else if (len > max) {
len = max;
}
2020-06-07 02:46:12 -04:00
for (i=0; i<len; i++) {
uint8_t c = callsign[i];
switch (state) {
case ADDR_NONE:
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')) {
state = ADDR_CALLSIGN;
addr->callsign[o++] = (c & 0x7f) << 1;
} else {
goto error_invalid_callsign;
}
break;
case ADDR_CALLSIGN:
if (o > PATTY_AX25_CALLSIGN_LEN) {
goto error_invalid_callsign;
}
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')) {
addr->callsign[o++] = (c & 0x7f) << 1;
} else if (c == '-') {
state = ADDR_SSID;
} else {
goto error_invalid_callsign;
}
break;
case ADDR_SSID:
if (digits >= 2) {
goto error_invalid_callsign;
}
if (c >= '0' && c <= '9') {
ssid *= 10;
ssid += c - '0';
digits++;
} else {
goto error_invalid_callsign;
}
2020-06-07 02:46:12 -04:00
}
}
2020-06-07 02:46:12 -04:00
while (o < PATTY_AX25_CALLSIGN_LEN) {
addr->callsign[o++] = ' ' << 1;
2020-06-07 02:46:12 -04:00
}
addr->ssid = (ssid & 0x0f) << 1;
return 0;
error_invalid_callsign:
errno = EINVAL;
2020-06-07 02:46:12 -04:00
return -1;
}
static inline int expt(int base, int e) {
int ret;
if (e == 0) {
return 1;
}
ret = base;
while (--e) {
ret *= ret;
}
return ret;
}
2020-06-07 02:46:12 -04:00
int patty_ax25_ntop(const patty_ax25_addr *addr,
char *dest,
size_t len) {
int i,
o = 0;
2020-06-07 02:46:12 -04:00
int ssid = (addr->ssid & 0x1e) >> 1;
2020-06-07 02:46:12 -04:00
for (i=0; i<PATTY_AX25_CALLSIGN_LEN; i++) {
2020-06-07 02:46:12 -04:00
uint8_t c;
if (o == len) {
goto error_overflow;
}
c = (addr->callsign[i] & 0xfe) >> 1;
if (c == ' ') {
2020-06-07 02:46:12 -04:00
break;
}
dest[o++] = c;
}
if (ssid) {
int place = 2;
2020-06-07 02:46:12 -04:00
if (o == len) {
goto error_overflow;
2020-06-07 02:46:12 -04:00
}
dest[o++] = '-';
2020-06-07 02:46:12 -04:00
while (place--) {
int div = expt(10, place),
num = ssid / div;
2020-06-07 02:46:12 -04:00
if (num) {
if (o == len) {
goto error_overflow;
}
2020-06-07 02:46:12 -04:00
dest[o++] = '0' + num;
}
2020-06-07 02:46:12 -04:00
}
}
2020-06-07 02:46:12 -04:00
if (o == len) {
goto error_overflow;
2020-06-07 02:46:12 -04:00
}
dest[o] = '\0';
return 0;
error_overflow:
errno = EOVERFLOW;
2020-06-07 02:46:12 -04:00
return -1;
}
2020-06-25 20:37:12 -04:00
static inline void hash_byte(uint32_t *hash, uint8_t c) {
*hash += c;
*hash += (*hash << 10);
*hash ^= (*hash >> 6);
}
void patty_ax25_addr_hash(uint32_t *hash, const patty_ax25_addr *addr) {
size_t i;
for (i=0; i<PATTY_AX25_CALLSIGN_LEN; i++) {
hash_byte(hash, addr->callsign[i] >> 1);
}
hash_byte(hash, PATTY_AX25_ADDR_SSID_NUMBER(addr->ssid));
2020-06-25 20:37:12 -04:00
}
size_t patty_ax25_addr_copy(void *buf,
patty_ax25_addr *addr,
uint8_t ssid_flags) {
size_t encoded = 0;
memcpy(buf, addr->callsign, sizeof(addr->callsign));
encoded += sizeof(addr->callsign);
((uint8_t *)buf)[encoded++] = ssid_flags | 0x60 | (addr->ssid & 0x1e);
return encoded;
}