diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c79ea9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +capi-test diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7456835 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +LIBS = -lasan +CFLAGS = -g -Wall + +LIBS += $(shell pkg-config --libs talloc libosmocore capi20) +CFLAGS += $(shell pkg-config --cflags talloc libosmocore capi20) + +all: capi-test + +clean: + @rm -f *.o capi-test + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +capi-test: capi.o capiconn.o + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + + diff --git a/capi.c b/capi.c new file mode 100644 index 0000000..6b38473 --- /dev/null +++ b/capi.c @@ -0,0 +1,261 @@ +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include "capiconn.h" + +#define CM(x) (1<<(x)) +#define CIPMASK_ALL 0x1FFF03FF +#define CIPMASK_VOICE (CM(1)|CM(4)|CM(5)|CM(16)|CM(26)) +#define CIPMASK_DATA (CM(2)|CM(3)) + + +enum log_subsys { + DLCAPI20, + DCAPI, +}; + +static void *tall_capi_ctx; + +struct capi_inst { + unsigned int applid; + capiconn_context *cc_ctx; + struct osmo_fd ofd; +}; + +static const char *conninfo(capi_connection *p) +{ + static char buf[1024]; + capi_conninfo *cp = capiconn_getinfo(p); + char *callingnumber = ""; + char *callednumber = ""; + + if (cp->callingnumber && cp->callingnumber[0] > 2) + callingnumber = (char *) cp->callingnumber+3; + if (cp->callednumber && cp->callednumber[0] > 1) + callednumber = (char *) cp->callednumber+2; + + snprintf(buf, sizeof(buf), + "\"%s\" -> \"%s\" %s (pcli=0x%x/ncci=0x%x)", + callingnumber, callednumber, + cp->isincoming ? "incoming" : "outgoing", + cp->plci, cp->ncci + ); + buf[sizeof(buf)-1] = 0; + return buf; +} + + +/*********************************************************************** + * capiconn call-backs + ***********************************************************************/ + +static void *cb_malloc(size_t size) +{ + return talloc_size(tall_capi_ctx, size); +} + +static void cb_free(void *buf) +{ + talloc_free(buf); +} + +static void cb_disconnected(capi_connection *cp, int localdisconnect, unsigned reason, unsigned reason_b3) +{ + LOGP(DCAPI, LOGL_DEBUG, "%s(local=%d, reason=0x%4x, reason_b3=0x%x)\n", __func__, localdisconnect, reason, reason_b3); +} + +static void cb_incoming(capi_connection *cp, unsigned contr, unsigned cipvalue, char *called, char *calling) +{ + printf("incoming call: %s (0x%x) %s -> %s\n", conninfo(cp), cipvalue, calling, called); + /* we should call capiconn_{accept,ignore,reject} */ + if (1) { + capiconn_accept(cp, 1, 1, 0, 0, 0, 0, 0); + } else + capiconn_ignore(cp); +} + +static void cb_connected(capi_connection *cp, _cstruct NCPI) +{ + printf("connected: %s\n", conninfo(cp)); +} + +/* user plane data received */ +static void cb_datareceived(capi_connection *cp, unsigned char *data, unsigned int len) +{ + LOGP(DCAPI, LOGL_DEBUG, "%s(%p, %u)\n", __func__, data, len); +} + +/* sent user plane data was confirmed */ +static void cb_datasent(capi_connection *cp, unsigned char *data) +{ + LOGP(DCAPI, LOGL_DEBUG, "%s(%p)\n", __func__, data); +} + + +/* capiconn wants to issue a CAPI_PUT_MESSAGE */ +static void cb_put_message(unsigned int appid, unsigned char *msg) +{ + int rc; + //LOGP(DCAPI, LOGL_DEBUG, "%s(%u)\n", __func__, appid); + rc = capi20_put_message(appid, msg); + if (rc) + fprintf(stderr, "capi20_put_message: %s\n", capi_info2str(rc)); +} + +static void cb_debugmsg(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + osmo_vlogp(DCAPI, LOGL_DEBUG, __FILE__, __LINE__, 0, fmt, ap); + va_end(ap); + LOGPC(DCAPI, LOGL_DEBUG, "\n"); +} + +static void cb_infomsg(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + osmo_vlogp(DCAPI, LOGL_INFO, __FILE__, __LINE__, 0, fmt, ap); + va_end(ap); + LOGPC(DCAPI, LOGL_INFO, "\n"); +} + +static void cb_errmsg(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + osmo_vlogp(DCAPI, LOGL_ERROR, __FILE__, __LINE__, 0, fmt, ap); + va_end(ap); + LOGPC(DCAPI, LOGL_ERROR, "\n"); +} + +capiconn_callbacks callbacks = { + .malloc = cb_malloc, + .free = cb_free, + + .disconnected = cb_disconnected, + .incoming = cb_incoming, + .connected = cb_connected, + .received = cb_datareceived, + .datasent = cb_datasent, + .chargeinfo = NULL, + + .capi_put_message = cb_put_message, + + .debugmsg = cb_debugmsg, + .infomsg = cb_infomsg, + .errmsg = cb_errmsg, +}; + +/*********************************************************************** + * initialization / integration + ***********************************************************************/ + +/* debug print callback for capi20 to log via libosmocore logging framework */ +static int cb_capi_dprintf(const char *file, int line, const char *func, const char *fmt, va_list va) +{ + osmo_vlogp(DLCAPI20, LOGL_DEBUG, file, line, 0, fmt, va); + return 0; +} + +/* osmocom select file descriptor call-back for capi20 file descriptor */ +static int capifd_cb(struct osmo_fd *ofd, unsigned int what) +{ + struct capi_inst *ci = ofd->data; + int rc; + + if (what & OSMO_FD_READ) { + unsigned char *msg = NULL; + rc = capi20_get_message(ci->applid, &msg); + if (rc == 0) { + const char *str = capi20_cmd2str(CAPIMSG_COMMAND(msg), CAPIMSG_SUBCOMMAND(msg)); + LOGP(DCAPI, LOGL_DEBUG, "Rx from CAPI: %s\n", str); + capiconn_inject(ci->applid, msg); + } + } + + return 0; +} + +struct capi_inst *capi_init(void *ctx) +{ + int rc; + + /* libcapi20 debug log print callback */ + register_dbg_vprintf(cb_capi_dprintf); + + struct capi_inst *ci = talloc_zero(ctx, struct capi_inst); + if (!ci) + return NULL; + + rc = capi20_register(1, 8, 128, &ci->applid); + if (rc != 0) { + fprintf(stderr, "Error in capi_register: %s\n", capi_info2str(rc)); + talloc_free(ci); + exit(1); + } + + ci->cc_ctx = capiconn_getcontext(ci->applid, &callbacks); + if (!ci->cc_ctx) { + fprintf(stderr, "get_coontext\n"); + capi20_release(ci->applid); + talloc_free(ci); + exit(1); + } + + struct capi_contrinfo cinfo = {0, 0, 0}; + capiconn_addcontr(ci->cc_ctx, 1, &cinfo); + rc = capiconn_listen(ci->cc_ctx, 1, CIPMASK_ALL, 0); + if (rc) { + fprintf(stderr, "Error in capiconn_listen: %s\n", capi_info2str(rc)); + capi20_release(ci->applid); + talloc_free(ci); + exit(1); + } + osmo_fd_setup(&ci->ofd, capi20_fileno(ci->applid), OSMO_FD_READ, capifd_cb, ci, 0); + osmo_fd_register(&ci->ofd); + + return ci; +} + +static const struct log_info_cat log_info_cat[] = { + [DCAPI] = { + .name = "DCAPI", + .description = "ISDN CAPI Interface", + .enabled = 1, + .loglevel = LOGL_DEBUG, + }, + [DLCAPI20] = { + .name = "DLCAPI02", + .description = "ISDN libcapi20", + .enabled = 1, + .loglevel = LOGL_DEBUG, + }, +}; + +static const struct log_info log_info = { + .cat = log_info_cat, + .num_cat = ARRAY_SIZE(log_info_cat), +}; + + +int main(int argc, char **argv) +{ + void *ctx = talloc_named_const(NULL, 1, "capi-test"); + + osmo_init_logging2(ctx, &log_info); + capi_init(ctx); + + while (1) { + osmo_select_main(0); + } +} diff --git a/capiconn.c b/capiconn.c index 3fa53b6..f11a86c 100644 --- a/capiconn.c +++ b/capiconn.c @@ -27,7 +27,6 @@ #include #include -#include "isdntun.h" #include "capiconn.h" /* xxxxxxxxxxxxxxxxxx */