diff --git a/include/patty/ax25/if.h b/include/patty/ax25/if.h index abe10f0..41655f4 100644 --- a/include/patty/ax25/if.h +++ b/include/patty/ax25/if.h @@ -40,10 +40,28 @@ typedef struct _patty_ax25_if { tx_bufsz; patty_kiss_tnc *tnc; - patty_list *addrs; + patty_ax25_addr addr; + patty_list *aliases; } patty_ax25_if; -patty_ax25_if *patty_ax25_if_new(int opts, void *info); +typedef struct _patty_ax25_if_info { + patty_ax25_addr addr; +} patty_ax25_if_info; + +enum patty_ax25_if_kiss_tnc_info_type { + PATTY_AX25_IF_KISS_TNC_INFO_NONE, + PATTY_AX25_IF_KISS_TNC_INFO_FD, + PATTY_AX25_IF_KISS_TNC_INFO_PATH +}; + +typedef struct _patty_ax25_if_kiss_tnc_info { + patty_ax25_addr addr; + enum patty_ax25_if_kiss_tnc_info_type type; + int fd; + char path[256]; +} patty_ax25_if_kiss_tnc_info; + +patty_ax25_if *patty_ax25_if_new(int opts, patty_ax25_if_info *info); void patty_ax25_if_destroy(patty_ax25_if *iface); diff --git a/include/patty/ax25/proto.h b/include/patty/ax25/proto.h index a01e683..58c1b4b 100644 --- a/include/patty/ax25/proto.h +++ b/include/patty/ax25/proto.h @@ -22,7 +22,7 @@ enum patty_ax25_proto { PATTY_AX25_PROTO_INET_ARP = 0xcd, PATTY_AX25_PROTO_FLEXNET = 0xce, PATTY_AX25_PROTO_NETROM = 0xcf, - PATTY_AX25_PROTO_RAW = 0xf0, + PATTY_AX25_PROTO_NONE = 0xf0, PATTY_AX25_PROTO_ESCAPE = 0xff }; diff --git a/include/patty/ax25/route.h b/include/patty/ax25/route.h index ee21f19..8d38ed6 100644 --- a/include/patty/ax25/route.h +++ b/include/patty/ax25/route.h @@ -29,6 +29,8 @@ void patty_ax25_route_table_destroy(patty_ax25_route_table *table); patty_ax25_route *patty_ax25_route_table_find(patty_ax25_route_table *table, patty_ax25_addr *dest); +patty_ax25_route *patty_ax25_route_table_default(patty_ax25_route_table *table); + int patty_ax25_route_table_add(patty_ax25_route_table *table, patty_ax25_route *route); diff --git a/include/patty/ax25/server.h b/include/patty/ax25/server.h index 3f98bdd..92547a4 100644 --- a/include/patty/ax25/server.h +++ b/include/patty/ax25/server.h @@ -6,7 +6,7 @@ typedef struct _patty_ax25_server patty_ax25_server; -patty_ax25_server *patty_ax25_server_new(); +patty_ax25_server *patty_ax25_server_new(const char *path); void patty_ax25_server_destroy(patty_ax25_server *server); diff --git a/include/patty/ax25/sock.h b/include/patty/ax25/sock.h index b26c3ab..0b42b88 100644 --- a/include/patty/ax25/sock.h +++ b/include/patty/ax25/sock.h @@ -55,4 +55,6 @@ patty_ax25_sock *patty_ax25_sock_new(enum patty_ax25_sock_type type); void patty_ax25_sock_destroy(patty_ax25_sock *sock); +int patty_ax25_sock_send_sabm(patty_ax25_sock *sock); + #endif /* _PATTY_AX25_SOCK_H */ diff --git a/include/patty/kiss.h b/include/patty/kiss.h index b0f4498..090bfbf 100644 --- a/include/patty/kiss.h +++ b/include/patty/kiss.h @@ -29,13 +29,13 @@ enum patty_kiss_command { typedef struct _patty_kiss_tnc patty_kiss_tnc; -patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd); +patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd); -patty_kiss_tnc *patty_kiss_tnc_open(const char *device); +patty_kiss_tnc *patty_kiss_tnc_new(const char *device); int patty_kiss_tnc_fd(patty_kiss_tnc *tnc); -void patty_kiss_tnc_close(patty_kiss_tnc *tnc); +void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc); size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc); diff --git a/src/decode.c b/src/decode.c index 37c9217..6d45ad2 100644 --- a/src/decode.c +++ b/src/decode.c @@ -162,8 +162,8 @@ int main(int argc, char **argv) { } tnc = (argc == 2)? - patty_kiss_tnc_open(argv[1]): - patty_kiss_tnc_open_fd(0); + patty_kiss_tnc_new(argv[1]): + patty_kiss_tnc_new_fd(0); if (tnc == NULL) { perror("Unable to open TNC"); @@ -204,7 +204,7 @@ int main(int argc, char **argv) { free(buf); - patty_kiss_tnc_close(tnc); + patty_kiss_tnc_destroy(tnc); return 0; @@ -214,7 +214,7 @@ error_kiss_tnc_recv: free(buf); error_malloc_buf: - patty_kiss_tnc_close(tnc); + patty_kiss_tnc_destroy(tnc); error_kiss_tnc_open: return 127; diff --git a/src/if.c b/src/if.c index 654a0a7..e340d09 100644 --- a/src/if.c +++ b/src/if.c @@ -5,12 +5,16 @@ #include -static int init_tnc(patty_ax25_if *iface, const char *device) { +static int init_tnc(patty_ax25_if *iface, patty_ax25_if_kiss_tnc_info *info) { static char *prefix = "kiss"; static int number = 0; - if ((iface->tnc = patty_kiss_tnc_open(device)) == NULL) { - goto error_kiss_tnc_open; + 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; @@ -19,15 +23,15 @@ static int init_tnc(patty_ax25_if *iface, const char *device) { return 0; -error_kiss_tnc_open: +error_kiss_tnc_new: return -1; } -static void close_tnc(patty_ax25_if *iface) { - patty_kiss_tnc_close(iface->tnc); +static void destroy_tnc(patty_ax25_if *iface) { + patty_kiss_tnc_destroy(iface->tnc); } -patty_ax25_if *patty_ax25_if_new(int opts, void *info) { +patty_ax25_if *patty_ax25_if_new(int opts, patty_ax25_if_info *info) { patty_ax25_if *iface; if ((iface = malloc(sizeof(*iface))) == NULL) { @@ -36,6 +40,12 @@ patty_ax25_if *patty_ax25_if_new(int opts, void *info) { 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 { @@ -48,13 +58,13 @@ patty_ax25_if *patty_ax25_if_new(int opts, void *info) { iface->tx_bufsz = PATTY_AX25_IF_BUFSZ; } - if ((iface->addrs = patty_list_new()) == NULL) { - goto error_list_new; + 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, (const char *)info) < 0) { + if (init_tnc(iface, (patty_ax25_if_kiss_tnc_info *)info) < 0) { goto error_init; } @@ -66,13 +76,15 @@ patty_ax25_if *patty_ax25_if_new(int opts, void *info) { 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->addrs); + patty_list_destroy(iface->aliases); -error_list_new: +error_list_new_aliases: free(iface->tx_buf); error_malloc_tx_buf: @@ -82,20 +94,21 @@ 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: - close_tnc(iface); + destroy_tnc(iface); break; default: break; } - patty_list_destroy(iface->addrs); + patty_list_destroy(iface->aliases); free(iface->tx_buf); free(iface->rx_buf); @@ -107,14 +120,22 @@ int patty_ax25_if_addr_each(patty_ax25_if *iface, patty_list_iterator *iter; patty_ax25_addr *addr; - if ((iter = patty_list_start(iface->addrs)) == NULL) { + 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) { - char buf[7]; - uint8_t ssid; - if (patty_ax25_ntop(addr, buf, &ssid, sizeof(buf)) < 0) { goto error_ntop; } @@ -133,6 +154,8 @@ error_ntop: patty_list_finish(iter); error_list_start: +error_callback_addr: +error_ntop_addr: return -1; } @@ -142,14 +165,22 @@ static patty_ax25_addr *find_addr(patty_ax25_if *iface, patty_list_iterator *iter; patty_ax25_addr *addr; - if ((iter = patty_list_start(iface->addrs)) == NULL) { + 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) { - char buf[7]; - uint8_t addr_ssid; - if (patty_ax25_ntop(addr, buf, &addr_ssid, sizeof(buf)) < 0) { goto error_ntop; } @@ -157,7 +188,6 @@ static patty_ax25_addr *find_addr(patty_ax25_if *iface, if (strncmp(buf, callsign, sizeof(buf)) != 0) { continue; } - if (addr_ssid != ssid) { continue; @@ -172,6 +202,7 @@ error_ntop: patty_list_finish(iter); error_list_start: +error_ntop_addr: return NULL; } @@ -194,7 +225,7 @@ int patty_ax25_if_addr_add(patty_ax25_if *iface, goto error_pton; } - if ((patty_list_append(iface->addrs, addr)) == NULL) { + if ((patty_list_append(iface->aliases, addr)) == NULL) { goto error_list_append; } @@ -212,7 +243,7 @@ error_exists: int patty_ax25_if_addr_delete(patty_ax25_if *iface, const char *callsign, uint8_t ssid) { - patty_list_item *item = iface->addrs->first; + patty_list_item *item = iface->aliases->first; int i = 0; while (item) { @@ -226,7 +257,7 @@ int patty_ax25_if_addr_delete(patty_ax25_if *iface, } if (strncmp(buf, callsign, sizeof(buf)) == 0 && addr_ssid == ssid) { - if (patty_list_splice(iface->addrs, i) == NULL) { + if (patty_list_splice(iface->aliases, i) == NULL) { goto error_list_splice; } } diff --git a/src/kiss.c b/src/kiss.c index ed5fadf..b580522 100644 --- a/src/kiss.c +++ b/src/kiss.c @@ -17,8 +17,14 @@ enum kiss_flags { KISS_ESCAPE = 1 << 2 }; +enum tnc_opts { + TNC_NONE = 0, + TNC_CLOSE_ON_DESTROY = 1 << 0 +}; + struct _patty_kiss_tnc { - int fd; + int fd, + opts; void *buf, *frame; @@ -30,7 +36,7 @@ struct _patty_kiss_tnc { ssize_t readlen; }; -patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd) { +patty_kiss_tnc *patty_kiss_tnc_new_fd(int fd) { patty_kiss_tnc *tnc; if ((tnc = malloc(sizeof(*tnc))) == NULL) { @@ -42,6 +48,7 @@ patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd) { } tnc->fd = fd; + tnc->opts = TNC_NONE; tnc->bufsz = PATTY_KISS_BUFSZ; tnc->offset = 0; tnc->dropped = 0; @@ -56,7 +63,7 @@ error_malloc_tnc: return NULL; } -patty_kiss_tnc *patty_kiss_tnc_open(const char *device) { +patty_kiss_tnc *patty_kiss_tnc_new(const char *device) { patty_kiss_tnc *tnc; int fd; @@ -64,13 +71,15 @@ patty_kiss_tnc *patty_kiss_tnc_open(const char *device) { goto error_open; } - if ((tnc = patty_kiss_tnc_open_fd(fd)) == NULL) { - goto error_tnc_open_fd; + if ((tnc = patty_kiss_tnc_new_fd(fd)) == NULL) { + goto error_tnc_new_fd; } + tnc->opts |= TNC_CLOSE_ON_DESTROY; + return tnc; -error_tnc_open_fd: +error_tnc_new_fd: close(fd); error_open: @@ -81,10 +90,13 @@ int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) { return tnc->fd; } -void patty_kiss_tnc_close(patty_kiss_tnc *tnc) { - close(tnc->fd); - free(tnc->buf); - free(tnc); +void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc) { + if (tnc->opts & TNC_CLOSE_ON_DESTROY) { + close(tnc->fd); + } + + free(tnc->buf); + free(tnc); } static void tnc_drop(patty_kiss_tnc *tnc) { @@ -107,6 +119,8 @@ ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, enum kiss_flags flags = KISS_NONE; if (tnc->offset == tnc->readlen) { + errno = 0; + return 0; } @@ -208,6 +222,8 @@ done: if (flags & KISS_FRAME) { tnc_drop(tnc); + errno = 0; + return 0; } diff --git a/src/route.c b/src/route.c index dbbef74..36e1824 100644 --- a/src/route.c +++ b/src/route.c @@ -64,12 +64,33 @@ void patty_ax25_route_table_destroy(patty_ax25_route_table *table) { patty_ax25_route *patty_ax25_route_table_find(patty_ax25_route_table *table, patty_ax25_addr *dest) { + patty_ax25_route *route; uint32_t hash; patty_hash_init(&hash); patty_ax25_addr_hash(&hash, dest); patty_hash_end(&hash); + route = patty_dict_get_with_hash(table, hash); + + if (route) { + return route; + } + + return patty_ax25_route_table_default(table); +} + +patty_ax25_route *patty_ax25_route_table_default(patty_ax25_route_table *table) { + patty_ax25_addr empty; + + uint32_t hash; + + memset(&empty, '\0', sizeof(empty)); + + patty_hash_init(&hash); + patty_ax25_addr_hash(&hash, &empty); + patty_hash_end(&hash); + return patty_dict_get_with_hash(table, hash); } diff --git a/src/server.c b/src/server.c index 29f40c8..738784d 100644 --- a/src/server.c +++ b/src/server.c @@ -15,6 +15,8 @@ typedef int (*patty_ax25_server_call)(patty_ax25_server *, int); struct _patty_ax25_server { + char path[PATTY_AX25_SOCK_PATH_SIZE]; + int fd, /* fd of UNIX domain socket */ fd_max; @@ -38,7 +40,7 @@ struct _patty_ax25_server { *clients_by_sock; }; -patty_ax25_server *patty_ax25_server_new() { +patty_ax25_server *patty_ax25_server_new(const char *path) { patty_ax25_server *server; if ((server = malloc(sizeof(*server))) == NULL) { @@ -47,6 +49,8 @@ patty_ax25_server *patty_ax25_server_new() { memset(server, '\0', sizeof(*server)); + strncpy(server->path, path, PATTY_AX25_SOCK_PATH_SIZE); + if ((server->ifaces = patty_list_new()) == NULL) { goto error_list_new_ifaces; } @@ -717,6 +721,8 @@ static int server_connect(patty_ax25_server *server, patty_ax25_call_connect_response response; patty_ax25_sock *sock; + patty_ax25_route *route; + patty_ax25_if *iface; if (read(client, &request, sizeof(request)) < 0) { goto error_io; @@ -750,6 +756,43 @@ static int server_connect(patty_ax25_server *server, break; } + if (sock->local.callsign[0]) { + /* + * If there is an address already bound to this socket, locate the + * appropriate route. + */ + route = patty_ax25_route_table_find(server->routes, &sock->local); + } else { + /* + * Otherwise, locate the default route. + */ + route = patty_ax25_route_table_default(server->routes); + } + + /* + * If no route could be found, then assume the network is down or not + * configured. + */ + if (route == NULL) { + response.ret = -1; + response.eno = ENETDOWN; + + goto error_network_down; + } + + iface = sock->iface = route->iface; + + /* + * If there is no local address bound to this sock, then bind the + * address of the default route interface. + */ + if (sock->local.callsign[0] == '\0') { + memcpy(&sock->local, &iface->addr, sizeof(sock->local)); + } + + /* + * Bind the requested remote address to the socket. + */ memcpy(&sock->remote, &request.peer, sizeof(request.peer)); sock->status = PATTY_AX25_SOCK_PENDING_CONNECT; @@ -767,9 +810,17 @@ static int server_connect(patty_ax25_server *server, * timeout has been exceeded or the peer has sent a UA frame to * acknowledge and establish the connection. */ + if (patty_ax25_sock_send_sabm(sock) < 0) { + response.ret = -1; + response.eno = EIO; + + goto error_sock_send_sabm; + } return 0; +error_sock_send_sabm: +error_network_down: error_invalid_status: error_sock_by_fd: if (write(client, &response, sizeof(response)) < 0) { @@ -956,11 +1007,18 @@ static int handle_client(void *key, goto error_io; } + if (server_calls[call] == NULL) { + errno = ENOSYS; + + goto error_not_implemented; + } + return server_calls[call](server, client); done: return 0; +error_not_implemented: error_dict_delete: error_io: return -1; @@ -1101,7 +1159,7 @@ static int handle_socks(patty_ax25_server *server) { } int patty_ax25_server_run(patty_ax25_server *server) { - if (listen_unix(server, PATTY_AX25_SERVER_PATH) < 0) { + if (listen_unix(server, server->path) < 0) { goto error_listen_unix; } @@ -1109,11 +1167,10 @@ int patty_ax25_server_run(patty_ax25_server *server) { int nready; memcpy(&server->fds_r, &server->fds_watch, sizeof(server->fds_r)); - memcpy(&server->fds_w, &server->fds_watch, sizeof(server->fds_w)); if ((nready = select( server->fd_max, &server->fds_r, - &server->fds_w, + NULL, NULL, NULL)) < 0) { goto error_io; diff --git a/src/sock.c b/src/sock.c index 9be16e8..7052ea7 100644 --- a/src/sock.c +++ b/src/sock.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -27,3 +28,38 @@ error_malloc_sock: void patty_ax25_sock_destroy(patty_ax25_sock *sock) { free(sock); } + +static size_t copy_addr_to_buf(patty_ax25_sock *sock, uint8_t *buf, size_t offset) { + size_t i; + + memcpy(&buf[offset], &sock->remote, sizeof(patty_ax25_addr)); + offset += sizeof(patty_ax25_addr); + + memcpy(&buf[offset], &sock->local, sizeof(patty_ax25_addr)); + offset += sizeof(patty_ax25_addr); + + for (i=0; ihops; i++) { + memcpy(&buf[offset], &sock->repeaters[i], sizeof(patty_ax25_addr)); + offset += sizeof(patty_ax25_addr); + + if (i == sock->hops - 1) { + buf[offset - 1] |= 0x01; + } + } + + return offset; +} + +int patty_ax25_sock_send_sabm(patty_ax25_sock *sock) { + size_t offset = 0; + uint8_t *buf = (uint8_t *)(sock->iface->tx_buf); + + offset = copy_addr_to_buf(sock, buf, offset); + + buf[offset++] = PATTY_AX25_PROTO_NONE; + buf[offset++] = 0x3f; + + return patty_ax25_if_send(sock->iface, + buf, + offset); +} diff --git a/src/testclient.c b/src/testclient.c index 89721a8..0167d44 100644 --- a/src/testclient.c +++ b/src/testclient.c @@ -32,10 +32,15 @@ int main(int argc, char **argv) { int fd, sock; + patty_ax25_addr peer; + char path[256]; + if (argc != 2) { usage(argc, argv, "No patty socket provided"); } + patty_ax25_pton("GB9BLM", 0, &peer); + if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], "socket()", argv[1], strerror(errno)); @@ -58,14 +63,14 @@ int main(int argc, char **argv) { goto error_call_socket; } - if (patty_ax25_call_close(fd, sock) < 0) { + if (patty_ax25_call_connect(fd, sock, &peer, path) < 0) { fprintf(stderr, "%s: %s: %s\n", - argv[0], "patty_ax25_call_close()", strerror(errno)); + argv[0], "patty_ax25_call_connect()", strerror(errno)); goto error_call_close; } - fprintf(stderr, "got sock %d\n", sock); + fprintf(stderr, "connected sock %d\n", sock); close(fd); diff --git a/src/testserver.c b/src/testserver.c index 37bed1e..6ab1d81 100644 --- a/src/testserver.c +++ b/src/testserver.c @@ -1,8 +1,13 @@ +#define _GNU_SOURCE #include #include #include #include -#include +#include +#include +#include +#include +#include #include #include @@ -17,7 +22,7 @@ static void usage(int argc, char **argv, const char *message, ...) { va_end(args); } - fprintf(stderr, "usage: %s /dev/ttyXX|kiss.cap\n", argv[0]); + fprintf(stderr, "usage: %s /dev/ttyXX|kiss.cap [path.sock]\n", argv[0]); exit(1); } @@ -27,22 +32,57 @@ int main(int argc, char **argv) { patty_ax25_if *iface; patty_ax25_route *route; - if (argc != 2) { + patty_ax25_if_kiss_tnc_info info = { + .type = PATTY_AX25_IF_KISS_TNC_INFO_FD + }; + + if (argc < 2) { usage(argc, argv, "No TNC device or KISS dump file provided"); + } else if (argc > 3) { + usage(argc, argv, "Too many arguments provided"); } - if ((server = patty_ax25_server_new()) == NULL) { + if ((info.fd = open(argv[1], O_RDWR)) < 0) { + fprintf(stderr, "%s: %s: %s: %s\n", + argv[0], "open()", argv[1], strerror(errno)); + + goto error_open; + } + + if (isatty(info.fd) && grantpt(info.fd) == 0 && unlockpt(info.fd) == 0) { + char name[256]; + struct termios t; + + if (ptsname_r(info.fd, name, sizeof(name)) < 0) { + goto error_open; + } + + if (tcgetattr(info.fd, &t) < 0) { + goto error_open; + } + + cfmakeraw(&t); + + if (tcsetattr(info.fd, TCSANOW, &t) < 0) { + goto error_open; + } + + fprintf(stderr, "pts %s\n", name); + } + + errno = 0; + + patty_ax25_pton("KZ3ROX", 0, &info.addr); + + if ((server = patty_ax25_server_new(argc == 3? argv[2]: PATTY_AX25_SERVER_PATH)) == NULL) { goto error_server_new; } - if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC, argv[1])) == NULL) { + if ((iface = patty_ax25_if_new(PATTY_AX25_IF_KISS_TNC, + (patty_ax25_if_info *)&info)) == NULL) { goto error_if_new; } - if (patty_ax25_if_addr_add(iface, "KZ3ROX", 0) < 0) { - goto error_if_addr_add; - } - if (patty_ax25_server_add_if(server, iface) < 0) { goto error_server_add_if; } @@ -70,10 +110,12 @@ error_server_run: error_server_add_route: error_route_new_default: error_server_add_if: -error_if_addr_add: error_if_new: patty_ax25_server_destroy(server); error_server_new: + close(info.fd); + +error_open: return 1; }