From 17287576555a5c46fa23549e2e5f073660dccb70 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 21 Apr 1999 09:51:03 +0200 Subject: Import ax25-tools 0.0.1 from tarball --- hdlcutil/hdrvcomm.c | 663 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 663 insertions(+) create mode 100644 hdlcutil/hdrvcomm.c (limited to 'hdlcutil/hdrvcomm.c') diff --git a/hdlcutil/hdrvcomm.c b/hdlcutil/hdrvcomm.c new file mode 100644 index 0000000..55f0f38 --- /dev/null +++ b/hdlcutil/hdrvcomm.c @@ -0,0 +1,663 @@ +/*****************************************************************************/ + +/* + * hdrvcomm.c -- HDLC driver communications. + * + * Copyright (C) 1996 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. + * + * + * History: + * 0.1 10.5.97 Started + */ + +/*****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ +#include +#include "hdrvcomm.h" +#include "usersmdiag.h" + +#include +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL +static int kernel_mode = 1; +#endif /* HDRVC_KERNEL */ +static char *if_name = "bc0"; +static char *prg_name; +static int fd = -1; +static struct ifreq ifr_h; +static int promisc = 0; +static int msqid = -1; + +/* ---------------------------------------------------------------------- */ + +static void terminate(void) +{ +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if (ioctl(fd, SIOCSIFFLAGS, &ifr_h) < 0) { + perror("ioctl (SIOCSIFFLAGS)"); + exit(1); + } + } +#endif /* HDRVC_KERNEL */ + exit(0); +} + +/* ---------------------------------------------------------------------- */ + +static void terminate_sig(int signal) +{ + printf("signal %i caught\n", signal); + terminate(); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_recvpacket(char *pkt, int maxlen) +{ + struct ifreq ifr_new; + struct sockaddr from; + int from_len = sizeof(from); + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if (!promisc) { + struct sockaddr sa; + + strcpy(sa.sa_data, if_name); + sa.sa_family = AF_INET; + if (bind(fd, &sa, sizeof(struct sockaddr)) < 0) { + fprintf(stderr, "%s: Error %s (%i) bind failed\n", + prg_name, strerror(errno), errno); + exit(-2); + } + ifr_new = ifr_h; + ifr_new.ifr_flags |= IFF_PROMISC; + if (ioctl(fd, SIOCSIFFLAGS, &ifr_new) < 0) { + perror("ioctl (SIOCSIFFLAGS)"); + exit(1); + } + signal(SIGTERM, terminate_sig); + signal(SIGQUIT, terminate_sig); + if (atexit((void (*)(void))terminate)) { + perror("atexit"); + terminate(); + } + promisc = 1; + fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK); + } + if (!pkt || maxlen < 2) + return 0; + return recvfrom(fd, pkt, maxlen, 0, &from, &from_len); + } +#endif /* HDRVC_KERNEL */ + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_getfd(void) +{ + return fd; +} + +/* ---------------------------------------------------------------------- */ + +char *hdrvc_ifname(void) +{ + return if_name; +} + +/* ---------------------------------------------------------------------- */ + +void hdrvc_args(int *argc, char *argv[], char *def_if) +{ + int ac, i; + + if (def_if) + if_name = def_if; + if (!argc || !argv || (ac = *argc) < 1) + return; + prg_name = argv[0]; + for (i = 1; i < ac-1; i++) { +#ifdef HDRVC_KERNEL + if (!strcmp(argv[i], "-i")) { + kernel_mode = 1; + if_name = argv[i+1]; + ac -= 2; + if (i < ac) + memmove(argv+i, argv+i+2, (ac-i) * sizeof(void *)); + i--; + } else +#endif /* HDRVC_KERNEL */ + if (!strcmp(argv[i], "-u")) { +#ifdef HDRVC_KERNEL + kernel_mode = 0; +#endif /* HDRVC_KERNEL */ + if_name = argv[i+1]; + ac -= 2; + if (i < ac) + memmove(argv+i, argv+i+2, (ac-i) * sizeof(void *)); + i--; + } + } + *argc = ac; +} + +/* ---------------------------------------------------------------------- */ + +void hdrvc_init(void) +{ +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if ((fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_AX25))) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot open %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + strcpy(ifr_h.ifr_name, if_name); + if (ioctl(fd, SIOCGIFFLAGS, &ifr_h) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot ioctl %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + } else +#endif /* HDRVC_KERNEL */ + { + key_t k = ftok(if_name, USERSM_KEY_PROJ); + + if (k == (key_t)-1) { + fprintf(stderr, "%s: Error %s (%i), cannot ftok on %s\n", prg_name, + strerror(errno), errno, if_name); + exit(-1); + } + if ((msqid = msgget(k, 0700)) < 0) { + fprintf(stderr, "%s: Error %s (%i), cannot msgget %d\n", prg_name, + strerror(errno), errno, k); + exit(-1); + } + } +} + +/* ---------------------------------------------------------------------- */ + +extern __inline__ void hdrvc_sendmsg(struct usersmmsg *msg, int len) +{ + if (msgsnd(msqid, (struct msgbuf *)msg, len+sizeof(msg->hdr)-sizeof(long), 0) < 0) { + perror("msgsnd"); + exit(1); + } +} + +extern __inline__ int hdrvc_recvmsg(struct usersmmsg *msg, int maxlen, long type) +{ + int len; + + if ((len = msgrcv(msqid, (struct msgbuf *)msg, maxlen-sizeof(long), type, MSG_NOERROR)) < 0) { + perror("msgrcv"); + exit(1); + } +#if 0 + for (;;) { + if ((len = msgrcv(msqid, (struct msgbuf *)msg, maxlen-sizeof(long), type, IPC_NOWAIT|MSG_NOERROR)) >= 0) + return len+sizeof(long); + if (errno != ENOMSG) { + perror("msgrcv"); + exit(1); + } + usleep(250000); + } +#endif + return len+sizeof(long); +} + +/* ---------------------------------------------------------------------- */ + +#ifdef HDRVC_KERNEL + +int hdrvc_hdlcdrv_ioctl(int cmd, struct hdlcdrv_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_sm_ioctl(int cmd, struct sm_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_baycom_ioctl(int cmd, struct baycom_ioctl *par) +{ + struct ifreq ifr = ifr_h; + + if (!kernel_mode) { + errno = EINVAL; + return -1; + } + ifr.ifr_data = (caddr_t)par; + par->cmd = cmd; + return ioctl(fd, SIOCDEVPRIVATE, &ifr); +} + +/* ---------------------------------------------------------------------- */ + +unsigned int hdrvc_get_ifflags(void) +{ + struct ifreq ifr; + + if (kernel_mode) { + memcpy(&ifr, &ifr_h, sizeof(ifr)); + if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { + perror("ioctl: SIOCGIFFLAGS"); + exit(-1); + } + return ifr.ifr_flags; + } + return IFF_UP | IFF_RUNNING; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_diag(struct sm_diag_data *diag) +{ + struct sm_ioctl smi; + int ret; + struct usersmmsg msg; + + if (!diag) { + errno = EINVAL; + return -1; + } + if (kernel_mode) { + memcpy(&smi.data.diag, diag, sizeof(smi.data.diag)); + ret = hdrvc_sm_ioctl(SMCTL_DIAGNOSE, &smi); + memcpy(diag, &smi.data.diag, sizeof(smi.data.diag)); + return ret; + } + msg.hdr.type = USERSM_CMD_REQ_DIAG; + msg.hdr.channel = 0; + msg.data.diag.mode = diag->mode; + msg.data.diag.flags = diag->flags; + msg.data.diag.samplesperbit = diag->samplesperbit; + msg.data.diag.datalen = diag->datalen; + hdrvc_sendmsg(&msg, sizeof(msg.data.diag)); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DIAG); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.diag) || ret < sizeof(msg.data.diag)+msg.data.diag.datalen*sizeof(short)) { + errno = EIO; + return -1; + } + diag->mode = msg.data.diag.mode; + diag->flags = msg.data.diag.flags; + diag->samplesperbit = msg.data.diag.samplesperbit; + diag->datalen = msg.data.diag.datalen; + memcpy(diag->data, msg.data.diag_out.samples, msg.data.diag.datalen*sizeof(short)); + return 0; +} + +#endif /* HDRVC_KERNEL */ + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_samples(void) +{ + int ret; + struct hdlcdrv_ioctl bi; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETSAMPLES, &bi); + if (ret < 0) + return ret; + return bi.data.bits & 0xff; + } +#endif /* HDRVC_KERNEL */ + errno = EAGAIN; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_bits(void) +{ + int ret; + struct hdlcdrv_ioctl bi; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETBITS, &bi); + if (ret < 0) + return ret; + return bi.data.bits & 0xff; + } +#endif /* HDRVC_KERNEL */ + errno = EAGAIN; + return -1; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_channel_access_param(struct hdrvc_channel_params *par) +{ + struct hdlcdrv_ioctl hi; + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + if ((ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETCHANNELPAR, &hi)) < 0) + return ret; + if (!par) { + errno = EINVAL; + return -1; + } + par->tx_delay = hi.data.cp.tx_delay; + par->tx_tail = hi.data.cp.tx_tail; + par->slottime = hi.data.cp.slottime; + par->ppersist = hi.data.cp.ppersist; + par->fulldup = hi.data.cp.fulldup; + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_CHACCESS_PAR; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_CHACCESS_PAR); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.cp)) { + errno = EIO; + return -1; + } + par->tx_delay = msg.data.cp.tx_delay; + par->tx_tail = msg.data.cp.tx_tail; + par->slottime = msg.data.cp.slottime; + par->ppersist = msg.data.cp.ppersist; + par->fulldup = msg.data.cp.fulldup; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_set_channel_access_param(struct hdrvc_channel_params par) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl hi; + + hi.data.cp.tx_delay = par.tx_delay; + hi.data.cp.tx_tail = par.tx_tail; + hi.data.cp.slottime = par.slottime; + hi.data.cp.ppersist = par.ppersist; + hi.data.cp.fulldup = par.fulldup; + if ((ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_SETCHANNELPAR, &hi)) < 0) + return ret; + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_SET_CHACCESS_PAR; + msg.hdr.channel = 0; + msg.data.cp.tx_delay = par.tx_delay; + msg.data.cp.tx_tail = par.tx_tail; + msg.data.cp.slottime = par.slottime; + msg.data.cp.ppersist = par.ppersist; + msg.data.cp.fulldup = par.fulldup; + hdrvc_sendmsg(&msg, sizeof(msg.data.cp)); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_calibrate(int calib) +{ + struct hdlcdrv_ioctl bhi; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + bhi.data.calibrate = calib; + return hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_CALIBRATE, &bhi); + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_CALIBRATE; + msg.hdr.channel = 0; + msg.data.calib = calib; + hdrvc_sendmsg(&msg, sizeof(msg.data.calib)); + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_channel_state(struct hdrvc_channel_state *st) +{ + struct hdlcdrv_ioctl bhi; + int ret; + struct usersmmsg msg; + + if (!st) { + errno = EINVAL; + return -1; + } +#ifdef HDRVC_KERNEL + if (kernel_mode) { + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETSTAT, &bhi); + if (ret >= 0) { + st->ptt = bhi.data.cs.ptt; + st->dcd = bhi.data.cs.dcd; + st->ptt_keyed = bhi.data.cs.ptt_keyed; + st->tx_packets = bhi.data.cs.tx_packets; + st->tx_errors = bhi.data.cs.tx_errors; + st->rx_packets = bhi.data.cs.rx_packets; + st->rx_errors = bhi.data.cs.rx_errors; + } + return ret; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_CHANNELSTATE; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_CHANNELSTATE); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.cs)) { + errno = EIO; + return -1; + } + st->ptt = msg.data.cs.ptt; + st->dcd = msg.data.cs.dcd; + st->ptt_keyed = msg.data.cs.ptt_keyed; + st->tx_packets = msg.data.cs.tx_packets; + st->tx_errors = msg.data.cs.tx_errors; + st->rx_packets = msg.data.cs.rx_packets; + st->rx_errors = msg.data.cs.rx_errors; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_diag2(unsigned int mode, unsigned int flags, short *data, + unsigned int maxdatalen, unsigned int *samplesperbit) +{ + int ret; + struct usersmmsg msg; + static unsigned int modeconvusersm[4] = { + USERSM_DIAGMODE_OFF, USERSM_DIAGMODE_INPUT, USERSM_DIAGMODE_DEMOD, + USERSM_DIAGMODE_CONSTELLATION + }; + + if (mode > HDRVC_DIAGMODE_CONSTELLATION) { + errno = EINVAL; + return -1; + } +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct sm_ioctl smi; + static unsigned int modeconvsm[4] = { + SM_DIAGMODE_OFF, SM_DIAGMODE_INPUT, SM_DIAGMODE_DEMOD, SM_DIAGMODE_CONSTELLATION + }; + + smi.data.diag.mode = modeconvsm[mode]; + smi.data.diag.flags = (flags & HDRVC_DIAGFLAG_DCDGATE) ? SM_DIAGFLAG_DCDGATE : 0; + smi.data.diag.samplesperbit = 0; + smi.data.diag.datalen = maxdatalen; + smi.data.diag.data = data; + if ((ret = hdrvc_sm_ioctl(SMCTL_DIAGNOSE, &smi)) < 0) + return ret; + if (samplesperbit) + *samplesperbit = smi.data.diag.samplesperbit; + if (smi.data.diag.mode != modeconvsm[mode] || !(smi.data.diag.flags & SM_DIAGFLAG_VALID)) + return 0; + return smi.data.diag.datalen; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DIAG; + msg.hdr.channel = 0; + msg.data.diag.mode = modeconvusersm[mode]; + msg.data.diag.flags = (flags & HDRVC_DIAGFLAG_DCDGATE) ? USERSM_DIAGFLAG_DCDGATE : 0; + msg.data.diag.samplesperbit = 0; + msg.data.diag.datalen = maxdatalen; + hdrvc_sendmsg(&msg, sizeof(msg.data.diag)); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DIAG); + if (ret < 0) + return ret; + if (ret < sizeof(msg.data.diag) || ret < sizeof(msg.data.diag)+msg.data.diag.datalen*sizeof(short)) { + errno = EIO; + return -1; + } + if (samplesperbit) + *samplesperbit = msg.data.diag.samplesperbit; + if (msg.data.diag.mode != modeconvusersm[mode] || !(msg.data.diag.flags & USERSM_DIAGFLAG_VALID)) + return 0; + if (!data || msg.data.diag.datalen <= 0) + return 0; + memcpy(data, msg.data.diag_out.samples, msg.data.diag.datalen*sizeof(short)); + return msg.data.diag.datalen; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_driver_name(char *buf, int bufsz) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl bhi; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_DRIVERNAME, &bhi); + if (ret < 0) + return ret; + strncpy(buf, bhi.data.modename, bufsz); + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DRVNAME; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DRVNAME); + if (ret < 0) + return ret; + if (ret < 1) { + errno = EIO; + return -1; + } + if (bufsz < ret) + ret = bufsz; + strncpy(buf, msg.data.by, ret); + buf[ret-1] = 0; + return 0; +} + +/* ---------------------------------------------------------------------- */ + +int hdrvc_get_mode_name(char *buf, int bufsz) +{ + int ret; + struct usersmmsg msg; + +#ifdef HDRVC_KERNEL + if (kernel_mode) { + struct hdlcdrv_ioctl bhi; + + ret = hdrvc_hdlcdrv_ioctl(HDLCDRVCTL_GETMODE, &bhi); + if (ret < 0) + return ret; + strncpy(buf, bhi.data.modename, bufsz); + return 0; + } +#endif /* HDRVC_KERNEL */ + msg.hdr.type = USERSM_CMD_REQ_DRVMODE; + msg.hdr.channel = 0; + hdrvc_sendmsg(&msg, 0); + ret = hdrvc_recvmsg(&msg, sizeof(msg), USERSM_CMD_ACK_DRVMODE); + if (ret < 0) + return ret; + if (ret < 1) { + errno = EIO; + return -1; + } + if (bufsz < ret) + ret = bufsz; + strncpy(buf, msg.data.by, ret); + buf[ret-1] = 0; + return 0; +} + +/* ---------------------------------------------------------------------- */ -- cgit v1.2.3