#include #include #include #include #include static int init_tnc(patty_ax25_if *iface, patty_ax25_if_kiss_tnc_info *info) { static char *prefix = "kiss"; static int number = 0; iface->tnc = (info->type == PATTY_AX25_IF_KISS_TNC_INFO_FD)? patty_kiss_tnc_new_fd(info->fd): patty_kiss_tnc_new(info->path); if (iface->tnc == NULL) { goto error_kiss_tnc_new; } iface->type = PATTY_AX25_IF_KISS_TNC; snprintf(iface->name, sizeof(iface->name), "%s%d", prefix, number++); return 0; error_kiss_tnc_new: return -1; } static void destroy_tnc(patty_ax25_if *iface) { patty_kiss_tnc_destroy(iface->tnc); } patty_ax25_if *patty_ax25_if_new(int opts, patty_ax25_if_info *info) { patty_ax25_if *iface; if ((iface = malloc(sizeof(*iface))) == NULL) { goto error_malloc_iface; } memset(iface, '\0', sizeof(*iface)); if (info->addr.callsign[0] == '\0') { errno = EINVAL; goto error_invalid_address; } if ((iface->rx_buf = malloc(PATTY_AX25_IF_BUFSZ)) == NULL) { goto error_malloc_rx_buf; } else { iface->rx_bufsz = PATTY_AX25_IF_BUFSZ; } if ((iface->tx_buf = malloc(PATTY_AX25_IF_BUFSZ)) == NULL) { goto error_malloc_tx_buf; } else { iface->tx_bufsz = PATTY_AX25_IF_BUFSZ; } if ((iface->aliases = patty_list_new()) == NULL) { goto error_list_new_aliases; } switch (PATTY_AX25_IF_OPT_TYPE(opts)) { case PATTY_AX25_IF_KISS_TNC: if (init_tnc(iface, (patty_ax25_if_kiss_tnc_info *)info) < 0) { goto error_init; } break; default: errno = EINVAL; goto error_invalid_if_type; } memcpy(&iface->addr, &info->addr, sizeof(iface->addr)); return iface; error_invalid_if_type: error_init: patty_list_destroy(iface->aliases); error_list_new_aliases: free(iface->tx_buf); error_malloc_tx_buf: free(iface->rx_buf); error_malloc_rx_buf: free(iface); error_malloc_iface: error_invalid_address: return NULL; } void patty_ax25_if_destroy(patty_ax25_if *iface) { switch (iface->type) { case PATTY_AX25_IF_KISS_TNC: destroy_tnc(iface); break; default: break; } patty_list_destroy(iface->aliases); free(iface->tx_buf); free(iface->rx_buf); free(iface); } int patty_ax25_if_addr_each(patty_ax25_if *iface, int (*callback)(char *, uint8_t, void *), void *ctx) { patty_list_iterator *iter; patty_ax25_addr *addr; char buf[7]; uint8_t ssid; if (patty_ax25_ntop(&iface->addr, buf, &ssid, sizeof(buf)) < 0) { goto error_ntop_addr; } if (callback(buf, ssid, ctx) < 0) { goto error_callback_addr; } if ((iter = patty_list_start(iface->aliases)) == NULL) { goto error_list_start; } while ((addr = patty_list_next(iter)) != NULL) { if (patty_ax25_ntop(addr, buf, &ssid, sizeof(buf)) < 0) { goto error_ntop; } if (callback(buf, ssid, ctx) < 0) { goto error_callback; } } patty_list_finish(iter); return 0; error_callback: error_ntop: patty_list_finish(iter); error_list_start: error_callback_addr: error_ntop_addr: return -1; } static patty_ax25_addr *find_addr(patty_ax25_if *iface, const char *callsign, uint8_t ssid) { patty_list_iterator *iter; patty_ax25_addr *addr; char buf[7]; uint8_t addr_ssid; if (patty_ax25_ntop(&iface->addr, buf, &addr_ssid, sizeof(buf)) < 0) { goto error_ntop_addr; } if (strncmp(buf, callsign, sizeof(buf)) == 0 && addr_ssid == ssid) { return &iface->addr; } if ((iter = patty_list_start(iface->aliases)) == NULL) { goto error_list_start; } while ((addr = patty_list_next(iter)) != NULL) { if (patty_ax25_ntop(addr, buf, &addr_ssid, sizeof(buf)) < 0) { goto error_ntop; } if (strncmp(buf, callsign, sizeof(buf)) != 0) { continue; } if (addr_ssid != ssid) { continue; } patty_list_finish(iter); return addr; } error_ntop: patty_list_finish(iter); error_list_start: error_ntop_addr: return NULL; } int patty_ax25_if_addr_add(patty_ax25_if *iface, const char *callsign, uint8_t ssid) { patty_ax25_addr *addr; if (find_addr(iface, callsign, ssid) != NULL) { errno = EEXIST; goto error_exists; } if ((addr = malloc(sizeof(*addr))) == NULL) { goto error_malloc_addr; } if (patty_ax25_pton(callsign, ssid, addr) < 0) { goto error_pton; } if ((patty_list_append(iface->aliases, addr)) == NULL) { goto error_list_append; } return 0; error_list_append: error_pton: free(addr); error_malloc_addr: error_exists: return -1; } int patty_ax25_if_addr_delete(patty_ax25_if *iface, const char *callsign, uint8_t ssid) { patty_list_item *item = iface->aliases->first; int i = 0; while (item) { char buf[7]; uint8_t addr_ssid; patty_ax25_addr *addr = item->value; if (patty_ax25_ntop(addr, buf, &addr_ssid, sizeof(buf)) < 0) { goto error_ntop; } if (strncmp(buf, callsign, sizeof(buf)) == 0 && addr_ssid == ssid) { if (patty_list_splice(iface->aliases, i) == NULL) { goto error_list_splice; } } item = item->next; i++; } return 0; error_list_splice: error_ntop: return -1; } ssize_t patty_ax25_if_recv(patty_ax25_if *iface, void **buf) { ssize_t readlen; int port; if ((readlen = patty_kiss_tnc_recv(iface->tnc, iface->rx_buf, iface->rx_bufsz, &port)) < 0) { goto error_kiss_tnc_recv; } *buf = iface->rx_buf; return readlen; error_kiss_tnc_recv: return -1; } ssize_t patty_ax25_if_send(patty_ax25_if *iface, const void *buf, size_t len) { ssize_t wrlen; if ((wrlen = patty_kiss_tnc_send(iface->tnc, buf, len, 0)) < 0) { goto error_kiss_tnc_send; } return wrlen; error_kiss_tnc_send: return -1; }