aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-07-27 21:44:50 +0200
committerHarald Welte <laforge@gnumonks.org>2016-10-17 22:14:19 +0200
commita0108e78a9458282105b9d9d34b41be09343c373 (patch)
tree0d332c2e2422c78cf6f1320f55ecbb6863068b43 /src
parent4ca5c53f7fd67a752512b33d8bbac30711c23866 (diff)
Implement new 'raw' input type for E1 timeslots
In the past, the A-bis E1 input system only unederstood LAPD signalling time-slots and trau-slots with 16kBps sub-slots. This adds the notion of a 'raw' transparent 64kBps slot, without any furthe de-multiplexing nor any HLDC inside. Change-Id: I0c25c2688eddd0c55c15b280a8c6e8a49629516b
Diffstat (limited to 'src')
-rw-r--r--src/e1_input.c23
-rw-r--r--src/input/dahdi.c85
-rw-r--r--src/input/misdn.c94
3 files changed, 202 insertions, 0 deletions
diff --git a/src/e1_input.c b/src/e1_input.c
index df990d5..75ae36e 100644
--- a/src/e1_input.c
+++ b/src/e1_input.c
@@ -217,6 +217,7 @@ const struct value_string e1inp_ts_type_names[5] = {
{ E1INP_TS_TYPE_NONE, "None" },
{ E1INP_TS_TYPE_SIGN, "Signalling" },
{ E1INP_TS_TYPE_TRAU, "TRAU" },
+ { E1INP_TS_TYPE_RAW, "RAW" },
{ 0, NULL }
};
@@ -299,6 +300,21 @@ int e1inp_ts_config_sign(struct e1inp_ts *ts, struct e1inp_line *line)
return 0;
}
+int e1inp_ts_config_raw(struct e1inp_ts *ts, struct e1inp_line *line,
+ void (*raw_recv_cb)(struct e1inp_ts *ts,
+ struct msgb *msg))
+{
+ if (ts->type == E1INP_TS_TYPE_RAW && ts->line && line)
+ return 0;
+
+ ts->type = E1INP_TS_TYPE_RAW;
+ ts->line = line;
+ ts->raw.recv_cb = raw_recv_cb;
+ INIT_LLIST_HEAD(&ts->raw.tx_queue);
+
+ return 0;
+}
+
struct e1inp_line *e1inp_line_find(uint8_t e1_nr)
{
struct e1inp_line *e1i_line;
@@ -531,6 +547,9 @@ int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg));
msgb_free(msg);
break;
+ case E1INP_TS_TYPE_RAW:
+ ts->raw.recv_cb(ts, msg);
+ break;
default:
ret = -EINVAL;
LOGP(DLMI, LOGL_ERROR, "unknown TS type %u\n", ts->type);
@@ -654,6 +673,10 @@ struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
}
msgb_put(msg, 40);
break;
+ case E1INP_TS_TYPE_RAW:
+ /* Get msgb from tx_queue */
+ msg = msgb_dequeue(&e1i_ts->raw.tx_queue);
+ break;
default:
LOGP(DLMI, LOGL_ERROR, "unsupported E1 TS type %u\n", e1i_ts->type);
return NULL;
diff --git a/src/input/dahdi.c b/src/input/dahdi.c
index ab06908..db00f5f 100644
--- a/src/input/dahdi.c
+++ b/src/input/dahdi.c
@@ -360,6 +360,79 @@ static int handle_tsX_read(struct osmo_fd *bfd)
return ret;
}
+/* write to a raw channel TS */
+static int handle_ts_raw_write(struct osmo_fd *bfd)
+{
+ struct e1inp_line *line = bfd->data;
+ unsigned int ts_nr = bfd->priv_nr;
+ struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
+ struct msgb *msg;
+ int ret;
+
+ /* get the next msg for this timeslot */
+ msg = e1inp_tx_ts(e1i_ts, NULL);
+ if (!msg)
+ return 0;
+
+ if (msg->len != D_BCHAN_TX_GRAN) {
+ /* This might lead to a transmit underrun, as we call tx
+ * from the rx path, as there's no select/poll on dahdi
+ * */
+ LOGP(DLINP, LOGL_NOTICE, "unexpected msg->len = %u, "
+ "expected %u\n", msg->len, D_BCHAN_TX_GRAN);
+ }
+
+ DEBUGP(DLMIB, "RAW CHAN TX: %s\n",
+ osmo_hexdump(msg->data, msg->len));
+
+ if (0/*invertbits*/) {
+ flip_buf_bits(msg->data, msg->len);
+ }
+
+ ret = write(bfd->fd, msg->data, msg->len);
+ if (ret < msg->len)
+ LOGP(DLINP, LOGL_DEBUG, "send returns %d instead of %d\n",
+ ret, msg->len);
+ msgb_free(msg);
+
+ return ret;
+}
+
+static int handle_ts_raw_read(struct osmo_fd *bfd)
+{
+ struct e1inp_line *line = bfd->data;
+ unsigned int ts_nr = bfd->priv_nr;
+ struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
+ struct msgb *msg = msgb_alloc(D_TSX_ALLOC_SIZE, "DAHDI Raw TS");
+ int ret;
+
+ if (!msg)
+ return -ENOMEM;
+
+ ret = read(bfd->fd, msg->data, D_TSX_ALLOC_SIZE);
+ if (ret < 0 || ret != D_TSX_ALLOC_SIZE) {
+ LOGP(DLINP, LOGL_DEBUG, "read error %d %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+
+ if (0/*invertbits*/) {
+ flip_buf_bits(msg->data, ret);
+ }
+
+ msgb_put(msg, ret);
+
+ msg->l2h = msg->data;
+ DEBUGP(DLMIB, "RAW CHAN RX: %s\n",
+ osmo_hexdump(msgb_l2(msg), ret));
+ ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
+ /* physical layer indicates that data has been sent,
+ * we thus can send some more data */
+ ret = handle_ts_raw_write(bfd);
+
+ return ret;
+}
+
/* callback from select.c in case one of the fd's can be read/written */
static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
@@ -389,6 +462,17 @@ static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what)
* writeset, since it doesn't support poll() based
* write flow control */
break;
+ case E1INP_TS_TYPE_RAW:
+ if (what & BSC_FD_EXCEPT)
+ handle_dahdi_exception(e1i_ts);
+ if (what & BSC_FD_READ)
+ rc = handle_ts_raw_read(bfd);
+ if (what & BSC_FD_WRITE)
+ rc = handle_ts_raw_write(bfd);
+ /* We never include the DAHDI B-Channel FD into the
+ * writeset, since it doesn't support poll() based
+ * write flow control */
+ break;
default:
LOGP(DLINP, LOGL_NOTICE,
"unknown E1 TS type %u\n", e1i_ts->type);
@@ -537,6 +621,7 @@ static int dahdi_e1_setup(struct e1inp_line *line)
e1i_ts, &lapd_profile_abis);
break;
case E1INP_TS_TYPE_TRAU:
+ case E1INP_TS_TYPE_RAW:
/* close/release LAPD instance, if any */
if (e1i_ts->lapd) {
lapd_instance_free(e1i_ts->lapd);
diff --git a/src/input/misdn.c b/src/input/misdn.c
index 330e3b3..391cd18 100644
--- a/src/input/misdn.c
+++ b/src/input/misdn.c
@@ -391,6 +391,92 @@ static int handle_tsX_read(struct osmo_fd *bfd)
return ret;
}
+/* write to a raw channel TS */
+static int handle_ts_raw_write(struct osmo_fd *bfd, unsigned int len)
+{
+ struct e1inp_line *line = bfd->data;
+ unsigned int ts_nr = bfd->priv_nr;
+ struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
+ struct msgb *msg;
+ struct mISDNhead *hh;
+ int ret;
+
+ /* get the next msg for this timeslot */
+ msg = e1inp_tx_ts(e1i_ts, NULL);
+ if (!msg)
+ return 0;
+
+ if (msg->len != len) {
+ /* This might lead to a transmit underrun, as we call tx
+ * from the rx path, as there's no select/poll on dahdi
+ * */
+ LOGP(DLINP, LOGL_NOTICE, "unexpected msg->len = %u, "
+ "expected %u\n", msg->len, len);
+ }
+
+ DEBUGP(DLMIB, "RAW CHAN TX: %s\n",
+ osmo_hexdump(msg->data, msg->len));
+
+ hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
+ hh->prim = PH_DATA_REQ;
+ hh->id = 0;
+
+ ret = write(bfd->fd, msg->data, msg->len);
+ if (ret < msg->len)
+ LOGP(DLINP, LOGL_DEBUG, "send returns %d instead of %d\n",
+ ret, msg->len);
+ msgb_free(msg);
+
+ return ret;
+}
+
+static int handle_ts_raw_read(struct osmo_fd *bfd)
+{
+ struct e1inp_line *line = bfd->data;
+ unsigned int ts_nr = bfd->priv_nr;
+ struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
+ struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE, "mISDN Tx RAW");
+ struct mISDNhead *hh;
+ int ret;
+
+ if (!msg)
+ return -ENOMEM;
+
+ hh = (struct mISDNhead *) msg->data;
+
+ ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0);
+ if (ret < 0) {
+ fprintf(stderr, "recvfrom error %s\n", strerror(errno));
+ return ret;
+ }
+
+ msgb_put(msg, ret);
+
+ if (hh->prim != PH_CONTROL_IND)
+ DEBUGP(DLMIB, "<= RAW CHAN len = %d, prim(0x%x) id(0x%x): %s\n",
+ ret, hh->prim, hh->id,
+ get_value_string(prim_names, hh->prim));
+
+ switch (hh->prim) {
+ case PH_DATA_IND:
+ msg->l2h = msg->data + MISDN_HEADER_LEN;
+ DEBUGP(DLMIB, "RAW CHAN RX: %s\n",
+ osmo_hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
+ /* the number of bytes received indicates that data to send */
+ handle_ts_raw_write(bfd, msgb_l2len(msg));
+ return e1inp_rx_ts(e1i_ts, msg, 0, 0);
+ case PH_ACTIVATE_IND:
+ case PH_DATA_CNF:
+ break;
+ default:
+ break;
+ }
+ /* FIXME: why do we free signalling msgs in the caller, and trau not? */
+ msgb_free(msg);
+
+ return ret;
+}
+
/* callback from select.c in case one of the fd's can be read/written */
static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what)
{
@@ -414,6 +500,13 @@ static int misdn_fd_cb(struct osmo_fd *bfd, unsigned int what)
* writeset, since it doesn't support poll() based
* write flow control */
break;
+ case E1INP_TS_TYPE_RAW:
+ if (what & BSC_FD_READ)
+ rc = handle_ts_raw_read(bfd);
+ /* We never include the mISDN B-Channel FD into the
+ * writeset, since it doesn't support poll() based
+ * write flow control */
+ break;
default:
fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
break;
@@ -524,6 +617,7 @@ static int mi_e1_setup(struct e1inp_line *line, int release_l2)
bfd->when = BSC_FD_READ;
break;
case E1INP_TS_TYPE_TRAU:
+ case E1INP_TS_TYPE_RAW:
bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
/* We never include the mISDN B-Channel FD into the
* writeset, since it doesn't support poll() based