patty/bin/if.c
XANTRONIX Development cb33d799ff Implement patty_ax25_if_driver
Changes:

    * Implement patty_ax25_if_driver type, providing a vtable with
      pointers to methods implementing an AX.25 interface PHY

    * Implement patty_ax25_if_name() to return a pointer to the name
      string of an AX.25 interface

    * Decouple patty_kiss_tnc from src/if.c using patty_ax25_if_driver

    * Remove port input/output arguments from patty_kiss_tnc_send()
      and patty_kiss_tnc_recv(), respectively; use 0 as the default,
      but keep the port argument in patty_kiss_frame_send()

    * Implement patty_ax25_if_fd() to return file descriptor backing a
      PHY; use this rather than patty_kiss_tnc_fd() in src/server.c to
      further decouple interfaces from their implementation

    * Remove 'enum patty_ax25_if_type' type; refactor constructor
      patty_ax25_if_new() to no longer take this as an argument, but
      rather a patty_ax25_if_driver to use to instantiate the PHY
      with the information pointer passed

    * Break out patty_kiss_tnc code from src/kiss.c into src/tnc.c,
      leaving only patty_kiss_frame_send() in the original; this is
      needed to prevent a cyclic dependency within patty_ax25_sock and
      other areas

    * Rename patty_bin_if_config() to patty_bin_if_create(); a separate
      patty_bin_if_config() will likely be created later as necessary
      to change an existing interface

    * Split PHY-specific interface configuration code into separate
      delegates in bin/if.c

    * Implement usage of patty_error to better capture internal error
      states not currently representable with semantic error numbers
      while configuring and instantiating PHYs

    * Pass patty_error object to patty_bin_kiss_config() to receive
      detailed error information
2024-03-01 00:20:47 -05:00

197 lines
4.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <patty/bin/if.h>
struct context {
patty_error *err;
char *name;
patty_ax25_addr addr;
};
enum mode {
MODE_NONE,
MODE_IFNAME,
MODE_IFOPTS,
MODE_IFADDR,
MODE_KISS,
MODE_BAUD,
MODE_FLOW
};
static patty_ax25_if *create_kiss(struct context *ctx, int argc, char **argv) {
enum mode mode = MODE_KISS;
patty_kiss_tnc_info info;
int i;
memset(&info, '\0', sizeof(info));
if (argc == 0) {
patty_error_fmt(ctx->err, "Too few parameters for 'kiss' interface");
goto error_invalid;
}
for (i=0; i<argc; i++) {
switch (mode) {
case MODE_KISS:
info.flags |= PATTY_KISS_TNC_DEVICE;
info.device = argv[i];
mode = MODE_IFOPTS;
break;
case MODE_IFOPTS:
if (strcmp(argv[i], "baud") == 0) {
mode = MODE_BAUD;
} else if (strcmp(argv[i], "flow") == 0) {
mode = MODE_FLOW;
} else {
patty_error_fmt(ctx->err, "Invalid parameter '%s'",
argv[i]);
}
break;
case MODE_BAUD:
if (!(argv[i][0] >= '0' && argv[i][0] <= '9')) {
patty_error_fmt(ctx->err, "Invalid baud rate '%s'",
argv[i]);
goto error_invalid;
}
info.flags |= PATTY_KISS_TNC_BAUD;
info.baud = atoi(argv[i]);
mode = MODE_IFOPTS;
break;
case MODE_FLOW:
if (strcmp(argv[i], "crtscts") == 0) {
info.flags |= PATTY_KISS_TNC_FLOW;
info.flow = PATTY_KISS_TNC_FLOW_CRTSCTS;
} else if (strcmp(argv[i], "xonxoff") == 0) {
info.flags |= PATTY_KISS_TNC_FLOW;
info.flow = PATTY_KISS_TNC_FLOW_XONXOFF;
} else {
patty_error_fmt(ctx->err, "Invalid flow control '%s'",
argv[i]);
goto error_invalid;
}
mode = MODE_IFOPTS;
break;
default:
break;
}
}
return patty_ax25_if_new( ctx->name,
&ctx->addr,
patty_kiss_tnc_driver(),
&info);
error_invalid:
return NULL;
}
struct if_type {
const char *name;
patty_ax25_if *(*func)(struct context *ctx, int argc, char **argv);
};
struct if_type if_types[] = {
{ "kiss", create_kiss },
{ NULL, NULL }
};
patty_ax25_if *patty_bin_if_create(int argc, char **argv, patty_error *e) {
enum mode mode = MODE_NONE;
struct context ctx = {
.err = e,
.name = NULL
};
int i;
patty_error_clear(e);
memset(&ctx.addr, '\0', sizeof(ctx.addr));
for (i=0; i<argc; i++) {
switch (mode) {
case MODE_NONE:
if (strcmp(argv[i], "if") != 0) {
patty_error_fmt(e, "Unexpected start of expression '%s'",
argv[i]);
goto error_invalid;
} else {
mode = MODE_IFNAME;
}
break;
case MODE_IFNAME:
ctx.name = argv[i];
mode = MODE_IFOPTS;
break;
case MODE_IFOPTS:
if (strcmp(argv[i], "ax25") == 0) {
mode = MODE_IFADDR;
} else {
int t;
for (t=0; if_types[t].name; t++) {
if (strcmp(if_types[t].name, argv[i]) == 0) {
return if_types[t].func(&ctx,
argc - i - 1,
argv + i + 1);
}
}
patty_error_fmt(e, "Invalid parameter '%s'", argv[i]);
goto error_invalid;
}
break;
case MODE_IFADDR:
if (patty_ax25_pton(argv[i], &ctx.addr) < 0) {
patty_error_fmt(e, "Invalid AX.25 address '%s': %s",
argv[i], strerror(errno));
goto error_invalid;
}
mode = MODE_IFOPTS;
break;
default:
break;
}
}
patty_error_fmt(e, "Media type not provided");
error_invalid:
return NULL;
}