#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include static void usage(int argc, char **argv, const char *message, ...) { if (message != NULL) { va_list args; va_start(args, message); vfprintf(stderr, message, args); fprintf(stderr, "\n"); va_end(args); } fprintf(stderr, "usage: %s /dev/ttyXX|kiss.cap [path.sock] callsign\n", argv[0]); exit(1); } int main(int argc, char **argv) { patty_ax25_server *server; patty_ax25_if *iface; patty_ax25_route *route; 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, "No socket path provided"); } else if (argc < 4) { usage(argc, argv, "No station callsign provided"); } else if (argc > 4) { usage(argc, argv, "Too many arguments provided"); } 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) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], argv[1], "ptsname_r()", strerror(errno)); goto error_open; } if (tcgetattr(info.fd, &t) < 0) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], argv[1], "tcgetattr()", strerror(errno)); goto error_open; } cfmakeraw(&t); if (tcsetattr(info.fd, TCSANOW, &t) < 0) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], argv[1], "tcsetattr()", strerror(errno)); goto error_open; } fprintf(stderr, "pts %s\n", name); } errno = 0; patty_ax25_pton(argv[3], 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, (patty_ax25_if_info *)&info)) == NULL) { goto error_if_new; } if (patty_ax25_server_add_if(server, iface) < 0) { goto error_server_add_if; } if ((route = patty_ax25_route_new_default(iface)) == NULL) { goto error_route_new_default; } if (patty_ax25_server_add_route(server, route) < 0) { goto error_server_add_route; } if (patty_ax25_server_run(server) < 0) { fprintf(stderr, "%s: %s: %s: %s\n", argv[0], argv[1], "patty_ax25_server_run()", strerror(errno)); goto error_server_run; } patty_ax25_server_destroy(server); return 0; error_server_run: error_server_add_route: error_route_new_default: error_server_add_if: error_if_new: patty_ax25_server_destroy(server); error_server_new: close(info.fd); error_open: return 1; }