patty/src/if.c
XANTRONIX Development 4e5634cbc7 My final commit
2024-03-01 00:20:46 -05:00

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;
}