#include #include #include #include #include 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)) == 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)); memcpy(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(iface->tnc)) >= 0) { FD_SET(fd, &ax25->fds); if (ax25->fdmax < fd + 1) { ax25->fdmax = fd + 1; } } if (patty_dict_set(ax25->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(iface->tnc)) >= 0) { FD_CLR(fd, &ax25->fds); if (ax25->fdmax == fd) { ax25->fdmax--; } if (patty_dict_delete(ax25->fd_lookup, &fd, sizeof(fd)) == NULL) { goto error_dict_delete; } } return 0; error_dict_delete: error_list_splice: return -1; }