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

drvinit.c

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

/*
 *      drvinit.c  -- HDLC packet radio modem for EPP/ECP using FPGA usermode driver.
 *                    Init code (discarded at runtime).
 *
 *      Copyright (C) 1998-2000  Thomas Sailer (sailer@ife.ee.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

#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <stdarg.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>

#ifdef HAVE_LINUX_IF_H
#include <linux/if.h>
#elif defined(HAVE_NET_IF_H)
#include <net/if.h>
#endif

#ifdef HAVE_SCHED_H
#include <sched.h>
#endif

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

#ifdef HAVE_PTY_H
#include <pty.h>
#else
extern int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct  winsize *winp);
#endif

#include "drv.h"
#include "parport.h"
#include "fpga.h"

#ifdef HAVE_MKISS
#include <sys/socket.h>
/* glibc2.0 does not have sockaddr_ax25, ifr.ifr_newname and SIOCSIFNAME */
#include <linux/ax25.h>
#include <linux/sockios.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

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

#define PIDFILE LOCALSTATEDIR "/run/baycomepp.pid"

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

static unsigned verboselevel = 0;

#ifdef HAVE_MKISS

struct ifconfig {
      char ifname[IFNAMSIZ];
      ax25_address hwaddr;
      struct in_addr ipaddr, netmask, broadcast;
};

#define IFCONFIGINIT { "", { "" }, { INADDR_NONE }, { INADDR_NONE }, { INADDR_NONE } }

#else /* !HAVE_MKISS */

struct ifconfig {
      char ifname[PATH_MAX];
};

#define IFCONFIGINIT { "" }

#endif /* !HAVE_MKISS */

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

int lprintf(unsigned vl, const char *format, ...)
{
        static const int logprio[] = { LOG_ERR, LOG_INFO };
        va_list ap;
        int r = 0;

        if (vl > verboselevel)
                return 0;
      va_start(ap, format);
      if (logging)
            vsyslog((vl > 1) ? LOG_DEBUG : logprio[vl], format, ap);
      else {
            r = fprintf(stderr, "baycomepp[%u]: ", getpid());
            r += vfprintf(stderr, format, ap);
      }
      va_end(ap);
        return r;
}

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)
{
      return 1;
}

/* --------------------------------------------------------------------- */
#ifdef HAVE_MKISS

static inline void ifconfigure(struct ifconfig *cfg)
{
      int master, slave, fd, disc = N_AX25, encap = 4;
      char mbuf[512], *mptr = mbuf;
      struct sockaddr_ax25 sax25;
      struct sockaddr_in sin;
      struct termios tm;
        struct ifreq ifr;
      unsigned i;

      openpty(&master, &slave, NULL, NULL, NULL);
      /* set pty/tty pair to raw */
      memset(&tm, 0, sizeof(tm));
      tm.c_cflag = CS8 | CREAD | CLOCAL;
      if (tcsetattr(master, TCSANOW, &tm))
            errstr(SEV_WARNING, "master: tcsetattr");
      memset(&tm, 0, sizeof(tm));
      tm.c_cflag = CS8 | CREAD | CLOCAL;
      if (tcsetattr(slave, TCSANOW, &tm))
            errstr(SEV_WARNING, "slave: tcsetattr");
        if (ioctl(master, TIOCSETD, &disc) == -1)
                errstr(SEV_FATAL, "ioctl: TIOCSETD");
      if (ioctl(master, SIOCGIFNAME, ifr.ifr_name) == -1)
                errstr(SEV_FATAL, "ioctl: SIOCGIFNAME");
        if (ioctl(master, SIOCSIFENCAP, &encap) == -1)
                errstr(SEV_FATAL, "ioctl: SIOCSIFENCAP");
      /* configure interface */
        if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
                errstr(SEV_FATAL, "socket");
#ifdef HAVE_IFRNEWNAME
      if (cfg->ifname[0]) {
            strncpy(ifr.ifr_newname, cfg->ifname, sizeof(ifr.ifr_newname));
            if (ioctl(fd, SIOCSIFNAME, &ifr) == -1) {
                  errstr(SEV_WARNING, "ioctl: SIOCSIFNAME");
                  errprintf(SEV_WARNING, "baycomepp: cannot set ifname to %s, using %s (old kernel version?)\n",
                          cfg->ifname, ifr.ifr_name);
            } else {
                  memcpy(ifr.ifr_name, ifr.ifr_newname, sizeof(ifr.ifr_name));
            }
      }
#endif /* HAVE_IFRNEWNAME */
      mptr += sprintf(mptr, "ifname %s mtu 256", ifr.ifr_name);
      ifr.ifr_mtu = 256;
        if (ioctl(fd, SIOCSIFMTU, &ifr) < 0)
                errstr(SEV_FATAL, "ioctl: SIOCSIFMTU");
      if (cfg->hwaddr.ax25_call[0]) {
            sax25.sax25_family = AF_AX25;
            memcpy(&sax25.sax25_call, &cfg->hwaddr, sizeof(sax25.sax25_call));
            sax25.sax25_ndigis = 0;
            memcpy(&ifr.ifr_hwaddr, &sax25, sizeof(ifr.ifr_hwaddr));
            if (ioctl(fd, SIOCSIFHWADDR, &ifr) == -1)
                  errstr(SEV_WARNING, "ioctl: SIOCSIFHWADDR");
            else {
                  mptr += sprintf(mptr, " hwaddr ");
                  for (i = 0; i < 6; i++)
                        if (sax25.sax25_call.ax25_call[i] != (' ' << 1))
                              *mptr++ = (sax25.sax25_call.ax25_call[i] >> 1) & 0x7f;
                  mptr += sprintf(mptr, "-%d", (sax25.sax25_call.ax25_call[6] >> 1) & 0x7f);
            }
      }
      if (cfg->ipaddr.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            sin.sin_addr = cfg->ipaddr;
            memcpy(&ifr.ifr_addr, &sin, sizeof(ifr.ifr_addr));
            if (ioctl(fd, SIOCSIFADDR, &ifr) == -1)
                  errstr(SEV_WARNING, "ioctl: SIOCSIFADDR");
            else
                  mptr += sprintf(mptr, " ipaddr %s", inet_ntoa(cfg->ipaddr));
      }
      if (cfg->netmask.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            sin.sin_addr = cfg->netmask;
            memcpy(&ifr.ifr_netmask, &sin, sizeof(ifr.ifr_netmask));
            if (ioctl(fd, SIOCSIFNETMASK, &ifr) == -1)
                  errstr(SEV_WARNING, "ioctl: SIOCSIFNETMASK");
            else
                  mptr += sprintf(mptr, " netmask %s", inet_ntoa(cfg->netmask));
      }
      if (cfg->broadcast.s_addr != INADDR_NONE) {
            sin.sin_family = AF_INET;
            sin.sin_addr = cfg->broadcast;
            memcpy(&ifr.ifr_broadaddr, &sin, sizeof(ifr.ifr_broadaddr));
            if (ioctl(fd, SIOCSIFBRDADDR, &ifr) == -1)
                  errstr(SEV_WARNING, "ioctl: SIOCSIFBRDADDR");
            else
                  mptr += sprintf(mptr, " broadcast %s", inet_ntoa(cfg->broadcast));
      }
        if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
                errstr(SEV_FATAL, "ioctl: SIOCGIFFLAGS");
        ifr.ifr_flags &= ~IFF_NOARP;
        ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
        if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
            printf("flags: 0x%x name %s\n", ifr.ifr_flags, ifr.ifr_name);
                errstr(SEV_FATAL, "ioctl: SIOCSIFFLAGS");
      }
        close(fd);
      /* prepare modem state etc. */
      state.kissfd = slave;
      /* don't close the master side! */
      fcntl(state.kissfd, F_SETFL, fcntl(state.kissfd, F_GETFL, 0) | O_NONBLOCK);
      errprintf(SEV_INFO, "baycomepp: %s\n", mbuf);
}

#else /* !HAVE_MKISS */

static inline void ifconfigure(struct ifconfig *cfg)
{
      int master, slave;
      struct termios tm;
      char ttyname[32];

      openpty(&master, &slave, ttyname, NULL, NULL);
      /* set pty/tty pair to raw */
      memset(&tm, 0, sizeof(tm));
      tm.c_cflag = CS8 | CREAD | CLOCAL;
      if (tcsetattr(master, TCSANOW, &tm))
            errstr(SEV_WARNING, "master: tcsetattr");
      memset(&tm, 0, sizeof(tm));
      tm.c_cflag = CS8 | CREAD | CLOCAL;
      if (tcsetattr(slave, TCSANOW, &tm))
            errstr(SEV_WARNING, "slave: tcsetattr");
      /* make link */
      if (cfg->ifname[0]) {
            //fchmod(slave, 0600);
            unlink(cfg->ifname);
            if (symlink(ttyname, cfg->ifname)) 
                  errprintf(SEV_WARNING, "baycomepp: symlink error: %s -> %s\n", ttyname, cfg->ifname);
      }
      /* prepare modem state etc. */
      state.kissfd = master;
      close(slave);
      /* don't close the master side! */
      fcntl(state.kissfd, F_SETFL, fcntl(state.kissfd, F_GETFL, 0) | O_NONBLOCK);
      errprintf(SEV_INFO, "baycomepp: starting AX.25 interface %s\n", cfg->ifname ? cfg->ifname : ttyname);
}

#endif /* !HAVE_MKISS */

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

static void write_pid(pid_t pid)
{
      FILE *f = fopen(PIDFILE, "a");
      if (!f) {
            errprintf(SEV_INFO, "cannot open PID file %s\n", PIDFILE);
            return;
      }
      fprintf(f, "%i\n", pid);
      fclose(f);
}

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

static void kill_baycomeppd(void)
{
      FILE *f = fopen(PIDFILE, "r");
      pid_t pid;

      if (!f) {
            errprintf(SEV_INFO, "cannot open PID file %s\n", PIDFILE);
            return;
      }
      while (fscanf(f, " %i \n", &pid) == 1) 
            if (pid <= 0 || pid == getpid())
                  errprintf(SEV_INFO, "invalid pid %i\n", pid);
            else {
                  kill(pid, SIGTERM);
                  errprintf(SEV_INFO, "terminating process %i\n", pid);
            }
      fclose(f);
      unlink(PIDFILE);
}

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

static void init(int mode)
{
      unsigned char eio[2048];
      u_int8_t stat;
      u_int8_t statecp[6];
      int cnt, icnt;
      struct timeval tv1, tv2;
      unsigned long usec;
      unsigned bytecnt = 0;

      /* we need this here so that the bitrate autoprobe works correctly */
      /*
       * set the process to realtime privs
       */
#ifdef HAVE_SCHED_H
      {
            struct sched_param schp;
            memset(&schp, 0, sizeof(schp));
            schp.sched_priority = sched_get_priority_min(SCHED_RR)+1;
#if 1
            if (sched_setscheduler(0, SCHED_RR, &schp) != 0)
                  errstr(SEV_ERROR, "sched_setscheduler");
#endif
      }
#endif /* HAVE_SCHED_H */
      /*
       * lock memory down
       */
      if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) 
            errstr(SEV_ERROR, "mlockall");
            switch(mode) {
      case MODE_EPP:
            if (adapter_start_epp(&state.config))
                  exit(1);
            /* reset modem */
            eio[0] = 0;
            eio[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
            if (parport_epp_write_addr(eio, 2) != 2)
                  goto errret;
            gettimeofday(&tv1, NULL);
            for (;;) {
                  if (parport_epp_read_addr(&stat, 1) != 1)
                        goto errret;
                  /* try to determine the FIFO count if in extended mode */
                  if (state.config.extstat) {
                        eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE|1;
                        if (parport_epp_write_addr(eio, 1) != 1)
                              goto errret;
                        if (parport_epp_read_addr(eio, 2) != 2)
                              goto errret;
                        icnt = eio[0] | (((unsigned int)eio[1]) << 8);
                        eio[0] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
                        if (parport_epp_write_addr(eio, 1) != 1)
                              goto errret;
                        icnt &= 0x7fff;
                  } else {
                        /* determine RX fifo size from status bits */
                        switch (stat & (EPP_NRAEF|EPP_NRHF)) {
                        case EPP_NRHF:
                              icnt = 0;
                              break;
                
                        case EPP_NRAEF:
                              icnt = 1025;
                              break;
                
                        case 0:
                              icnt = 1793;
                              break;
                
                        default:
                              icnt = 256;
                              break;
                        }
                  }
                  /* rx */
                  while (icnt > 0) {
                        cnt = icnt;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        icnt -= cnt;
                        bytecnt += cnt;
                        if (parport_epp_read_data(eio, cnt) != cnt)
                              goto errret;
                  }
                  gettimeofday(&tv2, NULL);
                  usec = ((60 + tv2.tv_sec - tv1.tv_sec) % 60) * 1000000 + tv2.tv_usec - tv1.tv_usec;
                  if (usec >= 500000)
                        break;
                  usleep(8000); /* must be more than 2ms, Linux busy-waits up to 2ms! */
            }
            break;

      case MODE_ECP:
            if (adapter_start_ecp(&state.config))
                  exit(1);
            eio[0] = 0xaf;  /* reset register: all reset */
            eio[1] = 0xa0;  /* reset register: terminate reset */
            eio[2] = 0xb0;
            if (parport_ecp_write_addr(eio, 3) != 3)
                  goto errret;
            gettimeofday(&tv1, NULL);
            for (;;) {
                  eio[0] = 0x81;
                  if (parport_ecp_write_addr(eio, 1) != 1)
                        goto errret;
                  if (parport_ecp_read_data(statecp, 6) != 6)
                        goto errret;
                  eio[0] = 0x80;
                  if (parport_ecp_write_addr(eio, 1) != 1)
                        goto errret;
                  icnt = ((unsigned)statecp[2] << 8) | statecp[1];
                  /* read */
                  while (icnt > 0) {
                        cnt = icnt;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        icnt -= cnt;
                        bytecnt += cnt;
                        eio[0] = 0xc0 | (cnt & 0xf);
                        eio[1] = 0xd0 | ((cnt >> 4) & 0xf);
                        eio[2] = 0xe0 | ((cnt >> 8) & 0xf);
                        if (parport_ecp_write_addr(eio, 3) != 3)
                              goto errret;
                        if (parport_ecp_read_data(eio, cnt) != cnt)
                              goto errret;
                  }
                  gettimeofday(&tv2, NULL);
                  usec = ((60 + tv2.tv_sec - tv1.tv_sec) % 60) * 1000000 + tv2.tv_usec - tv1.tv_usec;
                  if (usec >= 500000)
                        break;
                  usleep(8000); /* must be more than 2ms, Linux busy-waits up to 2ms! */
            }
            break;

      case MODE_EPPAFSK:
            state.config.bitrate = 1200;
            if (adapter_start_eppafsk(&state.config))
                  exit(1);
            /* reset modem */
            eio[0] = 0x00;
            eio[1] = 0x18;
            if (parport_epp_write_addr(eio, 2) != 2)
                  goto errret;
            gettimeofday(&tv1, NULL);
            for (;;) {
                  if (parport_epp_read_addr(&stat, 1) != 1)
                        goto errret;
                  /* determine the FIFO count */
                  eio[0] = 0x1a;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  if (parport_epp_read_addr(eio, 1) != 1)
                        goto errret;
                  icnt = eio[0] & 0x1f;
                  eio[0] = 0x18;
                  if (parport_epp_write_addr(eio, 1) != 1)
                        goto errret;
                  /* rx */
                  if (icnt > 0) {
                        if (parport_epp_read_data(eio, icnt) != icnt)
                              goto errret;
                        bytecnt += icnt;
                  }
                  gettimeofday(&tv2, NULL);
                  usec = ((60 + tv2.tv_sec - tv1.tv_sec) % 60) * 1000000 + tv2.tv_usec - tv1.tv_usec;
                  if (usec >= 500000)
                        break;
                  usleep(8000); /* must be more than 2ms, Linux busy-waits up to 2ms! */
            }
            break;

      case MODE_EPPCONV:
            /* reset modem */
            eio[0] = 0;
            eio[1] = EPP_TX_FIFO_ENABLE|EPP_RX_FIFO_ENABLE|EPP_MODEM_ENABLE;
            if (parport_epp_write_addr(eio, 2) != 2)
                  goto errret;
            gettimeofday(&tv1, NULL);
            for (;;) {
                  if (parport_epp_read_addr(&stat, 1) != 1)
                        goto errret;
                  /* try to determine the FIFO count if in extended mode */
                  /* determine RX fifo size from status bits */
                  switch (stat & (EPP_NRAEF|EPP_NRHF)) {
                  case EPP_NRHF:
                        icnt = 0;
                        break;
                        
                  case EPP_NRAEF:
                        icnt = 1025;
                        break;

                  case 0:
                        icnt = 1793;
                        break;
                        
                  default:
                        icnt = 256;
                        break;
                  }
                  /* rx */
                  while (icnt > 0) {
                        cnt = icnt;
                        if (cnt > sizeof(eio))
                              cnt = sizeof(eio);
                        icnt -= cnt;
                        bytecnt += cnt;
                        if (parport_epp_read_data(eio, cnt) != cnt)
                              goto errret;
                  }
                  gettimeofday(&tv2, NULL);
                  usec = ((60 + tv2.tv_sec - tv1.tv_sec) % 60) * 1000000 + tv2.tv_usec - tv1.tv_usec;
                  if (usec >= 500000)
                        break;
                  usleep(8000); /* must be more than 2ms, Linux busy-waits up to 2
                               ms! */
            }
            for (icnt = 0; icnt < 256; icnt++) {
                  if (parport_epp_read_addr(&stat, 1) != 1)
                        goto errret;
                  if (!(stat & EPP_NREF))
                        break;
                  if (parport_epp_read_data(eio, 1) != 1)
                        goto errret;
                  bytecnt++;
            }
            break;

      default:
            exit(1);
      }
      state.access.bitrate = (bytecnt * 8000000ULL + usec / 2ULL) / usec;
      state.access.bitrateby25 = (state.access.bitrate + 12) / 25;
      errprintf(SEV_INFO, "autoprobed bitrate: %u\n", state.access.bitrate);
      return;

errret:
      errprintf(SEV_FATAL, "Modem timeout\n");  
}

static void init2(struct ifconfig *ifcfg)
{
      ifconfigure(ifcfg);
      /*
       * sigusr1 is used to display the current state
       */
      if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
            errstr(SEV_ERROR, "signal");
      if (signal(SIGUSR2, sig_usr2) == SIG_ERR)
            errstr(SEV_ERROR, "signal");
      if (signal(SIGHUP, SIG_IGN) == SIG_ERR)
            errstr(SEV_ERROR, "signal");
      if (signal(SIGTERM, sighandler) == SIG_ERR)
            errstr(SEV_ERROR, "signal");
      /* start the modem */
      state.access.state = tx_idle;
      state.access.slotcnt = 1;
}

/* --------------------------------------------------------------------- */
/*
 * convert_call_entry is taken from the ax25 library
 */

static inline int convert_call_entry(const char *name, char *buf)
{
        int ct = 0;
        int ssid = 0;
        const char *p = name;
        char c;

        while (ct < 6) {
                c = toupper(*p);
                if (c == '-' || c == '\0')
                        break;
                if (!isalnum(c)) {
                  fprintf(stderr, "baycomepp: invalid symbol in callsign %s\n", name);
                        return -1;
                }
                buf[ct] = c << 1;
                p++;
                ct++;
        }
        for ( ; ct < 6; ct++)
                buf[ct] = ' ' << 1;
        if (*p != '\0') {
                p++;
                if (sscanf(p, "%d", &ssid) != 1 || ssid < 0 || ssid > 15) {
                        fprintf(stderr, "baycomepp: SSID must follow '-' and "
                          "be numeric in the range 0-15 - %s\n", name);
                        return -1;
                }
        }
        buf[6] = ((ssid + '0') << 1) & 0x1E;
        return 0;
}

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

int driver_init(int argc, char *argv[])
{
        static const struct option long_options[] = {
            { "epp", 0, 0, 0x400+MODE_EPP },
            { "ecp", 0, 0, 0x400+MODE_ECP },
            { "eppafsk", 0, 0, 0x400+MODE_EPPAFSK },
            { "eppconv", 0, 0, 0x400+MODE_EPPCONV },
            { "log", 0, 0, 'l' },
            { "kill", 0, 0, 'k' },
            { "mode", 1, 0, 'm' },
            { "port", 1, 0, 'p' },
            { "verbose", 0, 0, 'v' },
            { "no-daemon", 0, 0, 'n' },
#ifdef HAVE_MKISS
#ifdef HAVE_IFRNEWNAME
            { "ifname", 1, 0, 0x500 },
#endif /* HAVE_IFRNEWNAME */
            { "hwaddr", 1, 0, 0x501 },
            { "ipaddr", 1, 0, 0x502 },
            { "netmask", 1, 0, 0x503 },
            { "broadcast", 1, 0, 0x504 },
#else /* !HAVE_MKISS */
            { "iflink", 1, 0, 0x600 },
#endif /* !HAVE_MKISS */
            { 0, 0, 0, 0}
        };
      struct ifconfig ifcfg = IFCONFIGINIT;
      int c;
      int err = 0;
      pid_t pid;
      int daemon = 1;
      int mode = MODE_EPP;
      int pfds[2];
      unsigned iobase = 0x378;

      printf("baycomepp v" VERSION " (c) 1998-2000,2002 by Thomas Sailer, HB9JNX/AE4WA"
#ifdef EPPLONG
             "  (epplong)"
#endif
#ifdef EPPEMUL
             "  (eppemul)"
#endif
             "\n");
      /* initialize state struct */
      memset(&state, 0, sizeof(state));
      state.hrx.bufptr = state.hrx.buf;
      state.config = (struct adapter_config) { 19666600, 9600, 0, 0, 0, 1, 1, 0, 1 };
      state.chaccesspar = (struct chaccesspar) { 10, 10, 40, 3, 0 };
      /* parse arguments */
      while ((c = getopt_long(argc, argv, "lknvm:p:caz", long_options, NULL)) != EOF)
            switch (c) {
            case 'l':
                  logging = 1;
                  break;

            case 'k':
                  kill_baycomeppd();
                  exit(0);

            case 'n':
                  daemon = 0;
                  logpackets = 1;
                  break;

            case 'v':
                  verboselevel++;
                  break;

            case 'm':
                  parseconfig(&state.config, optarg);
                  state.config.extstat = 1;
                  break;

            case 'p': 
                  iobase = strtoul(optarg, NULL, 0);
                  if (iobase <= 0 || iobase >= 0x3f8)
                        err++;
                  break;

            case 0x400+MODE_EPPAFSK:
            case 'a':
                  mode = MODE_EPPAFSK;
                  break;

            case 0x400+MODE_ECP:
            case 'c':
                  mode = MODE_ECP;
                  break;

            case 0x400+MODE_EPPCONV:
            case 'z':
                  mode = MODE_EPPCONV;
                  break;

            case 0x400+MODE_EPP:
                  mode = MODE_EPP;
                  break;

#ifdef HAVE_MKISS
            case 0x500: /* ifname */
                  if (strlen(optarg) >= IFNAMSIZ) {
                        fprintf(stderr, "baycomepp: ifname \"%s\"too long\n", optarg);
                        err++;
                  }
                  strncpy(ifcfg.ifname, optarg, sizeof(ifcfg.ifname)-1);
                  ifcfg.ifname[sizeof(ifcfg.ifname)-1] = 0;
                  break;

            case 0x501: /* hwaddr */
                  if (convert_call_entry(optarg, ifcfg.hwaddr.ax25_call))
                        err++;
                  break;

            case 0x502: /* ipaddr */
                  if (!inet_aton(optarg, &ifcfg.ipaddr)) {
                        fprintf(stderr, "baycomepp: invalid ip address \"%s\"\n", optarg);
                        err++;
                  }
                  break;

            case 0x503: /* netmask */
                  if (!inet_aton(optarg, &ifcfg.netmask)) {
                        fprintf(stderr, "baycomepp: invalid netmask \"%s\"\n", optarg);
                        err++;
                  }
                  break;

            case 0x504: /* broadcast */
                  if (!inet_aton(optarg, &ifcfg.broadcast)) {
                        fprintf(stderr, "baycomepp: invalid broadcast address \"%s\"\n", optarg);
                        err++;
                  }
                  break;

#else /* !HAVE_MKISS */
            case 0x600: /* iflink */
                  strncpy(ifcfg.ifname, optarg, sizeof(ifcfg.ifname)-1);
                  ifcfg.ifname[sizeof(ifcfg.ifname)-1] = 0;
                  break;
#endif /* !HAVE_MKISS */

            default:
                  err++;
                  break;
            }
      if (err) {
            fprintf(stderr, "usage: baycomepp [-c <cfgfilename>] [-l] [-k] [-n] [-v] [-p <portaddr>] [-m <modestr>]\n"
#ifdef HAVE_MKISS
                  "                 [--ifname=<name>] [--hwaddr=<call>] [--ipaddr=<ip>]\n"
                  "                 [--netmask=<ip>] [--broadcast=<ip>]\n"
#else /* !HAVE_MKISS */
                  "                 [--iflink=<name>]\n"
#endif /* !HAVE_MKISS */
                  "  mode options:\n"
                  "    intclk    uses FPGA internal clock; DON'T use if an external osc is on board\n"
                  "    extclk    uses the external oscillator; recommended if the internal modem is used\n"
                  "    intmodem  uses the internal modem\n"
                  "    extmodem  uses a DF9IC type modem connected to the high speed modem connector\n"
                  "    fclk=     sets the FPGA clock frequency (default 19.6666 MHz)\n"
                  "    bitrate=  sets the bitrate for the FSK modem\n"
                  "    loopback  sets an internal modem loopback\n"
                  "    extstat   allows extended status readback\n"
                  "    noextstat disallows extended status readback\n");
            exit(1);
      }
      if (parport_init_direct(iobase))
            errprintf(SEV_FATAL, "no parport found at 0x%x\n", iobase); 
      init(mode);
      if (!daemon) {
            setsid(); /* become a process group leader and drop controlling terminal */
            fclose(stdin); /* no more standard in */
            if (logging)
                  openlog(progname, LOG_PID, LOG_DAEMON);
            init2(&ifcfg);
            return mode;
      }
      if (pipe(pfds)) {
            errstr(SEV_FATAL, "pipe\n");
            exit(1);
      }
      switch (pid = fork()) {
      case -1:
            errstr(SEV_FATAL, "fork\n");
            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 */
            if (logging)
                  openlog(progname, LOG_PID, LOG_DAEMON);
            init2(&ifcfg);
            if (write(pfds[1], &mode, sizeof(mode)) != sizeof(mode))
                  errstr(SEV_ERROR, "write\n");
            close(pfds[1]);
            return mode;

      default:
            close(pfds[1]);
            err = read(pfds[0], &c, sizeof(c));
            if (err != sizeof(c))
                  errprintf(SEV_FATAL, "baycomepp: modem init failed (read: %d errno: %d %s)\n",
                          err, errno, strerror(errno));
            write_pid(pid);
            fprintf(stderr, "baycomepp: child pid: %u\n", pid);
            break;
      }
      exit(0);
}

Generated by  Doxygen 1.6.0   Back to index