#include <errno.h>
#include <stdio.h>
-#include <osmocore/msgb.h>
-#include <osmocore/rsl.h>
-#include <osmocore/tlv.h>
-#include <osmocore/gsm48_ie.h>
-#include <osmocore/signal.h>
-#include <osmocore/protocol/gsm_04_08.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/gsm48_ie.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/signal.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/lapdm.h>
/* GSM 05.02 ยง6.3.1.3 Mapping of BCCH data */
switch (si_hdr->system_information) {
case GSM48_MT_RR_SYSINFO_1:
- fprintf(stderr, "\tSI1");
#ifdef BCCH_TC_CHECK
if (tc != 0)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI1 on the wrong TC: %d\n", tc);
#endif
if (!app_state.has_si1) {
struct gsm48_system_information_type_1 *si1 =
0xff, 0x01);
app_state.has_si1 = 1;
+ LOGP(DRR, LOGL_ERROR, "SI1 received.\n");
}
break;
case GSM48_MT_RR_SYSINFO_2:
- fprintf(stderr, "\tSI2");
#ifdef BCCH_TC_CHECK
if (tc != 1)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI2 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_3:
- fprintf(stderr, "\tSI3");
#ifdef BCCH_TC_CHECK
if (tc != 2 && tc != 6)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI3 on the wrong TC: %d\n", tc);
#endif
if (app_state.ccch_mode == CCCH_MODE_NONE) {
struct gsm48_system_information_type_3 *si3 =
}
break;
case GSM48_MT_RR_SYSINFO_4:
- fprintf(stderr, "\tSI4");
#ifdef BCCH_TC_CHECK
if (tc != 3 && tc != 7)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI4 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_5:
- fprintf(stderr, "\tSI5");
break;
case GSM48_MT_RR_SYSINFO_6:
- fprintf(stderr, "\tSI6");
break;
case GSM48_MT_RR_SYSINFO_7:
- fprintf(stderr, "\tSI7");
#ifdef BCCH_TC_CHECK
if (tc != 7)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI7 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_8:
- fprintf(stderr, "\tSI8");
#ifdef BCCH_TC_CHECK
if (tc != 3)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI8 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_9:
- fprintf(stderr, "\tSI9");
#ifdef BCCH_TC_CHECK
if (tc != 4)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI9 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_13:
- fprintf(stderr, "\tSI13");
#ifdef BCCH_TC_CHECK
if (tc != 4 && tc != 0)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI13 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_16:
- fprintf(stderr, "\tSI16");
#ifdef BCCH_TC_CHECK
if (tc != 6)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI16 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_17:
- fprintf(stderr, "\tSI17");
#ifdef BCCH_TC_CHECK
if (tc != 2)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI17 on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_2bis:
- fprintf(stderr, "\tSI2bis");
#ifdef BCCH_TC_CHECK
if (tc != 5)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI2bis on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_2ter:
- fprintf(stderr, "\tSI2ter");
#ifdef BCCH_TC_CHECK
if (tc != 5 && tc != 4)
- fprintf(stderr, " on wrong TC");
+ LOGP(DRR, LOGL_ERROR, "SI2ter on the wrong TC: %d\n", tc);
#endif
break;
case GSM48_MT_RR_SYSINFO_5bis:
- fprintf(stderr, "\tSI5bis");
break;
case GSM48_MT_RR_SYSINFO_5ter:
- fprintf(stderr, "\tSI5ter");
break;
default:
fprintf(stderr, "\tUnknown SI");
break;
};
-
- fprintf(stderr, "\n");
}
* a l1ctl_tx_dm_est_req_h1 to the layer1 to follow this
* assignment. The code has been removed.
*/
-int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
+static int gsm48_rx_imm_ass(struct msgb *msg, struct osmocom_ms *ms)
{
struct gsm48_imm_ass *ia = msgb_l3(msg);
uint8_t ch_type, ch_subch, ch_ts;
arfcn = ia->chan_desc.h0.arfcn_low | (ia->chan_desc.h0.arfcn_high << 8);
- DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
"ARFCN=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
ia->chan_desc.chan_nr, arfcn, ch_ts, ch_subch,
ia->chan_desc.h0.tsc);
hsn = ia->chan_desc.h1.hsn;
maio = ia->chan_desc.h1.maio_low | (ia->chan_desc.h1.maio_high << 2);
- DEBUGP(DRR, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
+ LOGP(DRR, LOGL_NOTICE, "GSM48 IMM ASS (ra=0x%02x, chan_nr=0x%02x, "
"HSN=%u, MAIO=%u, TS=%u, SS=%u, TSC=%u) ", ia->req_ref.ra,
ia->chan_desc.chan_nr, hsn, maio, ch_ts, ch_subch,
ia->chan_desc.h1.tsc);
}
}
- DEBUGPC(DRR, "\n");
+ LOGPC(DRR, LOGL_NOTICE, "\n");
+ return 0;
+}
+
+static const char *pag_print_mode(int mode)
+{
+ switch (mode) {
+ case 0:
+ return "Normal paging";
+ case 1:
+ return "Extended paging";
+ case 2:
+ return "Paging reorganization";
+ case 3:
+ return "Same as before";
+ default:
+ return "invalid";
+ }
+}
+
+static char *chan_need(int need)
+{
+ switch (need) {
+ case 0:
+ return "any";
+ case 1:
+ return "sdch";
+ case 2:
+ return "tch/f";
+ case 3:
+ return "tch/h";
+ default:
+ return "invalid";
+ }
+}
+
+static char *mi_type_to_string(int type)
+{
+ switch (type) {
+ case GSM_MI_TYPE_NONE:
+ return "none";
+ case GSM_MI_TYPE_IMSI:
+ return "imsi";
+ case GSM_MI_TYPE_IMEI:
+ return "imei";
+ case GSM_MI_TYPE_IMEISV:
+ return "imeisv";
+ case GSM_MI_TYPE_TMSI:
+ return "tmsi";
+ default:
+ return "invalid";
+ }
+}
+
+/**
+ * This can contain two MIs. The size checking is a bit of a mess.
+ */
+static int gsm48_rx_paging_p1(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging1 *pag;
+ int len1, len2, mi_type, tag;
+ char mi_string[GSM48_MI_SIZE];
+
+ /* is there enough room for the header + LV? */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2) {
+ LOGP(DRR, LOGL_ERROR, "PagingRequest is too short.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ len1 = pag->data[0];
+ mi_type = pag->data[1] & GSM_MI_TYPE_MASK;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1) {
+ LOGP(DRR, LOGL_ERROR, "PagingRequest with wrong MI\n");
+ return -1;
+ }
+
+ if (mi_type != GSM_MI_TYPE_NONE) {
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[1], len1);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+
+ /* check if we have a MI type in here */
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3)
+ return 0;
+
+ tag = pag->data[2 + len1 + 0];
+ len2 = pag->data[2 + len1 + 1];
+ mi_type = pag->data[2 + len1 + 2] & GSM_MI_TYPE_MASK;
+ if (tag == GSM48_IE_MOBILE_ID && mi_type != GSM_MI_TYPE_NONE) {
+ if (msgb_l3len(msg) < sizeof(*pag) + 2 + len1 + 3 + len2) {
+ LOGP(DRR, LOGL_ERROR, "Optional MI does not fit here.\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2 + len1 + 2], len2);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed2),
+ mi_type_to_string(mi_type),
+ mi_string);
+ }
+ return 0;
+}
+
+static int gsm48_rx_paging_p2(struct msgb *msg, struct osmocom_ms *ms)
+{
+ struct gsm48_paging2 *pag;
+ int tag, len, mi_type;
+ char mi_string[GSM48_MI_SIZE];
+
+ if (msgb_l3len(msg) < sizeof(*pag)) {
+ LOGP(DRR, LOGL_ERROR, "Paging2 message is too small.\n");
+ return -1;
+ }
+
+ pag = msgb_l3(msg);
+ LOGP(DRR, LOGL_NOTICE, "Paging1: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi1);
+ LOGP(DRR, LOGL_NOTICE, "Paging2: %s chan %s to TMSI M(0x%x) \n",
+ pag_print_mode(pag->pag_mode),
+ chan_need(pag->cneed1), pag->tmsi2);
+
+ /* no optional element */
+ if (msgb_l3len(msg) < sizeof(*pag) + 3)
+ return 0;
+
+ tag = pag->data[0];
+ len = pag->data[1];
+ mi_type = pag->data[2] & GSM_MI_TYPE_MASK;
+
+ if (tag != GSM48_IE_MOBILE_ID)
+ return 0;
+
+ if (msgb_l3len(msg) < sizeof(*pag) + 3 + len) {
+ LOGP(DRR, LOGL_ERROR, "Optional MI does not fit in here\n");
+ return -1;
+ }
+
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), &pag->data[2], len);
+ LOGP(DRR, LOGL_NOTICE, "Paging3: %s chan %s to %s M(%s) \n",
+ pag_print_mode(pag->pag_mode),
+ "n/a ",
+ mi_type_to_string(mi_type),
+ mi_string);
+
return 0;
}
switch (sih->system_information) {
case GSM48_MT_RR_PAG_REQ_1:
+ gsm48_rx_paging_p1(msg, ms);
+ break;
case GSM48_MT_RR_PAG_REQ_2:
+ gsm48_rx_paging_p2(msg, ms);
+ break;
case GSM48_MT_RR_PAG_REQ_3:
- /* FIXME: implement decoding of paging request */
+ LOGP(DRR, LOGL_ERROR, "PAGING of type 3 is not implemented.\n");
break;
case GSM48_MT_RR_IMM_ASS:
- LOGP(DRR, LOGL_NOTICE, "Immediate assignment.\n");
+ gsm48_rx_imm_ass(msg, ms);
+ break;
+ case GSM48_MT_RR_NOTIF_NCH:
+ /* notification for voice call groups and such */
+ break;
+ case 0x07:
+ /* wireshark know that this is SI2 quater and for 3G interop */
break;
default:
LOGP(DRR, LOGL_NOTICE, "unknown PCH/AGCH type 0x%02x\n",