299 lines
6.2 KiB
C
299 lines
6.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <patty/ax25.h>
|
|
|
|
static patty_ax25_if *create_tnc(const char *device) {
|
|
patty_ax25_if *iface;
|
|
|
|
static char * prefix = "kiss";
|
|
static int number = 0;
|
|
|
|
if ((iface = malloc(sizeof(*iface))) == NULL) {
|
|
goto error_malloc_iface;
|
|
}
|
|
|
|
memset(iface, '\0', sizeof(*iface));
|
|
|
|
if ((iface->tnc = patty_kiss_tnc_open(device, PATTY_KISS_BUFSZ)) == NULL) {
|
|
goto error_kiss_tnc_open;
|
|
}
|
|
|
|
iface->type = PATTY_AX25_IF_KISS_TNC_TTY;
|
|
|
|
snprintf(iface->name, sizeof(iface->name), "%s%d", prefix, number++);
|
|
|
|
return iface;
|
|
|
|
error_kiss_tnc_open:
|
|
free(iface);
|
|
|
|
error_malloc_iface:
|
|
return NULL;
|
|
}
|
|
|
|
static void destroy_tnc(patty_ax25_if *iface) {
|
|
patty_kiss_tnc_close(iface->tnc);
|
|
}
|
|
|
|
patty_ax25_if *patty_ax25_if_create(int opts, void *info) {
|
|
patty_ax25_if *iface;
|
|
|
|
switch (PATTY_AX25_IF_OPT_TYPE(opts)) {
|
|
case PATTY_AX25_IF_KISS_TNC_TTY: {
|
|
iface = create_tnc((const char *)info);
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
errno = EINVAL;
|
|
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
if (iface == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
if ((iface->addresses = patty_list_new()) == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
return iface;
|
|
|
|
error:
|
|
return NULL;
|
|
}
|
|
|
|
void patty_ax25_if_destroy(patty_ax25_if *iface) {
|
|
switch (iface->type) {
|
|
case PATTY_AX25_IF_KISS_TNC_TTY: {
|
|
destroy_tnc(iface); break;
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
int patty_ax25_if_each_address(patty_ax25_if *iface, int (*callback)(patty_ax25_address *, void *), void *ctx) {
|
|
patty_list_iterator *iter;
|
|
patty_ax25_address *address;
|
|
|
|
if ((iter = patty_list_start(iface->addresses)) == NULL) {
|
|
goto error_list_start;
|
|
}
|
|
|
|
while ((address = patty_list_next(iter)) != NULL) {
|
|
if (callback(address, ctx) < 0) {
|
|
goto error_callback;
|
|
}
|
|
}
|
|
|
|
patty_list_finish(iter);
|
|
|
|
return 0;
|
|
|
|
error_callback:
|
|
patty_list_finish(iter);
|
|
|
|
error_list_start:
|
|
return -1;
|
|
}
|
|
|
|
static patty_ax25_address *find_address(patty_ax25_if *iface, const char *callsign, int ssid) {
|
|
patty_list_iterator *iter;
|
|
patty_ax25_address *address;
|
|
|
|
if ((iter = patty_list_start(iface->addresses)) == NULL) {
|
|
goto error_list_start;
|
|
}
|
|
|
|
while ((address = patty_list_next(iter)) != NULL) {
|
|
if (strncmp(address->callsign, callsign, sizeof(address->callsign)) != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (address->ssid != ssid) {
|
|
continue;
|
|
}
|
|
|
|
patty_list_finish(iter);
|
|
|
|
return address;
|
|
}
|
|
|
|
patty_list_finish(iter);
|
|
|
|
error_list_start:
|
|
return NULL;
|
|
}
|
|
|
|
int patty_ax25_if_add_address(patty_ax25_if *iface, const char *callsign, int ssid) {
|
|
patty_ax25_address *address;
|
|
|
|
if (find_address(iface, callsign, ssid) != NULL) {
|
|
errno = EEXIST;
|
|
|
|
goto error_exists;
|
|
}
|
|
|
|
if ((address = malloc(sizeof(*address))) == NULL) {
|
|
goto error_malloc_address;
|
|
}
|
|
|
|
memset(address, '\0', sizeof(*address));
|
|
|
|
strncpy(address->callsign, callsign, sizeof(address->callsign));
|
|
|
|
address->ssid = ssid;
|
|
|
|
if ((patty_list_append(iface->addresses, address)) == NULL) {
|
|
goto error_list_append;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_list_append:
|
|
free(address);
|
|
|
|
error_malloc_address:
|
|
error_exists:
|
|
return -1;
|
|
}
|
|
|
|
int patty_ax25_if_delete_address(patty_ax25_if *iface, const char *callsign, int ssid) {
|
|
patty_list_item *item = iface->addresses->first;
|
|
int i = 0;
|
|
|
|
while (item) {
|
|
patty_ax25_address *address = item->value;
|
|
|
|
if (strncmp(address->callsign, callsign, sizeof(address->callsign)) == 0 && address->ssid == ssid) {
|
|
if (patty_list_splice(iface->addresses, i) == NULL) {
|
|
goto error_list_splice;
|
|
}
|
|
}
|
|
|
|
item = item->next;
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_list_splice:
|
|
return -1;
|
|
}
|
|
|
|
patty_ax25_if *patty_ax25_get_if(patty_ax25 *ax25, const char *name) {
|
|
patty_list_iterator *iter;
|
|
patty_ax25_if *iface;
|
|
|
|
if ((iter = patty_list_start(ax25->ifaces)) == NULL) {
|
|
goto error_list_start;
|
|
}
|
|
|
|
while ((iface = patty_list_next(iter)) != NULL) {
|
|
if (strncmp(iface->name, name, sizeof(iface->name)) == 0) {
|
|
patty_list_finish(iter);
|
|
|
|
return iface;
|
|
}
|
|
}
|
|
|
|
patty_list_finish(iter);
|
|
|
|
error_list_start:
|
|
return NULL;
|
|
}
|
|
|
|
int patty_ax25_each_if(patty_ax25 *ax25, int (*callback)(patty_ax25_if *, void *), void *ctx) {
|
|
patty_list_iterator *iter;
|
|
patty_ax25_if *iface;
|
|
|
|
if ((iter = patty_list_start(ax25->ifaces)) == NULL) {
|
|
goto error_list_start;
|
|
}
|
|
|
|
while ((iface = patty_list_next(iter)) != NULL) {
|
|
if (callback(iface, ctx) < 0) {
|
|
goto error_callback;
|
|
}
|
|
}
|
|
|
|
patty_list_finish(iter);
|
|
|
|
return 0;
|
|
|
|
error_callback:
|
|
patty_list_finish(iter);
|
|
|
|
error_list_start:
|
|
return -1;
|
|
}
|
|
|
|
int patty_ax25_add_if(patty_ax25 *ax25, patty_ax25_if *iface) {
|
|
int fd;
|
|
|
|
if ((fd = patty_kiss_tnc_fd_unix(iface->tnc)) >= 0) {
|
|
FD_SET(fd, &ax25->unix_fds);
|
|
|
|
if (ax25->unix_fdmax < fd + 1) {
|
|
ax25->unix_fdmax = fd + 1;
|
|
}
|
|
}
|
|
|
|
if (patty_dict_set(ax25->unix_fd_lookup, &fd, sizeof(fd), iface) == NULL) {
|
|
goto error_dict_set;
|
|
}
|
|
|
|
if (patty_list_append(ax25->ifaces, iface) == NULL) {
|
|
goto error_list_append;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_list_append:
|
|
error_dict_set:
|
|
return -1;
|
|
}
|
|
|
|
int patty_ax25_delete_if(patty_ax25 *ax25, patty_ax25_if *iface) {
|
|
patty_list_item *item = ax25->ifaces->first;
|
|
|
|
int fd, i = 0;
|
|
|
|
while (item) {
|
|
if (item->value == iface) {
|
|
if (patty_list_splice(ax25->ifaces, i) == NULL) {
|
|
goto error_list_splice;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
item = item->next;
|
|
i++;
|
|
}
|
|
|
|
if ((fd = patty_kiss_tnc_fd_unix(iface->tnc)) >= 0) {
|
|
FD_CLR(fd, &ax25->unix_fds);
|
|
|
|
if (ax25->unix_fdmax == fd) {
|
|
ax25->unix_fdmax--;
|
|
}
|
|
|
|
if (patty_dict_delete(ax25->unix_fd_lookup, &fd, sizeof(fd)) == NULL) {
|
|
goto error_dict_delete;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_dict_delete:
|
|
error_list_splice:
|
|
return -1;
|
|
}
|