Logo Search packages:      
Sourcecode: baycomusb version File versions  Download package

baycomusb.c

/*****************************************************************************/

/*
 *      baycomusb.c  -- HDLC packet radio modem for USB using FPGA/AnchorChips utility.
 *
 *      Copyright (C) 1998-2001  Thomas Sailer (t.sailer@alumni.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef WIN32
#include <sys/socket.h>
#include <sys/ioctl.h>
#endif

#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef HAVE_GETOPT_H
#include <getopt.h>
#else
#include "getopt.h"
#endif

#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#endif

#ifdef HAVE_LINUX_IF_H
#include <linux/if.h>
#endif
#ifdef HAVE_LINUX_AX25_H
#include <linux/ax25.h>
#endif
#ifdef HAVE_LINUX_SOCKIOS_H
#include <linux/sockios.h>
#endif
#ifdef HAVE_LINUX_IF_ETHER_H
#include <linux/if_ether.h>
#endif
#if defined(HAVE_ARPA_INET_H) && !defined(WIN32)
#include <arpa/inet.h>
#endif

#include "baycomusb.h"

/* ---------------------------------------------------------------------- */

static int quit = 0;

/* ---------------------------------------------------------------------- */

int tprintf(const char *format, ...)
{
      va_list ap;
      int i;

        va_start(ap, format);
        i = vprintf(format, ap);
        va_end(ap);
      fflush(stdout);
      return i;
}

int idle_callback(unsigned us_delay)
{
      if (us_delay)
            usleep(us_delay);
      return quit;
}

static void signal_quit(int signum)
{
      quit = 1;
}

/* ---------------------------------------------------------------------- */

#ifdef WIN32

static int doinit(int devnr, int busnr, const char *ifname)
{
      return 0;
}

#else /* WIN32 */

static int parsehw(ax25_address *hwaddr, const char *cp)
{
        const char *cp1;
        unsigned int i, j;

        if (!cp || !*cp)
                return 0;
        memset(hwaddr->ax25_call, ' ', 6);
        cp1 = strchr(cp, '-');
        if (cp1) {
                i = cp1 - cp;
                j = strtoul(cp1 + 1, NULL, 0);
                hwaddr->ax25_call[6] = j & 15;
        } else {
                i = strlen(cp);
            hwaddr->ax25_call[6] = 0;
      }
        if (i > 6)
                i = 6;
        memcpy(hwaddr->ax25_call, cp, i);
        for (i = 0; i < 7; i++)
                hwaddr->ax25_call[i] <<= 1;
        return 1;
}

static int parseip(struct in_addr *ipaddr, const char *cp)
{
        if (!cp || !*cp)
                return 0;
        if (inet_aton(cp, ipaddr))
                return 1;
        ipaddr->s_addr = 0;
        lprintf(0, "baycomusb: invalid IP address \"%s\"\n", cp);
        return 0;
}

#define PARAM_TXDELAY   1
#define PARAM_PERSIST   2
#define PARAM_SLOTTIME  3
#define PARAM_TXTAIL    4
#define PARAM_FULLDUP   5

static int initonedev(struct usbdevice *dev, const char *ifname)
{
      struct configentry *cfg;
      struct sockaddr sa;
      struct sockaddr_ax25 sax25;
        struct sockaddr_in sin;
        struct ifreq ifr, ifr_h;
      unsigned char buf[2];
      int i, fd;

      i = adapter_configure(dev);
      if (i < 1)
            return i;
      cfg = adapter_findconfig(dev);
      strncpy(ifr_h.ifr_name, ifname, sizeof(ifr_h.ifr_name));
#ifdef HAVE_IFRNEWNAME
      if (cfg->ifcfg.ifname[0]) {
            if ((fd = socket(PF_AX25, SOCK_SEQPACKET, 0)) < 0) {
                  lprintf(0, "Cannot create socket: %s (%u) \n", strerror(errno), errno);
                  } else {
                  strncpy(ifr_h.ifr_newname, cfg->ifcfg.ifname, sizeof(ifr_h.ifr_newname));
                  if (ioctl(fd, SIOCSIFNAME, &ifr_h) == -1)
                        lprintf(0, "Cannot rename interface (SIOCSIFNAME: %s (%u))\n", strerror(errno), errno);
                  else
                        strncpy(ifr_h.ifr_name, cfg->ifcfg.ifname, sizeof(ifr_h.ifr_name));
                  close(fd);
            }
      }
#endif
      if ((fd = socket(/*PF_PACKET*/AF_INET, /*SOCK_RAW*/SOCK_PACKET, htons(ETH_P_AX25))) < 0) {
            lprintf(0, "Cannot create socket: %s (%u) \n", strerror(errno), errno);
            return -1;
      }
      if (ioctl(fd, SIOCGIFINDEX, &ifr_h) == -1)
            lprintf(0, "ioctl: SIOCGIFINDEX failed: %s (%u)\n", strerror(errno), errno);
      ifr = ifr_h;
      ifr.ifr_mtu = 256;
      if (ioctl(fd, SIOCSIFMTU, &ifr) == -1)
            lprintf(0, "ioctl: SIOCSIFMTU failed: %s (%u)\n", strerror(errno), errno);
      if (parsehw(&sax25.sax25_call, cfg->ifcfg.hwaddr)) {
                sax25.sax25_family = AF_AX25;
                sax25.sax25_ndigis = 0;
            ifr = ifr_h;
                memcpy(&ifr.ifr_hwaddr, &sax25, sizeof(ifr.ifr_hwaddr));
                if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFHWADDR failed: %s (%u)\n", strerror(errno), errno);
      }
      if (parseip(&sin.sin_addr, cfg->ifcfg.ipaddr)) {
                sin.sin_family = AF_INET;
            ifr = ifr_h;
                memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
                if (ioctl(fd, SIOCSIFADDR, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFADDR failed: %s (%u)\n", strerror(errno), errno);
        }
      if (parseip(&sin.sin_addr, cfg->ifcfg.netmask)) {
                sin.sin_family = AF_INET;
            ifr = ifr_h;
                memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
                if (ioctl(fd, SIOCSIFNETMASK, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFNETMASK failed: %s (%u)\n", strerror(errno), errno);
        }
      if (parseip(&sin.sin_addr, cfg->ifcfg.broadcast)) {
                sin.sin_family = AF_INET;
            ifr = ifr_h;
                memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
                if (ioctl(fd, SIOCSIFBRDADDR, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFBRDADDR failed: %s (%u)\n", strerror(errno), errno);
        }
      if (cfg->adapter.mode != MODE_AUDIO) {
            ifr = ifr_h;
            if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
                  lprintf(0, "ioctl: SIOCGIFFLAGS failed: %s (%u)\n", strerror(errno), errno);
            else {
                  ifr.ifr_flags &= ~IFF_NOARP;
                  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
                  if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFFLAGS failed: %s (%u)\n", strerror(errno), errno);
            }
      }
      strncpy(sa.sa_data, ifr_h.ifr_name, sizeof(sa.sa_data));
      sa.sa_family = AF_PACKET;
      buf[0] = PARAM_TXDELAY;
      buf[1] = cfg->chaccess.txdelay / 10;
      if (sendto(fd, buf, 2, 0, &sa, sizeof(struct sockaddr)) == -1)
            lprintf(0, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_PERSIST;
      buf[1] = cfg->chaccess.ppersistence;
      if (sendto(fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(0, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_SLOTTIME;
      buf[1] = cfg->chaccess.slottime / 10;
      if (sendto(fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(0, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_TXTAIL;
      buf[1] = cfg->chaccess.txtail / 10;
      if (sendto(fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(0, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_FULLDUP;
      buf[1] = cfg->chaccess.fullduplex;
      if (sendto(fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(0, "sendto failed: %s (%u)\n", strerror(errno), errno);
      return 0;
}

static int doinit(int devnr, int busnr, const char *ifname)
{
      struct usbdevice *dev;
      unsigned int index;
      int ret;

      if (devnr != -1 && busnr != -1) {
            if (!(dev = usb_open_bynumber(busnr, devnr, BAYCOMUSB_VENDORID, -1))) {
                  lprintf(0, "Cannot open Baycom USB device %03u:%03u\n", busnr, devnr);
                  return -1;
            }
            ret = initonedev(dev, ifname);
            usb_close(dev);
            return ret;
      }
      for (ret = index = 0; ; index++) {
            if (!(dev = usb_open(BAYCOMUSB_VENDORID, -1, 0, index))) {
                  if (!index)
                        lprintf(0, "No Baycom USB devices found\n");
                  break;
            }
            ret |= initonedev(dev, ifname);
            usb_close(dev);
      }
      return ret;
}

#endif /* WIN32 */

static int dotest(unsigned int index, int devnr, int busnr, const struct usbtests *tst)
{
      struct usbdevice *dev;
      struct configentry *cfg;
      unsigned int i;
      int ret;

      for (i = 0; ; i++) {
            cfg = config_entry(i);
            if (!cfg)
                  break;
            tst->cfg(cfg);
      }
      if (devnr != -1 && busnr != -1) {
            if (!(dev = usb_open_bynumber(busnr, devnr, BAYCOMUSB_VENDORID, -1))) {
                  lprintf(0, "Cannot open Baycom USB device %03u:%03u\n", busnr, devnr);
                  return -1;
            }
      } else {
            if (!(dev = usb_open(BAYCOMUSB_VENDORID, -1, 0, index))) {
                  lprintf(0, "Cannot open Baycom USB device at index %u\n", index);
                  return -1;
            }
      }
      cfg = config_entry(0);
      if (cfg->adapter.mode != MODE_NONE) {
            ret = adapter_configure(dev);
            if (ret == -1)
                  goto err;
            if (!ret) {
                  usb_close(dev);
                  sleep(2);
                  if (devnr != -1 && busnr != -1) {
                        if (!(dev = usb_open_bynumber(busnr, devnr, BAYCOMUSB_VENDORID, -1))) {
                              lprintf(0, "Cannot open Baycom USB device %03u:%03u\n", busnr, devnr);
                              return -1;
                        }
                  } else {
                        if (!(dev = usb_open(BAYCOMUSB_VENDORID, -1, 0, index))) {
                              lprintf(0, "Cannot open Baycom USB device at index %u\n", index);
                              return -1;
                        }
                  }
                  ret = adapter_configure(dev);
                  if (ret < 1) {
                        ret = -1;
                        goto err;
                  }
            }
      }
#ifdef SIGHUP
      signal(SIGHUP, signal_quit);
#endif
      signal(SIGINT, signal_quit);
#ifdef SIGQUIT
      signal(SIGQUIT, signal_quit);
#endif
      signal(SIGTERM, signal_quit);
      ret = abs(tst->func(dev, adapter_findconfig(dev)));
 err:
      usb_close(dev);
      return ret;
}

/* ---------------------------------------------------------------------- */

int main(int argc, char *argv[])
{
        static const struct option long_options[] = {
                { "drv", 1, 0, 'D' },
            { "config", 1, 0, 'C' },
                { "device", 1, 0, 'd' },
                { "index", 1, 0, 'i' },
                { "ifname", 1, 0, 'I' },
                { "test", 1, 0, 't' },
                { "verbose", 0, 0, 'v' },
                { "help", 0, 0, 'h' },
            { 0, 0, 0, 0 }
        };
      int c, err = 0;
      const struct usbtests *tst = NULL;
      const char *ifname = NULL;
      int devnr = -1, busnr = -1;
      unsigned int index = 0;
      char *cp;

      printf("baycomusb v" VERSION " (c) 1999-2001 by Thomas Sailer, HB9JNX/AE4WA\n");
      while ((c = getopt_long(argc, argv, "D:C:svd:i:I:t:", long_options, NULL)) != EOF) {
            switch (c) {
            case 'D':
                  usb_setmountpoint(optarg);
                  break;

            case 'C':
                  config_setfile(optarg);
                  break;

#if defined(HAVE_SYSLOG) && defined(HAVE_VSYSLOG)
            case 's':
                  if (syslogmsg)
                        break;
                  openlog("baycomusb", LOG_PID, LOG_USER);
                  syslogmsg = 1;
                  break;
#endif

            case 'v':
                  verboselevel++;
                  break;

            case 'd':
                  cp = strchr(optarg, ':');
                  if (!cp) {
                        busnr = 0;
                        devnr = strtoul(optarg, NULL, 0);
                        break;
                  }
                  *cp++ = 0;
                  busnr = strtoul(optarg, NULL, 0);
                  devnr = strtoul(cp, NULL, 0);
                  break;

            case 'i':
                  index = strtoul(optarg, NULL, 0);
                  break;

            case 'I':
                  ifname = optarg;
                  break;

            case 't':
                  if (tst != NULL) {
                        err++;
                        break;
                  }
                  for (tst = usbtests; tst->name && strcmp(optarg, tst->name); tst++);
                  if (!tst->name)
                        err++;
                  break;

            default:
                  err++;
                  break;
            }
      }
      if (err) {
            lprintf(0, "usage: %s [-v] [-D <drvpath>] [-C <configfile>] [-d <bus:dev>] [-i <idx>] [-I <ifname>] [-t <test>]\n"
                  "  test options:\n", argv[0]);
            for (tst = usbtests; tst->name; tst++)
                  lprintf(0, "    %-15s%s\n", tst->name, tst->desc);
            exit(1);
      }
      if (config_parse())
            lprintf(0, "Warning: Could not parse configuration file %s\n", config_getfile());
      if (!tst)
            exit(doinit(devnr, busnr, ifname));
      exit(dotest(index, devnr, busnr, tst));
}

Generated by  Doxygen 1.6.0   Back to index