osmo-isdntap/src/dahdi.c

268 lines
6.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <dahdi/user.h>
#include <osmocom/core/utils.h>
#include "isdntap.h"
#define BLOCK_SIZE 512
/* obtain a per-span sysfs integer attribute */
static int get_span_sysfs_int(unsigned int spanno, const char *attr)
{
int res, rc;
char filename[PATH_MAX];
FILE *fp;
snprintf(filename, sizeof(filename), "/sys/bus/dahdi_spans/devices/span-%u/%s", spanno, attr);
fp = fopen(filename, "r");
if (!fp)
return -1;
rc = fscanf(fp, "%d", &res);
fclose(fp);
if (rc == EOF)
return -1;
return res;
}
/* obtain a per-span sysfs string attribute. Caller must free() return value */
static char *get_span_sysfs_str(unsigned int spanno, const char *attr)
{
char *res = NULL;
int rc;
char filename[PATH_MAX];
FILE *fp;
snprintf(filename, sizeof(filename), "/sys/bus/dahdi_spans/devices/span-%u/%s", spanno, attr);
fp = fopen(filename, "r");
if (!fp)
return NULL;
rc = fscanf(fp, "%ms", &res);
fclose(fp);
if (rc == EOF) {
free(res);
return NULL;
}
return res;
}
/* Find the DAHDI span number for the given 'name' */
static int get_span_no_by_name(const char *name)
{
unsigned int i;
/* iterate over all (up to 256 max) spans and find a matching name */
for (i = 1; i < 256; i++) {
char *name_attr = get_span_sysfs_str(i, "name");
if (!name_attr)
continue;
if (!strcmp(name_attr, name)) {
free(name_attr);
return i;
}
free(name_attr);
}
return -1;
}
/* crate a [rx or tx] mirror FD for given DAHDI channel number */
static int make_mirror(long type, int chan)
{
int res = 0;
int fd = 0;
struct dahdi_bufferinfo bi;
fd = open("/dev/dahdi/pseudo", O_RDONLY);
memset(&bi, 0, sizeof(bi));
bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
bi.numbufs = 32;
bi.bufsize = BLOCK_SIZE;
ioctl(fd, DAHDI_SET_BUFINFO, &bi);
res = ioctl(fd, type, &chan);
if (res) {
fprintf(stderr, "error setting channel err=%d!\n", res);
return -1;
}
return fd;
}
static int dahdi_bchan_fd_cb(struct osmo_fd *ofd, unsigned int what)
{
struct isdntap_ts *ts = ofd->data;
uint8_t buf[4096];
int rc;
OSMO_ASSERT(what & OSMO_FD_READ);
rc = read(ofd->fd, buf, sizeof(buf));
if (rc <= 0)
return -EIO;
if (ofd->priv_nr == 1) {
/* Rx Mirror */
} else {
/* Tx Mirror */
}
return isdntap_ts_rx_bchan(ts, buf, rc, 0);
}
static int dahdi_dchan_fd_cb(struct osmo_fd *ofd, unsigned int what)
{
struct isdntap_ts *ts = ofd->data;
uint8_t buf[4096];
int rc;
OSMO_ASSERT(what & OSMO_FD_READ);
rc = read(ofd->fd, buf, sizeof(buf));
if (rc <= 0)
return -EIO;
if (ofd->priv_nr == 1) {
/* Rx Mirror */
} else {
/* Tx Mirror */
}
return isdntap_ts_rx_dchan(ts, buf, rc, 0);
}
static int open_line_dahdi(struct isdntap_line *line)
{
struct isdntap_ts *sig_ts;
char *spantype;
int rc;
/* make sure we have a span number */
if (line->driver.dahdi.spanno < 0) {
if (!line->driver.dahdi.name)
return -1;
line->driver.dahdi.spanno = get_span_no_by_name(line->driver.dahdi.name);
}
if (line->driver.dahdi.spanno < 0)
return -1;
/* resolve the base channel number */
rc = get_span_sysfs_int(line->driver.dahdi.spanno, "basechan");
if (rc < 0)
return rc;
line->driver.dahdi.basechan = rc;
/* resolve the numberof channels */
rc = get_span_sysfs_int(line->driver.dahdi.spanno, "channels");
if (rc < 0)
return rc;
line->driver.dahdi.channels = rc;
/* obtain the span type */
spantype = get_span_sysfs_str(line->driver.dahdi.spanno, "spantype");
if (!spantype)
return -1;
line->driver.dahdi.spantype = talloc_strdup(line, spantype);
free(spantype);
/* note the DAHDI channel number for each timeslot */
for (int i = 0; i < line->driver.dahdi.channels; i++) {
/* FIXME: the below is very E1-specific */
struct isdntap_ts *ts = &line->ts[1+i];
ts->driver.dahdi.channo = line->driver.dahdi.basechan + i;
}
sig_ts = &line->ts[16]; // FIXME: configurable
rc = make_mirror(DAHDI_RXMIRROR, sig_ts->driver.dahdi.channo);
if (rc < 0)
return rc;
/* verify HDLC mode? */
osmo_fd_setup(&sig_ts->driver.dahdi.rx, rc, OSMO_FD_READ, dahdi_dchan_fd_cb, sig_ts, 1);
osmo_fd_register(&sig_ts->driver.dahdi.rx);
rc = make_mirror(DAHDI_TXMIRROR, sig_ts->driver.dahdi.channo);
if (rc < 0) {
close(sig_ts->driver.dahdi.rx.fd);
sig_ts->driver.dahdi.rx.fd = -1;
return rc;
}
/* verify HDLC mode? */
osmo_fd_setup(&sig_ts->driver.dahdi.tx, rc, OSMO_FD_READ, dahdi_dchan_fd_cb, sig_ts, 2);
osmo_fd_register(&sig_ts->driver.dahdi.tx);
return 0;
}
static int open_ts_dahdi(struct isdntap_ts *ts)
{
int rc;
rc = make_mirror(DAHDI_RXMIRROR, ts->driver.dahdi.channo);
if (rc < 0)
return rc;
osmo_fd_setup(&ts->driver.dahdi.rx, rc, OSMO_FD_READ, dahdi_bchan_fd_cb, ts, 1);
osmo_fd_register(&ts->driver.dahdi.rx);
rc = make_mirror(DAHDI_TXMIRROR, ts->driver.dahdi.channo);
if (rc < 0) {
osmo_fd_unregister(&ts->driver.dahdi.rx);
close(ts->driver.dahdi.rx.fd);
ts->driver.dahdi.rx.fd = -1;
return rc;
}
osmo_fd_setup(&ts->driver.dahdi.tx, rc, OSMO_FD_READ, dahdi_bchan_fd_cb, ts, 2);
osmo_fd_register(&ts->driver.dahdi.tx);
return 0;
}
static void close_ts_dahdi(struct isdntap_ts *ts)
{
if (ts->driver.dahdi.rx.fd >= 0) {
osmo_fd_unregister(&ts->driver.dahdi.rx);
close(ts->driver.dahdi.rx.fd);
ts->driver.dahdi.rx.fd = -1;
}
if (ts->driver.dahdi.tx.fd >= 0) {
osmo_fd_unregister(&ts->driver.dahdi.tx);
close(ts->driver.dahdi.tx.fd);
ts->driver.dahdi.tx.fd = -1;
}
}
static void close_line_dahdi(struct isdntap_line *line)
{
/* close all file descriptors on all timeslots */
for (int i = 0; i < line->driver.dahdi.channels; i++) {
/* FIXME: the below is very E1-specific */
struct isdntap_ts *ts = &line->ts[1+i];
close_ts_dahdi(ts);
}
}
const struct isdntap_driver dahdi_driver = {
.name = "dahdi",
.line_open = open_line_dahdi,
.line_close = close_line_dahdi,
.ts_open = open_ts_dahdi,
.ts_close = close_ts_dahdi,
};