diff options
Diffstat (limited to 'openbsc/src/libabis')
-rw-r--r-- | openbsc/src/libabis/e1_input.c | 36 | ||||
-rw-r--r-- | openbsc/src/libabis/e1_input_vty.c | 170 | ||||
-rw-r--r-- | openbsc/src/libabis/input/dahdi.c | 44 | ||||
-rw-r--r-- | openbsc/src/libabis/input/lapd.c | 78 | ||||
-rw-r--r-- | openbsc/src/libabis/input/lapd.h | 16 |
5 files changed, 300 insertions, 44 deletions
diff --git a/openbsc/src/libabis/e1_input.c b/openbsc/src/libabis/e1_input.c index 97dcd3364..a6661b785 100644 --- a/openbsc/src/libabis/e1_input.c +++ b/openbsc/src/libabis/e1_input.c @@ -39,17 +39,19 @@ #endif #include <osmocom/core/select.h> +#include <osmocom/core/linuxlist.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/rate_ctr.h> + #include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <openbsc/e1_input.h> #include <openbsc/abis_nm.h> #include <openbsc/abis_rsl.h> -#include <osmocom/core/linuxlist.h> #include <openbsc/subchan_demux.h> #include <openbsc/trau_frame.h> #include <openbsc/trau_mux.h> -#include <osmocom/core/talloc.h> #include <openbsc/signal.h> #include <openbsc/misdn.h> @@ -65,6 +67,31 @@ LLIST_HEAD(e1inp_line_list); static void *tall_sigl_ctx; +static const struct rate_ctr_desc e1inp_ctr_d[] = { + [E1I_CTR_HDLC_ABORT] = { + "hdlc.abort", "HDLC abort" + }, + [E1I_CTR_HDLC_BADFCS] = { + "hdlc.bad_fcs", "HLDC Bad FCS" + }, + [E1I_CTR_HDLC_OVERR] = { + "hdlc.overrun", "HDLC Overrun" + }, + [E1I_CTR_ALARM] = { + "alarm", "Alarm" + }, + [E1I_CTR_REMOVED] = { + "removed", "Line removed" + }, +}; + +static const struct rate_ctr_group_desc e1inp_ctr_g_d = { + .group_name_prefix = "e1inp", + .group_description = "E1 Input subsystem", + .num_ctr = ARRAY_SIZE(e1inp_ctr_d), + .ctr_desc = e1inp_ctr_d, +}; + /* * pcap writing of the misdn load * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat @@ -360,8 +387,10 @@ struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name) return NULL; line->driver = driver; - line->num = e1_nr; + + line->rate_ctr = rate_ctr_group_alloc(line, &e1inp_ctr_g_d, line->num); + for (i = 0; i < NUM_E1_TS; i++) { line->ts[i].num = i+1; line->ts[i].line = line; @@ -570,6 +599,7 @@ int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi) if (!link) return -EINVAL; + isd.line = ts->line; isd.link_type = link->type; isd.trx = link->trx; isd.tei = tei; diff --git a/openbsc/src/libabis/e1_input_vty.c b/openbsc/src/libabis/e1_input_vty.c index b211e818f..eb34aa188 100644 --- a/openbsc/src/libabis/e1_input_vty.c +++ b/openbsc/src/libabis/e1_input_vty.c @@ -20,30 +20,36 @@ #include <stdlib.h> #include <unistd.h> +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> +#include <osmocom/gsm/gsm_utils.h> + #include <osmocom/vty/command.h> #include <osmocom/vty/buffer.h> #include <osmocom/vty/vty.h> #include <osmocom/vty/logging.h> +#include <osmocom/vty/misc.h> #include <osmocom/vty/telnet_interface.h> -#include <osmocom/core/linuxlist.h> #include <openbsc/gsm_data.h> #include <openbsc/e1_input.h> -#include <osmocom/core/utils.h> -#include <osmocom/gsm/gsm_utils.h> -#include <osmocom/core/talloc.h> #include <openbsc/vty.h> #include <openbsc/debug.h> #include "../../bscconfig.h" +/* CONFIG */ + #define E1_DRIVER_NAMES "(misdn|dahdi)" #define E1_DRIVER_HELP "mISDN supported E1 Card\n" \ "DAHDI supported E1/T1/J1 Card\n" +#define E1_LINE_HELP "Configure E1/T1/J1 Line\n" "Line Number\n" + DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd, "e1_line <0-255> driver " E1_DRIVER_NAMES, - "Configure E1/T1/J1 Line\n" "Line Number\n" "Set driver for this line\n" + E1_LINE_HELP "Set driver for this line\n" E1_DRIVER_HELP) { struct e1inp_line *line; @@ -63,6 +69,27 @@ DEFUN(cfg_e1line_driver, cfg_e1_line_driver_cmd, return CMD_SUCCESS; } +DEFUN(cfg_e1line_name, cfg_e1_line_name_cmd, + "e1_line <0-255> name .LINE", + E1_LINE_HELP "Set name for this line\n" "Human readable name\n") +{ + struct e1inp_line *line; + int e1_nr = atoi(argv[0]); + + line = e1inp_line_get(e1_nr); + if (!line) { + vty_out(vty, "%% Line %d doesn't exist%s", e1_nr, VTY_NEWLINE); + return CMD_WARNING; + } + if (line->name) { + talloc_free((void *)line->name); + line->name = NULL; + } + line->name = talloc_strdup(line, argv[1]); + + return CMD_SUCCESS; +} + DEFUN(cfg_e1inp, cfg_e1inp_cmd, "e1_input", "Configure E1/T1/J1 TDM input\n") @@ -84,10 +111,138 @@ static int e1inp_config_write(struct vty *vty) llist_for_each_entry(line, &e1inp_line_list, list) { vty_out(vty, " e1_line %u driver %s%s", line->num, line->driver->name, VTY_NEWLINE); + if (line->name) + vty_out(vty, " e1_line %u name %s%s", line->num, + line->name, VTY_NEWLINE); + } + return CMD_SUCCESS; +} + +/* SHOW */ + +static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv) +{ + vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE); +} + +DEFUN(show_e1drv, + show_e1drv_cmd, + "show e1_driver", + SHOW_STR "Display information about available E1 drivers\n") +{ + struct e1inp_driver *drv; + + llist_for_each_entry(drv, &e1inp_driver_list, list) + e1drv_dump_vty(vty, drv); + + return CMD_SUCCESS; +} + +static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line, + int stats) +{ + vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s", + line->num, line->name ? line->name : "", + line->driver->name, VTY_NEWLINE); + if (stats) + vty_out_rate_ctr_group(vty, " ", line->rate_ctr); +} + +DEFUN(show_e1line, + show_e1line_cmd, + "show e1_line [line_nr] [stats]", + SHOW_STR "Display information about a E1 line\n" + "E1 Line Number\n") +{ + struct e1inp_line *line; + int stats = 0; + + if (argc >= 1 && strcmp(argv[0], "stats")) { + int num = atoi(argv[0]); + if (argc >= 2) + stats = 1; + llist_for_each_entry(line, &e1inp_line_list, list) { + if (line->num == num) { + e1line_dump_vty(vty, line, stats); + return CMD_SUCCESS; + } + } + return CMD_WARNING; + } + + if (argc >= 1 && !strcmp(argv[0], "stats")) + stats = 1; + + llist_for_each_entry(line, &e1inp_line_list, list) + e1line_dump_vty(vty, line, stats); + + return CMD_SUCCESS; +} + +static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts) +{ + if (ts->type == E1INP_TS_TYPE_NONE) + return; + vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s", + ts->num, ts->line->num, e1inp_tstype_name(ts->type), + VTY_NEWLINE); +} + +DEFUN(show_e1ts, + show_e1ts_cmd, + "show e1_timeslot [line_nr] [ts_nr]", + SHOW_STR "Display information about a E1 timeslot\n" + "E1 Line Number\n" "E1 Timeslot Number\n") +{ + struct e1inp_line *line = NULL; + struct e1inp_ts *ts; + int ts_nr; + + if (argc == 0) { + llist_for_each_entry(line, &e1inp_line_list, list) { + for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) { + ts = &line->ts[ts_nr]; + e1ts_dump_vty(vty, ts); + } + } + return CMD_SUCCESS; + } + if (argc >= 1) { + int num = atoi(argv[0]); + struct e1inp_line *l; + llist_for_each_entry(l, &e1inp_line_list, list) { + if (l->num == num) { + line = l; + break; + } + } + if (!line) { + vty_out(vty, "E1 line %s is invalid%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + if (argc >= 2) { + ts_nr = atoi(argv[1]); + if (ts_nr >= NUM_E1_TS) { + vty_out(vty, "E1 timeslot %s is invalid%s", + argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + ts = &line->ts[ts_nr]; + e1ts_dump_vty(vty, ts); + return CMD_SUCCESS; + } else { + for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) { + ts = &line->ts[ts_nr]; + e1ts_dump_vty(vty, ts); + } + return CMD_SUCCESS; } return CMD_SUCCESS; } + struct cmd_node e1inp_node = { E1INP_NODE, "%s(e1_input)#", @@ -99,6 +254,11 @@ int e1inp_vty_init(void) install_element(CONFIG_NODE, &cfg_e1inp_cmd); install_node(&e1inp_node, e1inp_config_write); install_element(E1INP_NODE, &cfg_e1_line_driver_cmd); + install_element(E1INP_NODE, &cfg_e1_line_name_cmd); + + install_element_ve(&show_e1drv_cmd); + install_element_ve(&show_e1line_cmd); + install_element_ve(&show_e1ts_cmd); return 0; } diff --git a/openbsc/src/libabis/input/dahdi.c b/openbsc/src/libabis/input/dahdi.c index 6f8983763..6802a1e85 100644 --- a/openbsc/src/libabis/input/dahdi.c +++ b/openbsc/src/libabis/input/dahdi.c @@ -40,6 +40,8 @@ #include <osmocom/core/select.h> #include <osmocom/core/msgb.h> +#include <osmocom/core/rate_ctr.h> + #include <openbsc/debug.h> #include <openbsc/gsm_data.h> #include <openbsc/abis_nm.h> @@ -68,6 +70,7 @@ static const struct value_string dahdi_evt_names[] = { static void handle_dahdi_exception(struct e1inp_ts *ts) { int rc, evt; + struct e1inp_line *line = ts->line; struct input_signal_data isd; rc = ioctl(ts->driver.dahdi.fd.fd, DAHDI_GETEVENT, &evt); @@ -84,11 +87,24 @@ static void handle_dahdi_exception(struct e1inp_ts *ts) case DAHDI_EVENT_ALARM: /* we should notify the code that the line is gone */ osmo_signal_dispatch(SS_INPUT, S_INP_LINE_ALARM, &isd); + rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_ALARM]); break; case DAHDI_EVENT_NOALARM: /* alarm has gone, we should re-start the SABM requests */ osmo_signal_dispatch(SS_INPUT, S_INP_LINE_NOALARM, &isd); break; + case DAHDI_EVENT_ABORT: + rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_ABORT]); + break; + case DAHDI_EVENT_OVERRUN: + rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_OVERR]); + break; + case DAHDI_EVENT_BADFCS: + rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_BADFCS]); + break; + case DAHDI_EVENT_REMOVED: + rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_REMOVED]); + break; } } @@ -100,7 +116,7 @@ static int handle_ts1_read(struct osmo_fd *bfd) struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI TS1"); lapd_mph_type prim; unsigned int sapi, tei; - int ilen, ret; + int ilen, ret, error = 0; uint8_t *idata; if (!msg) @@ -122,9 +138,21 @@ static int handle_ts1_read(struct osmo_fd *bfd) DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei); - idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim); - if (!idata && prim == 0) - return -EIO; + idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim, &error); + if (!idata) { + switch(error) { + case LAPD_ERR_UNKNOWN_TEI: + /* We don't know about this TEI, probably the BSC + * lost local states (it crashed or it was stopped), + * notify the driver to see if it can do anything to + * recover the existing signalling links with the BTS. + */ + e1inp_event(e1i_ts, S_INP_TEI_UNKNOWN, tei, sapi); + return -EIO; + } + if (prim == 0) + return -EIO; + } msgb_pull(msg, 2); @@ -421,11 +449,17 @@ static int dahdi_e1_setup(struct e1inp_line *line) char openstr[128]; struct e1inp_ts *e1i_ts = &line->ts[idx]; struct osmo_fd *bfd = &e1i_ts->driver.dahdi.fd; + int dev_nr; + + /* DAHDI device names/numbers just keep incrementing + * even over multiple boards. So TS1 of the second + * board will be 32 */ + dev_nr = line->num * (NUM_E1_TS-1) + ts; bfd->data = line; bfd->priv_nr = ts; bfd->cb = dahdi_fd_cb; - snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", ts); + snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", dev_nr); switch (e1i_ts->type) { case E1INP_TS_TYPE_NONE: diff --git a/openbsc/src/libabis/input/lapd.c b/openbsc/src/libabis/input/lapd.c index d0fab1815..2934b58ca 100644 --- a/openbsc/src/libabis/input/lapd.c +++ b/openbsc/src/libabis/input/lapd.c @@ -31,7 +31,6 @@ #include <stdio.h> #include <string.h> -#include <assert.h> #include <errno.h> #include "lapd.h" @@ -190,7 +189,7 @@ static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei) static void lapd_tei_set_state(struct lapd_tei *teip, int newstate) { - DEBUGP(DMI, "state change on TEI %d: %s -> %s\n", teip->tei, + LOGP(DMI, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n", teip->tei, lapd_tei_states[teip->state], lapd_tei_states[newstate]); teip->state = newstate; }; @@ -234,7 +233,7 @@ static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi) { struct lapd_sap *sap = talloc_zero(teip, struct lapd_sap); - LOGP(DMI, LOGL_INFO, "Allocating SAP for SAPI=%u / TEI=%u\n", + LOGP(DMI, LOGL_INFO, "LAPD Allocating SAP for SAPI=%u / TEI=%u\n", sapi, teip->tei); sap->sapi = sapi; @@ -254,8 +253,9 @@ static void lapd_sap_set_state(struct lapd_tei *teip, uint8_t sapi, if (!sap) return; - DEBUGP(DMI, "state change on TEI %u / SAPI %u: %s -> %s\n", teip->tei, - sapi, lapd_sap_states[sap->state], lapd_sap_states[newstate]); + LOGP(DMI, LOGL_INFO, "LAPD state change on TEI %u / SAPI %u: " + "%s -> %s\n", teip->tei, sapi, + lapd_sap_states[sap->state], lapd_sap_states[newstate]); switch (sap->state) { case SAP_STATE_SABM_RETRANS: if (newstate != SAP_STATE_SABM_RETRANS) @@ -281,11 +281,12 @@ static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len) uint8_t resp[8]; struct lapd_tei *teip; - DEBUGP(DMI, "TEIMGR: entity %x, ref %x, mt %x, action %x, e %x\n", entity, ref, mt, action, e); + DEBUGP(DMI, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, e %x\n", + entity, ref, mt, action, e); switch (mt) { case 0x01: /* IDENTITY REQUEST */ - DEBUGP(DMI, "TEIMGR: identity request for TEI %u\n", action); + DEBUGP(DMI, "LAPD TEIMGR: identity request for TEI %u\n", action); teip = teip_from_tei(li, action); if (!teip) { @@ -302,15 +303,16 @@ static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len) lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED); break; default: - LOGP(DMI, LOGL_NOTICE, "TEIMGR: unknown mt %x action %x\n", + LOGP(DMI, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x action %x\n", mt, action); break; }; }; /* General input function for any data received for this LAPD instance */ -uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len, - int *ilen, lapd_mph_type *prim) +uint8_t * +lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len, + int *ilen, lapd_mph_type *prim, int *error) { uint8_t sapi, cr, tei, command; int pf, ns, nr; @@ -325,13 +327,15 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len *prim = 0; if (len < 2) { - DEBUGP(DMI, "len %d < 2\n", len); + LOGP(DMI, LOGL_ERROR, "LAPD receive len %d < 2, ignoring\n", len); + *error = LAPD_ERR_BAD_LEN; return NULL; }; if ((data[0] & 1) != 0 || (data[1] & 1) != 1) { - DEBUGP(DMI, "address field %x/%x not well formed\n", data[0], - data[1]); + LOGP(DMI, LOGL_ERROR, "LAPD address field %x/%x not well formed\n", + data[0], data[1]); + *error = LAPD_ERR_BAD_ADDR; return NULL; }; @@ -342,7 +346,8 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len //DEBUGP(DMI, " address sapi %x tei %d cmd %d cr %d\n", sapi, tei, command, cr); if (len < 3) { - DEBUGP(DMI, "len %d < 3\n", len); + LOGP(DMI, LOGL_ERROR, "LAPD receive len %d < 3, ignoring\n", len); + *error = LAPD_ERR_BAD_LEN; return NULL; }; @@ -353,14 +358,22 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len nr = -1; if ((data[2] & 1) == 0) { typ = LAPD_TYPE_I; - assert(len >= 4); + if (len < 4) { + LOGP(DMI, LOGL_ERROR, "LAPD I frame, len %d < 4\n", len); + *error = LAPD_ERR_BAD_LEN; + return NULL; + } ns = data[2] >> 1; nr = data[3] >> 1; pf = data[3] & 1; cmd = LAPD_CMD_I; } else if ((data[2] & 3) == 1) { typ = LAPD_TYPE_S; - assert(len >= 4); + if (len < 4) { + LOGP(DMI, LOGL_ERROR, "LAPD S frame, len %d < 4\n", len); + *error = LAPD_ERR_BAD_LEN; + return NULL; + } nr = data[3] >> 1; pf = data[3] & 1; switch (data[2]) { @@ -374,7 +387,8 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len cmd = LAPD_CMD_REJ; break; default: - LOGP(DMI, LOGL_ERROR, "unknown LAPD S cmd %x\n", data[2]); + LOGP(DMI, LOGL_ERROR, "LAPD unknown S cmd %x\n", data[2]); + *error = LAPD_ERR_UNKNOWN_S_CMD; return NULL; }; } else if ((data[2] & 3) == 3) { @@ -405,8 +419,9 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len break; default: - LOGP(DMI, LOGL_ERROR, "unknown U cmd %x " + LOGP(DMI, LOGL_ERROR, "LAPD unknown U cmd %x " "(pf %x data %x)\n", val, pf, data[2]); + *error = LAPD_ERR_UNKNOWN_U_CMD; return NULL; }; }; @@ -421,13 +436,14 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len teip = teip_from_tei(li, tei); if (!teip) { - LOGP(DMI, LOGL_NOTICE, "Unknown TEI %u\n", tei); + LOGP(DMI, LOGL_NOTICE, "LAPD Unknown TEI %u\n", tei); + *error = LAPD_ERR_UNKNOWN_TEI; return NULL; } sap = lapd_sap_find(teip, sapi); if (!sap) { - LOGP(DMI, LOGL_INFO, "No SAP for TEI=%u / SAPI=%u, " + LOGP(DMI, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, " "allocating\n", tei, sapi); sap = lapd_sap_alloc(teip, sapi); } @@ -440,12 +456,15 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len switch (cmd) { case LAPD_CMD_I: if (ns != sap->vr) { - DEBUGP(DMI, "ns %d != vr %d\n", ns, sap->vr); + DEBUGP(DMI, "LAPD ns %d != vr %d\n", ns, sap->vr); if (ns == ((sap->vr - 1) & 0x7f)) { - DEBUGP(DMI, "DOUBLE FRAME, ignoring\n"); + LOGP(DMI, LOGL_NOTICE, "LAPD double frame, " + "ignoring\n"); cmd = 0; // ignore } else { - assert(0); + LOGP(DMI, LOGL_ERROR, "LAPD Out of order " + "ns %d != vr %d, ignoring\n", ns, sap->vr); + return NULL; }; } else { //printf("IN SEQUENCE\n"); @@ -560,7 +579,7 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len */ /* interrogating us, send rr */ - DEBUGP(DMI, "Sending RR response\n"); + DEBUGP(DMI, "LAPD Sending RR response\n"); resp[l++] = data[0]; resp[l++] = (tei << 1) | 1; resp[l++] = 0x01; // rr @@ -577,6 +596,7 @@ uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len return contents; } + *error = LAPD_ERR_BAD_CMD; return NULL; }; @@ -587,7 +607,7 @@ static int lapd_send_sabm(struct lapd_instance *li, uint8_t tei, uint8_t sapi) if (!msg) return -ENOMEM; - DEBUGP(DMI, "Sending SABM for TEI=%u, SAPI=%u\n", tei, sapi); + LOGP(DMI, LOGL_INFO, "LAPD Sending SABM for TEI=%u, SAPI=%u\n", tei, sapi); msgb_put_u8(msg, (sapi << 2) | (li->network_side ? 2 : 0)); msgb_put_u8(msg, (tei << 1) | 1); @@ -662,15 +682,15 @@ void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi, struct lapd_sap *sap; if (!teip) { - LOGP(DMI, LOGL_ERROR, "Cannot transmit on non-existing " - "TEI %u\n", tei); + LOGP(DMI, LOGL_ERROR, "LAPD Cannot transmit on " + "non-existing TEI %u\n", tei); return; } sap = lapd_sap_find(teip, sapi); if (!sap) { - LOGP(DMI, LOGL_INFO, "Tx on unknown SAPI=%u in TEI=%u, " - "allocating\n", sapi, tei); + LOGP(DMI, LOGL_INFO, "LAPD Tx on unknown SAPI=%u " + "in TEI=%u, allocating\n", sapi, tei); sap = lapd_sap_alloc(teip, sapi); } diff --git a/openbsc/src/libabis/input/lapd.h b/openbsc/src/libabis/input/lapd.h index fb980d104..dd22028ab 100644 --- a/openbsc/src/libabis/input/lapd.h +++ b/openbsc/src/libabis/input/lapd.h @@ -26,8 +26,20 @@ struct lapd_instance { struct llist_head tei_list; /* list of TEI in this LAPD instance */ }; -extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data, unsigned int len, - int *ilen, lapd_mph_type *prim); +enum lapd_recv_errors { + LAPD_ERR_NONE = 0, + LAPD_ERR_BAD_LEN, + LAPD_ERR_BAD_ADDR, + LAPD_ERR_UNKNOWN_S_CMD, + LAPD_ERR_UNKNOWN_U_CMD, + LAPD_ERR_UNKNOWN_TEI, + LAPD_ERR_BAD_CMD, + __LAPD_ERR_MAX +}; + +extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data, + unsigned int len, int *ilen, lapd_mph_type *prim, + int *error); extern void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi, uint8_t *data, unsigned int len); |