aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/libabis
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/libabis')
-rw-r--r--openbsc/src/libabis/e1_input.c36
-rw-r--r--openbsc/src/libabis/e1_input_vty.c170
-rw-r--r--openbsc/src/libabis/input/dahdi.c44
-rw-r--r--openbsc/src/libabis/input/lapd.c78
-rw-r--r--openbsc/src/libabis/input/lapd.h16
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);