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

mainunix.c

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

/*
 *      mainunix.c  --  Transceiver control UNIX stuff.
 *
 *      Copyright (C) 2000-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.
 *
 *  History:
 *   0.1  19.09.2000  Created
 *
 */

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

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

#define _REENTRANT

#include "trx.h"

#define _USE_BSD
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <ctype.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_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
#ifdef HAVE_NET_IF_ARP_H
#include <net/if_arp.h>
#endif
#ifdef HAVE_NETAX25_AX25_H
#include <netax25/ax25.h>
#elif defined(HAVE_LINUX_AX25_H)
#include <linux/ax25.h>
#endif
#ifdef HAVE_NET_ROUTE_H
#include <net/route.h>
#endif

#include <glib.h>
#include <pthread.h>

#include "list.h"

#include "baycom_usb.h"

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

struct orbfdlist {
      struct list_head list;
      GIOPConnection *conn;
      struct pollfd *pfd;
};

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

static int devices_fd = -1;
static LIST_HEAD(devices_list);
static pthread_mutex_t orbit_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t devlist_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t devlist_cond = PTHREAD_COND_INITIALIZER;
static LIST_HEAD(orb_fds);
static int quit = 0;
static int sock_fd = -1;

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

void acquire_orbit_mutex(void)
{
      pthread_mutex_lock(&orbit_mutex);
}

void release_orbit_mutex(void)
{
      pthread_mutex_unlock(&orbit_mutex);
}

void acquire_trxdata_mutex(struct trx_thread_state *state)
{
      pthread_mutex_lock(&state->mutex);
}

void release_trxdata_mutex(struct trx_thread_state *state)
{
      pthread_mutex_unlock(&state->mutex);
}

int check_quit(void)
{
      return quit;
}

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

#if 0
static int findinterface(struct trx_thread_state *state)
{
      struct ifreq ifr;
      int fd;
      union {
            struct baycomusb_device bdev;
            char buf[1024];
      } bd;
      FILE *f;
      char *cp;

      if (!(f = fopen("/proc/net/dev", "r"))) {
            lprintf(1, "cannot open /proc/net/dev\n");
            return -1;
      }
      if ((fd = socket(PF_AX25, SOCK_SEQPACKET, 0)) < 0) {
            lprintf(0, "Cannot create socket: %s (%u) \n", strerror(errno), errno);
      }
      for (;;) {
            if (!fgets(bd.buf, sizeof(bd.buf), f)) {
                  lprintf(1, "Cannot find network interface for %03d:%03d\n", state->busnr, state->devnr);
                  fclose(f);
                  close(fd);
                  return -1;
            }
            if (!(cp = strchr(bd.buf, ':')))
                  continue;
            *cp = 0;
            cp = bd.buf;
            while (*cp == ' ')
                  cp++;
            strncpy(ifr.ifr_name, cp, sizeof(ifr.ifr_name));
            if (ioctl(fd, SIOCGIFHWADDR, &ifr))
                  continue;
            if (ifr.ifr_addr.sa_family != AF_AX25)
                  continue;
            ifr.ifr_data = (void *)&bd.bdev;
            bd.bdev.cmd = BAYCOMUSB_GETDEVICE;
            if (ioctl(fd, SIOCDEVPRIVATE, &ifr))
                  continue;

            printf("Baycomusb netdev: %s usbdev: %03d:%03d\n", ifr.ifr_name, bd.bdev.busnr, bd.bdev.devnr);

            if (bd.bdev.busnr != state->busnr || bd.bdev.devnr != state->devnr)
                  continue;
            break;
      }
      fclose(f);
      close(fd);
      if (strcmp(state->serial, bd.bdev.serial))
            lprintf(1, "USB device %03d:%03d: serial numbers %s / %s do not match!\n",
                  state->busnr, state->devnr, state->serial, bd.bdev.serial);
      state->bitrate = bd.bdev.bitrate;
      strncpy(state->ifname, ifr.ifr_name, sizeof(state->ifname));
      return 0;
}
#endif

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

int reopen_usbdev(struct trx_thread_state *state)
{
      struct timespec tm;
      struct timeval tv;
      int r;

      if (state->usbdev)
            usb_close(state->usbdev);
      state->usbdev = NULL;
      pthread_mutex_lock(&devlist_mutex);
            state->busnr = state->devnr = -1;
      gettimeofday(&tv, NULL);
      tm.tv_sec = tv.tv_sec + 60;
      tm.tv_nsec = tv.tv_usec * 1000;
      for (;;) {
            if ((r = pthread_cond_timedwait(&devlist_cond, &devlist_mutex, &tm)) && r != EINTR) {
                  lprintf(1, "Timeout reopening USB device %s: pthread_cond_wait error %s (%d)\n", state->serial, strerror(r), r);
                  pthread_mutex_unlock(&devlist_mutex);
                  return -1;
            }
            if (check_quit()) {
                  pthread_mutex_unlock(&devlist_mutex);
                  return -1;
            }
            if (state->busnr != -1 && state->devnr != -1)
                  break;
      }
      pthread_mutex_unlock(&devlist_mutex);
      if (!(state->usbdev = usb_open_bynumber(state->busnr, state->devnr, BAYCOMUSB_VENDORID, -1))) {
            lprintf(1, "Cannot open USB device %03d:%03d\n", state->busnr, state->devnr);
            return -1;
      }
      lprintf(10, "=== THREADCONTINUE: %03d:%03d\n", state->busnr, state->devnr);
      return 0;
}

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

static void *thread_start(void *arg)
{
      struct trx_thread_state *state = arg;
      struct trx_thread_state *state2;
      struct list_head *list;
      int i;

      lprintf(10, ">>> THREADSTART: %03d:%03d\n", state->busnr, state->devnr);
      /* open communications to device */
      pthread_mutex_init(&state->mutex, NULL);
      state->netif_fd = -1;
      /* get serial number from device */
      if (!(state->usbdev = usb_open_bynumber(state->busnr, state->devnr, BAYCOMUSB_VENDORID, -1))) {
            lprintf(1, "Cannot open USB device %03d:%03d\n", state->busnr, state->devnr);
            goto ret;
      }
      i = adapter_init_getserial(state);
      if (i < 0) {
            if (i == -2)
                  lprintf(1, "Error loading USB device %03d:%03d\n", state->busnr, state->devnr);
            goto ret;
      }
      lprintf(2, "USB device %03d:%03d serial %s\n", state->busnr, state->devnr, state->serial);
      pthread_mutex_lock(&devlist_mutex);
      for (list = devices_list.next; list != &devices_list; list = list->next) {
            state2 = list_entry(list, struct trx_thread_state, device_list);
            if (state2 != state && !strcmp(state2->serial, state->serial)) {
                  state2->busnr = state->busnr;
                  state2->devnr = state->devnr;
                  state2->mode = state->mode;
                  list_del(&state->device_list);
                  INIT_LIST_HEAD(&state->device_list);
                  pthread_mutex_unlock(&devlist_mutex);
                  lprintf(2, "Thread for USB device %03d:%03d serial %s already running\n", 
                        state->busnr, state->devnr, state->serial);
                  pthread_cond_broadcast(&devlist_cond);
                  goto ret;
            }
      }
      pthread_mutex_unlock(&devlist_mutex);
      state->flags = FLG_RELOADMODEM | FLG_MODEMERROR | FLG_T7FERROR;

      trx_thread(state);

  ret:
      pthread_mutex_destroy(&state->mutex);
      if (state->usbdev)
            usb_close(state->usbdev);
      netif_close(state);
      pthread_mutex_lock(&devlist_mutex);
      list_del(&state->device_list);
      pthread_mutex_unlock(&devlist_mutex);
      lprintf(10, "<<< THREADSTOP: %s\n", state->serial);
      free(state);
      return NULL;
}

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

static void check_new_uninited_modems(void)
{
        char buf[16384];
        char *start, *end, *lineend, *cp;
        int ret;
        unsigned int devnum = 0, busnum = 0, vendorid, productid;
      struct list_head *list;
      struct trx_thread_state *state;
      pthread_attr_t attr;
      pthread_t thr;

      /* now scan devices file */
        if (lseek(devices_fd, 0, SEEK_SET) == (off_t)-1)
                lprintf(0, "lseek: %s (%d)\n", strerror(errno), errno);
      lprintf(10, "read\n");
        ret = read(devices_fd, buf, sizeof(buf)-1);
      lprintf(10, "end read: %d\n", ret);
        if (ret == -1)
                lprintf(0, "read: %s (%d)\n", strerror(errno), errno);
        end = buf + ret;
        *end = 0;
        start = buf;
      while (start < end) {
                lineend = strchr(start, '\n');
                if (!lineend)
                        break;
                *lineend = 0;
                switch (start[0]) {
                case 'T':  /* topology line */
                        if ((cp = strstr(start, "Dev#="))) {
                                devnum = strtoul(cp + 5, NULL, 0);
                        } else
                                devnum = 0;
                        if ((cp = strstr(start, "Bus="))) {
                                busnum = strtoul(cp + 4, NULL, 0);
                        } else
                                busnum = 0;
                        break;

                case 'P':
                        if ((cp = strstr(start, "Vendor="))) {
                                vendorid = strtoul(cp + 7, NULL, 16);
                        } else
                                vendorid = 0xffff;
                        if ((cp = strstr(start, "ProdID="))) {
                                productid = strtoul(cp + 7, NULL, 16);
                        } else
                                productid = 0xffff;
                  lprintf(5, "Device %u Bus %u Vendor ID %04x Product ID %04x\n", devnum, busnum, vendorid, productid);
                  if (vendorid != BAYCOMUSB_VENDORID ||
                            (productid != BAYCOMUSB_PRODUCTID_EMPTY &&
                             productid != BAYCOMUSB_PRODUCTID_FPGALD &&
                             productid != BAYCOMUSB_PRODUCTID_MODEM &&
                             productid != BAYCOMUSB_PRODUCTID_AUDIO))
                        break;
                  /* search device; mark and continue if found */
                  pthread_mutex_lock(&devlist_mutex);
                  for (list = devices_list.next; list != &devices_list; list = list->next) {
                        state = list_entry(list, struct trx_thread_state, device_list);
                        if (state->devnr != devnum || state->busnr != busnum)
                              continue;
                        goto devalreadyfound;
                  }
                  /* not found, make new device and create thread */
                  state = malloc(sizeof(struct trx_thread_state));
                  if (!state)
                        goto err;
                  memset(state, 0, sizeof(struct trx_thread_state));
                  state->devnr = devnum;
                  state->busnr = busnum;
                  /* start thread */
                  if (pthread_attr_init(&attr))
                        goto err;
                  if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
                        goto err;
                  if (pthread_create(&thr, &attr, thread_start, state))
                        goto err;
                  pthread_attr_destroy(&attr);
                  list_add(&state->device_list, &devices_list);
              devalreadyfound:
                  pthread_mutex_unlock(&devlist_mutex);
                  break;

              err:
                  if (state)
                        free(state);
                  pthread_mutex_unlock(&devlist_mutex);
                  break;

                default:
                        break;
                }
#if 0
                printf("line: %s\n", start);
#endif
                start = lineend + 1;
        }

}

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

static void orb_add_connection(GIOPConnection *cnx)
{
      struct orbfdlist *ofd;

      if (!(cnx->user_data = ofd = malloc(sizeof(struct orbfdlist))))
            return;
      ofd->conn = cnx;
      ofd->pfd = NULL;
      list_add(&ofd->list, &orb_fds);
}

static void orb_remove_connection(GIOPConnection *cnx)
{
      struct orbfdlist *ofd = cnx->user_data;

      if (!ofd)
            return;
      ofd->conn = NULL;
}

#define MAXPFD 64

static void mainloop(void)
{
      struct list_head *list;
      struct orbfdlist *ofd;
      struct pollfd *pfd;
      struct pollfd pfds[MAXPFD];
      unsigned int npfd;
      int i;

      while (!quit) {
            npfd = 1;
            pfds[0].fd = devices_fd;
            pfds[0].events = POLLIN;
            acquire_orbit_mutex();
            for (list = orb_fds.next; list != &orb_fds;) {
                  ofd = list_entry(list, struct orbfdlist, list);
                  list = list->next;
                  if (!ofd->conn) {
                        list_del(&ofd->list);
                        free(ofd);
                        continue;
                  }
                  if (npfd >= MAXPFD) {
                        ofd->pfd = NULL;
                        continue;
                  }
                  ofd->pfd = &pfds[npfd++];
                  ofd->pfd->fd = GIOP_CONNECTION_GET_FD(ofd->conn);
                  ofd->pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLNVAL;
            }
            release_orbit_mutex();
            i = poll(pfds, npfd, -1);
            if (i == -1 && errno != EINTR) {
                  lprintf(0, "poll: %s (%u)\n", strerror(errno), errno);
                  exit(1);
            }
            if (pfds[0].revents & POLLIN)
                  check_new_uninited_modems();
            acquire_orbit_mutex();
            for (list = orb_fds.next; list != &orb_fds; list = list->next) {
                  ofd = list_entry(list, struct orbfdlist, list);
                  if (!(pfd = ofd->pfd))
                        continue;
#if 0
                  printf("fd %d events 0x%x revents 0x%x\n", pfd->fd, pfd->events, pfd->revents);
#endif
                  if (pfd->revents & (POLLERR | POLLHUP | POLLNVAL) && ofd->conn) {
                        giop_main_handle_connection_exception(ofd->conn);
                  }
                  if (pfd->revents & (POLLIN | POLLPRI) && ofd->conn) {
                        giop_main_handle_connection(ofd->conn);
                  }
            }
            release_orbit_mutex();
      }
}

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

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

static int parsehwpath(struct full_sockaddr_ax25 *fsa, const char *cp)
{
      char tmp[128];
      char *cp2, *ptrptr;

      if (!fsa || !cp || !*cp)
            return 0;
      fsa->fsa_ax25.sax25_family = AF_AX25;
      fsa->fsa_ax25.sax25_ndigis = 0;
      strncpy(tmp, cp, sizeof(tmp));
      cp2 = strtok_r(tmp, " \t\n,", &ptrptr);
      if (!parsehw(&fsa->fsa_ax25.sax25_call, cp2))
            return 0;
      while ((cp2 = strtok_r(NULL, " \t\n,", &ptrptr))) {
            if (fsa->fsa_ax25.sax25_ndigis >= AX25_MAX_DIGIS)
                  return 1;
            if (!parsehw(&fsa->fsa_digipeater[fsa->fsa_ax25.sax25_ndigis], cp2))
                  return 0;
            fsa->fsa_ax25.sax25_ndigis++;
      }
      return 1;
}

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

static int set_intf(struct trx_thread_state *state)
{
      struct sockaddr_ax25 sax25;
        struct sockaddr_in sin;
        struct ifreq ifr;
      struct arpreq arpreq;
      struct rtentry rtentry;
      struct full_sockaddr_ax25 gwpath;
        struct ax25_routes_struct ax25_route;
        struct ax25_route_opt_struct ax25_opt;
      int fd;

        if (state->mode != MODE_FSK && state->mode != MODE_EXTERNAL && state->mode != MODE_AFSK)
                return 0;
      strncpy(ifr.ifr_name, state->ifname, sizeof(ifr.ifr_name));
#ifdef HAVE_IFRNEWNAME
      if (state->cfg.intf.ifname[0] && strcmp(state->cfg.intf.ifname, state->ifname)) {
            strncpy(ifr.ifr_newname, state->cfg.intf.ifname, sizeof(ifr.ifr_newname));
            if (ioctl(sock_fd, SIOCSIFNAME, &ifr) == -1) {
                  lprintf(1, "Cannot rename interface (SIOCSIFNAME: %s (%u))\n", strerror(errno), errno);
                  netif_close(state);
                  if (netif_open(state))
                        return -1;
            } else {
                  strncpy(state->ifname, ifr.ifr_newname, sizeof(state->ifname));
                  strncpy(ifr.ifr_name, state->ifname, sizeof(ifr.ifr_name));
            }
      }
#endif
      if (ioctl(sock_fd, SIOCGIFINDEX, &ifr) == -1)
            lprintf(1, "ioctl: SIOCGIFINDEX failed: %s (%u)\n", strerror(errno), errno);
      ifr.ifr_mtu = 256;
      if (ioctl(sock_fd, SIOCSIFMTU, &ifr) == -1)
            lprintf(1, "ioctl: SIOCSIFMTU failed: %s (%u)\n", strerror(errno), errno);
      if (parsehw(&sax25.sax25_call, state->cfg.intf.hwaddr)) {
                sax25.sax25_family = AF_AX25;
                sax25.sax25_ndigis = 0;
                memcpy(&ifr.ifr_hwaddr, &sax25, sizeof(ifr.ifr_hwaddr));
                if (ioctl(sock_fd, SIOCSIFHWADDR, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFHWADDR failed: %s (%u)\n", strerror(errno), errno);
      }
      sin.sin_addr.s_addr = (state->cfg.intf.ipaddr[3] << 24) | (state->cfg.intf.ipaddr[2] << 16) |
            (state->cfg.intf.ipaddr[1] << 8) | state->cfg.intf.ipaddr[0];
      if (sin.sin_addr.s_addr != INADDR_ANY && sin.sin_addr.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
            if (ioctl(sock_fd, SIOCSIFADDR, &ifr) == -1)
                  lprintf(1, "ioctl: SIOCSIFADDR failed: %s (%u)\n", strerror(errno), errno);
      }
      sin.sin_addr.s_addr = (state->cfg.intf.netmask[3] << 24) | (state->cfg.intf.netmask[2] << 16) |
            (state->cfg.intf.netmask[1] << 8) | state->cfg.intf.netmask[0];
      if (sin.sin_addr.s_addr != INADDR_ANY && sin.sin_addr.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
            if (ioctl(sock_fd, SIOCSIFNETMASK, &ifr) == -1)
                  lprintf(1, "ioctl: SIOCSIFNETMASK failed: %s (%u)\n", strerror(errno), errno);
      }
      sin.sin_addr.s_addr = (state->cfg.intf.broadcast[3] << 24) | (state->cfg.intf.broadcast[2] << 16) |
            (state->cfg.intf.broadcast[1] << 8) | state->cfg.intf.broadcast[0];
      if (sin.sin_addr.s_addr != INADDR_ANY && sin.sin_addr.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
            if (ioctl(sock_fd, SIOCSIFBRDADDR, &ifr) == -1)
                  lprintf(1, "ioctl: SIOCSIFBRDADDR failed: %s (%u)\n", strerror(errno), errno);
      }
        if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
            if (ioctl(sock_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(sock_fd, SIOCSIFFLAGS, &ifr) == -1)
                        lprintf(0, "ioctl: SIOCSIFFLAGS failed: %s (%u)\n", strerror(errno), errno);
            }
      }
      /* set gateway ARP etc */
      if (!state->cfg.intf.gwipaddr[0] && !state->cfg.intf.gwipaddr[1] &&
          !state->cfg.intf.gwipaddr[2] && !state->cfg.intf.gwipaddr[3])
            return 0;
      if (!parsehwpath(&gwpath, state->cfg.intf.gwhwaddr))
            return 0;
      /* get interface address */
      if (ioctl(sock_fd, SIOCGIFHWADDR, &ifr) == -1) {
            lprintf(0, "ioctl: SIOCSIFHWADDR failed: %s (%u)\n", strerror(errno), errno);
            return 0;
      }
      memcpy(&sax25, &ifr.ifr_hwaddr, sizeof(sax25));
      if (sax25.sax25_family != AF_AX25) {
            lprintf(0, "ioctl: SIOCSIFHWADDR invalid address family: %u\n", sax25.sax25_family);
            return 0;
      }
      sin.sin_addr.s_addr = (state->cfg.intf.gwipaddr[3] << 24) | (state->cfg.intf.gwipaddr[2] << 16) |
            (state->cfg.intf.gwipaddr[1] << 8) | state->cfg.intf.gwipaddr[0];
      if (sin.sin_addr.s_addr == INADDR_ANY || sin.sin_addr.s_addr == INADDR_NONE)
            return 0;
      sin.sin_family = AF_INET;
      arpreq.arp_flags = ATF_COM | ATF_PERM;
      ((struct sockaddr_in *)&arpreq.arp_pa)->sin_family = AF_INET;
      ((struct sockaddr_in *)&arpreq.arp_pa)->sin_port = 0;
      ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr = sin.sin_addr;
      memcpy(&arpreq.arp_ha, &gwpath, sizeof(arpreq.arp_ha));
      ((struct sockaddr_ax25 *)&arpreq.arp_ha)->sax25_ndigis = 0;
      strncpy(arpreq.arp_dev, state->ifname, sizeof(arpreq.arp_dev));
      if (ioctl(sock_fd, SIOCSARP, &arpreq))
            lprintf(0, "ioctl: SIOCSARP failed: %s (%u)\n", strerror(errno), errno);
      if ((fd = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) {
            lprintf(0, "socket: AF_AX25,SOCK_SEQPACKET failed: %s (%u)\n", strerror(errno), errno);
            return 0;
      }
      ax25_route.port_addr = sax25.sax25_call;
      ax25_route.dest_addr = gwpath.fsa_ax25.sax25_call;
      ax25_route.digi_count = gwpath.fsa_ax25.sax25_ndigis;
      memcpy(&ax25_route.digi_addr, &gwpath.fsa_digipeater, sizeof(ax25_route.digi_addr));
      if (ioctl(fd, SIOCADDRT, &ax25_route) != 0)
            lprintf(0, "ioctl: SIOCADDRT (ax25) failed: %s (%u)\n", strerror(errno), errno);
      ax25_opt.port_addr = sax25.sax25_call;
      ax25_opt.dest_addr = gwpath.fsa_ax25.sax25_call;
      ax25_opt.cmd = AX25_SET_RT_IPMODE;
      ax25_opt.arg = state->cfg.intf.gwipmode;
      if (ioctl(fd, SIOCAX25OPTRT, &ax25_opt) != 0)
            lprintf(0, "ioctl: SIOCAX25OPTRT failed: %s (%u)\n", strerror(errno), errno);
      close(fd);
      memset(&rtentry, 0, sizeof(rtentry));
      rtentry.rt_flags = RTF_UP | RTF_GATEWAY;
      ((struct sockaddr_in *)&rtentry.rt_dst)->sin_family = AF_INET;
      ((struct sockaddr_in *)&rtentry.rt_dst)->sin_port = 0;
      ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr = sin.sin_addr;
      ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_family = AF_INET;
      ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_port = 0;
      ((struct sockaddr_in *)&rtentry.rt_gateway)->sin_addr = sin.sin_addr;
      sin.sin_addr.s_addr = (state->cfg.intf.gwnetmask[3] << 24) | (state->cfg.intf.gwnetmask[2] << 16) |
            (state->cfg.intf.gwnetmask[1] << 8) | state->cfg.intf.gwnetmask[0];
      if (sin.sin_addr.s_addr != INADDR_ANY && sin.sin_addr.s_addr != INADDR_NONE) {
            ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_family = AF_INET;
            ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_port = 0;
            ((struct sockaddr_in *)&rtentry.rt_genmask)->sin_addr = sin.sin_addr;
            ((struct sockaddr_in *)&rtentry.rt_dst)->sin_addr.s_addr &= sin.sin_addr.s_addr;
      } else
            rtentry.rt_flags |= RTF_HOST;
      rtentry.rt_dev = state->ifname;
      if (ioctl(sock_fd, SIOCADDRT, &rtentry) != 0)
            lprintf(0, "ioctl: SIOCADDRT (ipv4) failed: %s (%u)\n", strerror(errno), errno);
      return 0;
}

static void set_chacc(struct trx_thread_state *state)
{
      struct sockaddr sa;
      unsigned char buf[2];

        if (state->mode != MODE_FSK && state->mode != MODE_EXTERNAL && state->mode != MODE_AFSK)
                return;
      strncpy(sa.sa_data, state->ifname, sizeof(sa.sa_data));
      sa.sa_family = AF_PACKET;
      buf[0] = PARAM_TXDELAY;
      buf[1] = state->cfg.chacc.txdelay / 10;
      if (sendto(sock_fd, buf, 2, 0, &sa, sizeof(struct sockaddr)) == -1)
            lprintf(1, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_PERSIST;
      buf[1] = state->cfg.chacc.ppersistence;
      if (sendto(sock_fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(1, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_SLOTTIME;
      buf[1] = state->cfg.chacc.slottime / 10;
      if (sendto(sock_fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(1, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_TXTAIL;
      buf[1] = state->cfg.chacc.txtail / 10;
      if (sendto(sock_fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(1, "sendto failed: %s (%u)\n", strerror(errno), errno);
      buf[0] = PARAM_FULLDUP;
      buf[1] = state->cfg.chacc.fullduplex;
      if (sendto(sock_fd, buf, 2, 0, &sa, sizeof(sa)) == -1)
            lprintf(1, "sendto failed: %s (%u)\n", strerror(errno), errno);
}

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

#define SCRIPTNAME "/etc/ax25/baycomusb.ifchange"

static void runscript(struct trx_thread_state *state, const char *cmd)
{
      pid_t pid;
      char home[128];
      char ifname[64];
      char hwaddr[64];
      char ipaddr[64];
      char netmask[64];
      char broadcast[64];
      char gwhwaddr[192];
      char gwipaddr[64];
      char gwnetmask[64];
      char gwipmode[64];
      char *cp;
      char *const argv[] = { SCRIPTNAME, cmd, NULL };
      char *const envp[] = { "TERM=linux", home, ifname, hwaddr, ipaddr, netmask, broadcast,
                         gwhwaddr, gwipaddr, gwnetmask, gwipmode, NULL };
      
      return;

      lprintf(4, "Running Script: %s\n", cmd);
      pid = fork();
      if (pid) {
            if (pid != -1)
                  return;
            lprintf(1, "fork failed: %s (%u)\n", strerror(errno), errno);
            return;
      }
      cp = getenv("HOME");
      snprintf(home, sizeof(home), "HOME=%s", cp ? cp : "/");
      snprintf(ifname, sizeof(ifname), "IFNAME=%s", state->ifname);
      snprintf(hwaddr, sizeof(hwaddr), "HWADDR=%s", state->cfg.intf.hwaddr);
      snprintf(ipaddr, sizeof(ipaddr), "IPADDR=%u.%u.%u.%u", state->cfg.intf.ipaddr[0], state->cfg.intf.ipaddr[1],
             state->cfg.intf.ipaddr[2], state->cfg.intf.ipaddr[3]);
      snprintf(netmask, sizeof(netmask), "NETMASK=%u.%u.%u.%u", state->cfg.intf.netmask[0], state->cfg.intf.netmask[1],
             state->cfg.intf.netmask[2], state->cfg.intf.netmask[3]);
      snprintf(broadcast, sizeof(broadcast), "BROADCAST=%u.%u.%u.%u", state->cfg.intf.broadcast[0], state->cfg.intf.broadcast[1],
             state->cfg.intf.broadcast[2], state->cfg.intf.broadcast[3]);
      snprintf(gwhwaddr, sizeof(gwhwaddr), "GWHWADDR=%s", state->cfg.intf.gwhwaddr);
      snprintf(gwipaddr, sizeof(gwipaddr), "GWIPADDR=%u.%u.%u.%u", state->cfg.intf.gwipaddr[0], state->cfg.intf.gwipaddr[1],
             state->cfg.intf.gwipaddr[2], state->cfg.intf.gwipaddr[3]);
      snprintf(gwnetmask, sizeof(gwnetmask), "GWNETMASK=%u.%u.%u.%u", state->cfg.intf.gwnetmask[0], state->cfg.intf.gwnetmask[1],
                   state->cfg.intf.gwnetmask[2], state->cfg.intf.gwnetmask[3]);
      snprintf(gwipmode, sizeof(gwipmode), "GWIPMODE=%c", state->cfg.intf.gwipmode);
      execve(SCRIPTNAME, argv, envp);
      lprintf(4, "execve("SCRIPTNAME") failed: %s (%u)\n", strerror(errno), errno);
}

void netif_close(struct trx_thread_state *state)
{
      if (state->netif_fd != -1)
            close(state->netif_fd);
      state->netif_fd = -1;
      runscript(state, "down");
}

int netif_open(struct trx_thread_state *state)
{
      struct baycomusb_startnetdev stn;
      unsigned char br[6];
      int r;
      
      if (state->netif_fd != -1)
            close(state->netif_fd);
      state->netif_fd = -1;
      if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL ||
          state->mode == MODE_AFSK) {
            r = usb_control_msg(state->usbdev, 0xc0, 0xd1, 0, 0, 6, br, 100);
            if (r != 6) {
                  lprintf(1, "Error while reading adapter bitrate\n");
                  return -1;
            }
            state->bitratetx = br[0] | (br[1] << 8) | (br[2] << 16);
            state->bitraterx = br[3] | (br[4] << 8) | (br[5] << 16);
            state->txdmul = (state->bitratetx + 799) / 800;
            lprintf(5, "Adapter %s bitrate %u/%u\n",
                  state->serial, state->bitraterx, state->bitratetx);
      } else
            state->bitraterx = state->bitratetx = state->txdmul = 0;
      if ((state->netif_fd = open(NETIFMUXDEV, O_RDWR)) == -1) {
            lprintf(1, "Cannot open " NETIFMUXDEV "\n");
            return -1;
      }
      stn.busnr = state->busnr;
      stn.devnr = state->devnr;
      strncpy(stn.ifname, state->cfg.intf.ifname, sizeof(stn.ifname));
      if (!stn.ifname[0])
            strncpy(stn.ifname, "bcu0", sizeof(stn.ifname));
      if (ioctl(state->netif_fd, BAYCOMUSB_STARTNETDEV, &stn)) {
            lprintf(1, "ioctl: BAYCOMUSB_STARTNETDEV: error %s (%d)\n", strerror(errno), errno);
            close(state->netif_fd);
            state->netif_fd = -1;
            return -1;
      }
      strncpy(state->ifname, stn.ifname, sizeof(state->ifname));
      if (set_intf(state))
            return -1;
      runscript(state, "up"); 
      return 0;
}

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

#if 0

static int bcusbioctl(struct trx_thread_state *ctrl, int cmd, void *data)
{
        struct ifreq ifr;

        if (!ctrl)
                return -1;
        strncpy(ifr.ifr_name, ctrl->ifname, sizeof(ifr.ifr_name));
        ifr.ifr_data = data;
        *((int *)data) = cmd;
        return ioctl(sock_fd, SIOCDEVPRIVATE, &ifr);
}

#else

static int bcusbioctl(struct trx_thread_state *ctrl, int cmd, void *data)
{
        if (!ctrl)
                return -1;
        return ioctl(ctrl->netif_fd, cmd, data);
}

#endif

static int periodic(struct trx_thread_state *state)
{
        struct baycomusb_status b;
        struct baycomusb_receiveuart ruart;
        struct baycomusb_transmituart tuart;
      struct baycomusb_forceptt bforceptt;
        struct baycomusb_modemdisc bmdisc;
        struct baycomusb_t7fcontrol bt7f;
        struct baycomusb_setleds bleds;
      
      if (bcusbioctl(state, BAYCOMUSB_GETSTATUS, &b))
                return -1;
      state->ptt = b.ptt;
      state->dcd = b.dcd;
      state->rssi = b.rssi;
      if (b.uartchars) {
            if (!bcusbioctl(state, BAYCOMUSB_RECEIVEUART, &ruart))
                  addrxfifo(state, ruart.buffer, ruart.len);
      }
      if (state->tfifo.rd != state->tfifo.wr) {
            tuart.txchar = state->tfifo.buf[state->tfifo.rd];
            if (!bcusbioctl(state, BAYCOMUSB_TRANSMITUART, &tuart)) {
                  state->tfifo.rd = (state->tfifo.rd + 1) % sizeof(state->tfifo.buf);
            }
      }
      if (state->flags & FLG_CLRPTT) {
            state->flags &= ~FLG_CLRPTT;
            bforceptt.ptt = 0;
            goto setptt;
      }
      if (state->flags & FLG_SETPTT && !(state->flags & FLG_INHIBITSETPTT)) {
            state->flags &= ~FLG_SETPTT;
            bforceptt.ptt = (state->flags & FLG_MANUALPTT) ? 1 : 0;
        setptt:
            if (bcusbioctl(state, BAYCOMUSB_FORCEPTT, &bforceptt))
                  lprintf(1, "USB device %03d:%03d: failed to set ptt\n", state->busnr, state->devnr);
      }
      if (state->flags & FLG_RECONFINTF) {
            state->flags &= ~FLG_RECONFINTF;
            if (set_intf(state))
                  return -1;
      }
      if (state->flags & FLG_RECONFCHACC) {
            state->flags &= ~FLG_RECONFCHACC;
            set_chacc(state);
      }
      if (state->flags & (FLG_SETMDISCDIR | FLG_SETMDISCOUT)) {
            state->flags &= ~(FLG_SETMDISCDIR | FLG_SETMDISCOUT);
            bmdisc.setdirection = state->cfg.mdisc.direction;
            bmdisc.setoutput = state->cfg.mdisc.output;
            /* enable RxC, TxC or TxD outputs if special output mode is selected */
            if (state->mode == MODE_FSK) {
                  if (state->cfg.mdisc.rxc)
                        bmdisc.setdirection &= ~(1 << 0);
                  if (state->cfg.mdisc.txc)
                        bmdisc.setdirection &= ~(1 << 1);
                  if (state->cfg.mdisc.txd)
                        bmdisc.setdirection &= ~(1 << 3);
            }
            if (bcusbioctl(state, BAYCOMUSB_MODEMDISC, &bmdisc))
                  lprintf(1, "USB device %03d:%03d: failed to set modem disconnect port\n", state->busnr, state->devnr);
      }
      if (state->flags & FLG_SETT7FPORT) {
            state->flags &= ~FLG_SETT7FPORT;
            bt7f.setoutput = state->t7fport;
            if (bcusbioctl(state, BAYCOMUSB_T7FCONTROL, &bt7f))
                  lprintf(1, "USB device %03d:%03d: failed to set T7F control port\n", state->busnr, state->devnr);
      }
      if (state->flags & FLG_SETLEDS) {
            state->flags &= ~FLG_SETLEDS;
            bleds.leds = state->leds;
            if (bcusbioctl(state, BAYCOMUSB_SETLEDS, &bleds))
                  lprintf(1, "USB device %03d:%03d: failed to set LEDS\n", state->busnr, state->devnr);
      }
      return 0;
}

int polldevice(struct trx_thread_state *state)
{
      int r;

      usleep(25000);
      acquire_trxdata_mutex(state);
      r = periodic(state);
      release_trxdata_mutex(state);
      return r;
}

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

int getuartline(struct trx_thread_state *ctrl, unsigned int *ptr, unsigned char *buf, size_t bufsz, unsigned int timeout)
{
        unsigned int cpy = 0, tdiff, reload;
        struct timeval tv1, tv2;

        if (!ctrl)
                return -1;
        if (gettimeofday(&tv1, NULL))
                return -1;
      timeout *= 1000;
        while (cpy < bufsz) {
            acquire_trxdata_mutex(ctrl);
            if (buf) {
                  while (cpy < bufsz && getrxfifo(ctrl, ptr, buf, 1) == 1) {
                        if (*buf == '\r' || *buf == '\n') {
                              cpy++;
                              *buf++ = '\n';
                              *buf = 0;
                              release_trxdata_mutex(ctrl);
                              return cpy;
                        }
                        cpy++;
                        buf++;
                  }
            }
            if (periodic(ctrl)) {
                  release_trxdata_mutex(ctrl);
                        return -1;
            }
            reload = ctrl->flags & FLG_RELOADMODEM;
            release_trxdata_mutex(ctrl);
            if (reload)
                  break;
                if (gettimeofday(&tv2, NULL))
                        break;
                tdiff = 1000000 * (tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec;
                if (tdiff > timeout)
                  break;
                usleep(25000);
        }
      if (buf)
            *buf = 0;
        return cpy;
}

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

struct trxapi_baycomusb_adapter_audio_devs *audio_get_device_list(void)
{
      return NULL;
}

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

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

static void signal_child(int signum, siginfo_t *info, void *dummy)
{
      int status;
      struct rusage rusage;

      if (info->si_code == CLD_STOPPED || info->si_code == CLD_CONTINUED)
            return;
      wait4(-1, &status, WNOHANG, &rusage);
}

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

int main (int argc, char *argv[])
{
        static const struct option long_options[] = {
                { "drv", 1, 0, 'D' },
                { "config", 1, 0, 'C' },
            { "daemonize", 0, 0, 'd' },
                { "verbose", 0, 0, 'v' },
                { "help", 0, 0, 'h' },
                { 0, 0, 0, 0 }
        };
        int c, err = 0;
      unsigned int daemonize = 0;
      char devname[256] = "/proc/bus/usb/devices";
      const char *cfgfile = NULL;
      CORBA_Environment ev;
        int pfds[2];
        pid_t pid;
        unsigned char uch;
      struct sigaction sigact;

        printf("baycomusbserv v" VERSION " (c) 1999-2001 by Thomas Sailer, HB9JNX/AE4WA\n");
      /* init custom IO handlers */
      IIOPAddConnectionHandler = orb_add_connection;
        IIOPRemoveConnectionHandler = orb_remove_connection;
      if (server_init1(&argc, argv))
            return -1;
      while ((c = getopt_long(argc, argv, "D:C:sv:d", long_options, NULL)) != EOF) {
                switch (c) {
                case 'D':
                        usb_setmountpoint(optarg);
                  snprintf(devname, sizeof(devname), "%s/devices", optarg);
                        break;

                case 'C':
                        cfgfile = 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 'd':
                  daemonize = 1;
                  break;

                case 'v':
                        verboselevel = strtoul(optarg, NULL, 0);
                        break;

                default:
                        err++;
                        break;
                }
        }
        if (err) {
                lprintf(0, "usage: %s [-v <vl>] [-D <drvpath>] [-C <configfile>]\n", argv[0]);
            exit(1);
        }
        if (daemonize) {
                if (pipe(pfds)) {
                        lprintf(0, "pipe error %s (%u)", strerror(errno), errno);
                  exit(1);
            }
                switch (pid = fork()) {
                case -1:
                        lprintf(0, "fork error %s (%u)", strerror(errno), errno);
                  exit(1);
                  
                case 0: /* child process */
                        close(pfds[0]);
                        setsid(); /* become a process group leader and drop controlling terminal */
                        fclose(stdin); /* no more standard in */
                        break;
                        
                default: /* parent process */
                        close(pfds[1]);
                        err = read(pfds[0], &uch, sizeof(uch));
                        if (err != sizeof(uch)) {
                                lprintf(0, "baycomusbserv init failed\n");
                        _exit(1);
                  }
                  /* need to run _exit, otherwise ORBit inadvertedly kills some needed stuff */
                        _exit(0);
                }
        }
        if (config_load(cfgfile))
            exit(1);
      if ((devices_fd = open(devname, 0)) == -1) {
            lprintf(0, "Cannot open %s, usbdevfs not mounted?\n", devname);
            exit(1);
      }
      sigact.sa_handler = signal_quit;
      sigemptyset(&sigact.sa_mask);
      sigact.sa_flags = SA_RESTART;
#ifdef SIGHUP
        sigaction(SIGHUP, &sigact, NULL);
#endif
        sigaction(SIGINT, &sigact, NULL);
#ifdef SIGQUIT
        sigaction(SIGQUIT, &sigact, NULL);
#endif
        sigaction(SIGTERM, &sigact, NULL);
      sigact.sa_sigaction = signal_child;
      sigemptyset(&sigact.sa_mask);
      sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
        sigaction(SIGCHLD, &sigact, NULL);
        if (daemonize) {
                uch = 0;
                if (write(pfds[1], &uch, sizeof(uch)) != sizeof(uch)) {
                        lprintf(0, "write error %s (%u)", strerror(errno), errno);
                  exit(1);
            }
                close(pfds[1]);
        }
      if ((sock_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);
            exit(1);;
      }
      if (server_init2())
            return 1;
      mainloop();
      config_save();
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index