jolly has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-abis/+/41140?usp=email )
Change subject: Add CAS channel support ......................................................................
Add CAS channel support
CAS is currently supported by e1d driver only.
Change-Id: I81cc89e01bb4207dc899ab28f24a131f24b61c9c --- M include/osmocom/abis/e1_input.h M src/e1_input.c M src/input/dahdi.c M src/input/e1d.c M src/input/misdn.c 5 files changed, 154 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/40/41140/1
diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index 66985ea..ccf6926 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -77,6 +77,7 @@ E1INP_TS_TYPE_RAW, E1INP_TS_TYPE_HDLC, E1INP_TS_TYPE_I460, + E1INP_TS_TYPE_CAS, }; const char *e1inp_tstype_name(enum e1inp_ts_type tp); extern const struct value_string e1inp_ts_type_names[]; @@ -120,6 +121,12 @@ struct llist_head tx_queue; } hdlc; struct { + /* call-back for every received frame */ + void (*recv_cb)(struct e1inp_ts *ts, struct msgb *msg); + /* pending to-be-transmitted msgb */ + struct msgb *tx_msg; + } cas; + struct { struct osmo_i460_timeslot i460_ts; } i460; }; @@ -335,6 +342,11 @@ void (*hdlc_recv_cb)(struct e1inp_ts *ts, struct msgb *msg));
+/* configure and initialize one timeslot dedicated to CAS frames */ +int e1inp_ts_config_cas(struct e1inp_ts *ts, struct e1inp_line *line, + void (*cas_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)); + /* configure and initialize one timeslot dedicated to nothing */ int e1inp_ts_config_none(struct e1inp_ts *ts, struct e1inp_line *line);
@@ -410,5 +422,6 @@
int e1inp_ts_send_raw(struct e1inp_ts *ts, struct msgb *msg); int e1inp_ts_send_hdlc(struct e1inp_ts *ts, struct msgb *msg); +int e1inp_ts_send_cas(struct e1inp_ts *ts, struct msgb *msg);
#endif /* _E1_INPUT_H */ diff --git a/src/e1_input.c b/src/e1_input.c index 066a572..656d657 100644 --- a/src/e1_input.c +++ b/src/e1_input.c @@ -283,6 +283,7 @@ { E1INP_TS_TYPE_RAW, "RAW" }, { E1INP_TS_TYPE_HDLC, "HDLC" }, { E1INP_TS_TYPE_I460, "I460" }, + { E1INP_TS_TYPE_CAS, "CAS" }, { 0, NULL } };
@@ -361,6 +362,23 @@ return 0; }
+int e1inp_ts_send_cas(struct e1inp_ts *ts, struct msgb *msg) +{ + struct e1inp_driver *driver; + + OSMO_ASSERT(ts->type == E1INP_TS_TYPE_CAS); + + /* notify the driver we have something to write */ + driver = ts->line->driver; + driver->want_write(ts); + + /* update CAS message */ + msgb_free(ts->cas.tx_msg); + ts->cas.tx_msg = msg; + + return 0; +} + /* Depending on its typ a timeslot may hold resources which must be cleaned up * or reset before the type of the timeslot type may be changed. */ static int cleanup_e1inp_ts(struct e1inp_ts *e1i_ts) @@ -390,6 +408,10 @@ case E1INP_TS_TYPE_HDLC: msgb_queue_free(&e1i_ts->hdlc.tx_queue); return 0; + case E1INP_TS_TYPE_CAS: + msgb_free(e1i_ts->cas.tx_msg); + e1i_ts->cas.tx_msg = NULL; + return 0; case E1INP_TS_TYPE_I460: /* The caller is responsible for removing all I.460 subchannels * first. */ @@ -504,6 +526,23 @@ return 0; }
+int e1inp_ts_config_cas(struct e1inp_ts *ts, struct e1inp_line *line, + void (*cas_recv_cb)(struct e1inp_ts *ts, + struct msgb *msg)) +{ + if (ts->type == E1INP_TS_TYPE_CAS && ts->line && line) + return 0; + + cleanup_e1inp_ts(ts); + + ts->type = E1INP_TS_TYPE_CAS; + ts->line = line; + ts->cas.recv_cb = cas_recv_cb; + ts->cas.tx_msg = NULL; + + return 0; +} + int e1inp_ts_config_none(struct e1inp_ts *ts, struct e1inp_line *line) { if (ts->type == E1INP_TS_TYPE_NONE && ts->line && line) @@ -879,6 +918,9 @@ case E1INP_TS_TYPE_HDLC: ts->hdlc.recv_cb(ts, msg); break; + case E1INP_TS_TYPE_CAS: + ts->cas.recv_cb(ts, msg); + break; case E1INP_TS_TYPE_I460: osmo_i460_demux_in(&ts->i460.i460_ts, msg->l2h, msgb_l2len(msg)); msgb_free(msg); @@ -1013,6 +1055,10 @@ /* Get msgb from tx_queue */ msg = msgb_dequeue(&e1i_ts->hdlc.tx_queue); break; + case E1INP_TS_TYPE_CAS: + /* Get msgb from tx_msg, but don't remove it. */ + msg = e1i_ts->cas.tx_msg; + break; case E1INP_TS_TYPE_I460: msg = msgb_alloc(TSX_ALLOC_SIZE, "I460_TX"); if (!msg) diff --git a/src/input/dahdi.c b/src/input/dahdi.c index b9a3fcf..1e6df31 100644 --- a/src/input/dahdi.c +++ b/src/input/dahdi.c @@ -718,6 +718,9 @@ * write flow control */ bfd->when = OSMO_FD_READ | OSMO_FD_EXCEPT;// | OSMO_FD_WRITE; break; + case E1INP_TS_TYPE_CAS: + LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "CAS not supported by dahdi driver.\n"); + return -ENOTSUP; }
if (bfd->fd < 0) diff --git a/src/input/e1d.c b/src/input/e1d.c index dd4e9fe..9d48bbb 100644 --- a/src/input/e1d.c +++ b/src/input/e1d.c @@ -542,6 +542,35 @@ return ret; }
+/* write to a CAS channel TS */ +static int handle_ts_cas_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; + + /* Disable write, as there can be only one CAS message. */ + osmo_fd_write_disable(bfd); + + /* Get the msg, but don't free it. When the application is restarted, + * it will be sent again, so the application gets the latest CAS message. */ + msg = e1inp_tx_ts(e1i_ts, NULL); + if (!msg) + return 0; + + LOGPITS(e1i_ts, DLMIB, LOGL_DEBUG, "CAS CHAN TX: %s\n", osmo_hexdump(msg->data, msg->len)); + + ret = write(bfd->fd, msg->data, msg->len); + if (ret < msg->len) { + LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "write returns %d instead of %d\n", ret, msg->len); + osmo_fsm_inst_dispatch(g_e1d_fsm_inst, EV_CONN_LOST, line); + } + + return ret; +} + #define TSX_ALLOC_SIZE 4096
/* read from a hdlc channel TS */ @@ -573,6 +602,35 @@ return ret; }
+/* read from a CAS channel TS */ +static int handle_ts_cas_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, "E1D CAS TS"); + int ret; + + if (!msg) + return -ENOMEM; + + ret = read(bfd->fd, msg->data, TSX_ALLOC_SIZE); + if (ret <= 0) { + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "%s read error: %d %s\n", __func__, ret, strerror(errno)); + msgb_free(msg); + osmo_fsm_inst_dispatch(g_e1d_fsm_inst, EV_CONN_LOST, line); + return ret; + } + + msgb_put(msg, ret); + + msg->l2h = msg->data; + LOGPITS(e1i_ts, DLMIB, LOGL_DEBUG, "CAS CHAN RX: %s\n", msgb_hexdump_l2(msg)); + ret = e1inp_rx_ts(e1i_ts, msg, 0, 0); + + return ret; +} + static void e1d_write_msg(struct msgb *msg, void *cbdata) { struct osmo_fd *bfd = cbdata; @@ -631,6 +689,12 @@ if (what & OSMO_FD_WRITE) ret = handle_ts_hdlc_write(bfd); break; + case E1INP_TS_TYPE_CAS: + if (what & OSMO_FD_READ) + ret = handle_ts_cas_read(bfd); + if (what & OSMO_FD_WRITE) + ret = handle_ts_cas_write(bfd); + break; default: LOGPITS(e1i_ts, DLINP, LOGL_NOTICE, "unknown/unsupported E1 TS type %u\n", e1i_ts->type); break; @@ -777,6 +841,30 @@ } bfd->when = OSMO_FD_READ; break; + case E1INP_TS_TYPE_CAS: + /* close/release LAPD instance, if any */ + if (e1i_ts->lapd) { + lapd_instance_free(e1i_ts->lapd); + e1i_ts->lapd = NULL; + } + /* close, if old timeslot mode doesn't match new config */ + if (bfd->fd >= 0 && ts_info[ts].cfg.mode != E1DP_TSMODE_CAS) { + close(bfd->fd); + bfd->fd = -1; + } + if (bfd->fd < 0) { + bfd->fd = osmo_e1dp_client_ts_open(g_e1d, e1d_intf, e1d_line, ts, + E1DP_TSMODE_CAS, D_BCHAN_TX_GRAN); + } + if (bfd->fd < 0) { + LOGPITS(e1i_ts, DLINP, LOGL_ERROR, "Could not open timeslot %d\n", ts); + talloc_free(ts_info); + osmo_fsm_inst_dispatch(g_e1d_fsm_inst, EV_CONN_LOST, NULL); + return -EIO; + } + /* Also trigger one write, so latest CAS frame will be sent, if any. */ + bfd->when = OSMO_FD_READ | OSMO_FD_WRITE; + break; case E1INP_TS_TYPE_TRAU: case E1INP_TS_TYPE_I460: case E1INP_TS_TYPE_RAW: diff --git a/src/input/misdn.c b/src/input/misdn.c index 8f04567..3172ee4 100644 --- a/src/input/misdn.c +++ b/src/input/misdn.c @@ -866,6 +866,9 @@ /* open raw socket */ bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW); break; + case E1INP_TS_TYPE_CAS: + LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "CAS not supported by mISDN\n"); + return -ENOTSUP; }
/* failed to open? */ @@ -901,6 +904,7 @@ /* TS 16 is D-channel, so we use channel 0 */ addr.channel = (ts == 16) ? 0 : ts; break; + case E1INP_TS_TYPE_CAS: default: LOGPITS(e1i_ts, DLMI, LOGL_ERROR, "unsupported E1 TS type: %u\n", e1i_ts->type); break;