From a62202be31e4a790fc28c9f59d3fb4eb96ef916d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 21:46:54 +0200 Subject: [abis_nm]: Print Object Class of ip.access messages --- openbsc/src/abis_nm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index f9a7252a7..ff122dc8d 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2474,6 +2474,11 @@ static int abis_nm_rx_ipacc(struct msgb *msg) foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen); abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); + DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", + obj_class_name(foh->obj_class), foh->obj_class, + foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, + foh->obj_inst.ts_nr); + DEBUGP(DNM, "IPACCESS(0x%02x): ", foh->msg_type); switch (foh->msg_type) { -- cgit v1.2.3 From af7b2faf71931d471a3dff221ea3678fd7026635 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 21:47:31 +0200 Subject: ip.access maximum output power depends on GSM band --- openbsc/src/bsc_init.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 3d8b1b158..1dea0eb75 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -527,7 +527,21 @@ static void nm_reconfig_trx(struct gsm_bts_trx *trx) } break; case GSM_BTS_TYPE_NANOBTS: - trx->nominal_power = 20; + switch (trx->bts->band) { + case GSM_BAND_850: + case GSM_BAND_900: + trx->nominal_power = 20; + break; + case GSM_BAND_1800: + case GSM_BAND_1900: + trx->nominal_power = 23; + break; + dedfault: + fprintf(stderr, "Unsupported nanoBTS GSM band %s\n", + gsm_band_name(trx->bts->band)); + break; + } + break; default: break; } -- cgit v1.2.3 From d004a6462a839372554021108c3ae77343f6c1d0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 21:47:54 +0200 Subject: ip.access / multi-TRX: correctly identify TRX number on SW ACT REP --- openbsc/src/bsc_init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 1dea0eb75..adf37ed7f 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -405,7 +405,11 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, static int sw_activ_rep(struct msgb *mb) { struct abis_om_fom_hdr *foh = msgb_l3(mb); - struct gsm_bts_trx *trx = mb->trx; + struct gsm_bts *bts = mb->trx->bts; + struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); + + if (!trx) + return -ENODEV; switch (foh->obj_class) { case NM_OC_BASEB_TRANSC: -- cgit v1.2.3 From 746d6091d921b066f000debb2f0a844e1c5c258c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 22:11:11 +0200 Subject: [abis_nm] introduce and use abis_nm_ipaccess_rsl_connect() --- openbsc/include/openbsc/abis_nm.h | 2 ++ openbsc/src/abis_nm.c | 30 +++++++++++++++++++++++++++++- openbsc/src/bsc_init.c | 9 +-------- 3 files changed, 32 insertions(+), 9 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 3e72321c5..c3b8e556b 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -748,6 +748,8 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr, int attr_len); int abis_nm_ipaccess_restart(struct gsm_bts *bts); +int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, + u_int32_t ip, u_int16_t port, u_int8_t stream); /* Functions calling into other code parts */ enum nm_evt { diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index ff122dc8d..58dd2b86d 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2479,7 +2479,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr); - DEBUGP(DNM, "IPACCESS(0x%02x): ", foh->msg_type); + DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type); switch (foh->msg_type) { case NM_MT_IPACC_RSL_CONNECT_ACK: @@ -2602,6 +2602,34 @@ int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr, attr_len); } +int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, + u_int32_t ip, u_int16_t port, u_int8_t stream) +{ + struct in_addr ia; + u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0, + NM_ATT_IPACC_DST_IP_PORT, 0, 0, + NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 }; + + int attr_len = sizeof(attr); + + ia.s_addr = htonl(ip); + attr[1] = stream; + attr[3] = port >> 8; + attr[4] = port & 0xff; + *(u_int32_t *)(attr+6) = ia.s_addr; + + /* if ip == 0, we use the default IP */ + if (ip == 0) + attr_len -= 5; + + DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n", + inet_ntoa(ia), htons(port), stream); + + return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT, + NM_OC_BASEB_TRANSC, trx->bts->bts_nr, + trx->nr, 0xff, attr, attr_len); +} + /* restart / reboot an ip.access nanoBTS */ int abis_nm_ipaccess_restart(struct gsm_bts *bts) { diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index adf37ed7f..40047c24c 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -338,11 +338,6 @@ static unsigned char nanobts_attr_radio[] = { NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff, }; -static unsigned char nanobts_attr_e0[] = { - NM_ATT_IPACC_STREAM_ID, 0x00, - NM_ATT_IPACC_DST_IP_PORT, 0x0b, 0xbb, /* TCP PORT for RSL */ -}; - /* Callback function to be called whenever we get a GSM 12.21 state change event */ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, struct gsm_nm_state *old_state, struct gsm_nm_state *new_state) @@ -414,9 +409,7 @@ static int sw_activ_rep(struct msgb *mb) switch (foh->obj_class) { case NM_OC_BASEB_TRANSC: /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff, - nanobts_attr_e0, sizeof(nanobts_attr_e0)); + abis_nm_ipaccess_rsl_connect(trx, 0, 3003, 0); abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, trx->bts->bts_nr, trx->nr, 0xff); abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, -- cgit v1.2.3 From 35d447b02286002a668ccc0d44f10123cb37d74f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 22:49:33 +0200 Subject: [abis_nm] print ip.access stream_id in RSL connect ack --- openbsc/src/abis_nm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 58dd2b86d..2cb6d0060 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2492,6 +2492,9 @@ static int abis_nm_rx_ipacc(struct msgb *msg) DEBUGPC(DNM, "PORT=%u ", ntohs(*((u_int16_t *) TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT)))); + if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID)) + DEBUGPC(DNM, "STREAM=0x%02x ", + *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID)); DEBUGPC(DNM, "\n"); break; case NM_MT_IPACC_RSL_CONNECT_NACK: -- cgit v1.2.3 From 31a74906a3753dc69ae58d8af112f24100ee9675 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 19 Oct 2009 22:50:30 +0200 Subject: [abis_nm] print ip.access TCP port in correct byte order --- openbsc/src/abis_nm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 2cb6d0060..088794e0f 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2626,7 +2626,7 @@ int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, attr_len -= 5; DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n", - inet_ntoa(ia), htons(port), stream); + inet_ntoa(ia), port, stream); return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT, NM_OC_BASEB_TRANSC, trx->bts->bts_nr, -- cgit v1.2.3 From 8175e95222cf1c831e1fcfc1b8842aa331ef3b8d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 00:22:00 +0200 Subject: ip.access: Support multi-TRX / RSL stream ID In order to support multi-TRX configurations, we need to be able to cope with multiple RSL streams (each with their own stream identifier) inside one ip.access TCP connection. Since this is very similar to using the TEI on a E1 line, we simply recycle the logic and data fields that are used for the TEI. --- openbsc/src/input/ipaccess.c | 30 +++++++++++++-------------- openbsc/src/vty_interface.c | 49 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 24 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 2239cf152..1265982d2 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -222,20 +222,20 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, if (bfd->priv_nr == 1) { bts->oml_link = e1inp_sign_link_create(&line->ts[1-1], E1INP_SIGN_OML, bts->c0, - 0, 0xff); + bts->oml_tei, 0); } else if (bfd->priv_nr == 2) { struct e1inp_ts *e1i_ts; struct bsc_fd *newbfd; + struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id); - /* FIXME: implement this for non-0 TRX */ bfd->data = line = bts->oml_link->ts->line; - e1i_ts = &line->ts[2-1]; + e1i_ts = &line->ts[2+trx_id - 1]; newbfd = &e1i_ts->driver.ipaccess.fd; + e1inp_ts_config(e1i_ts, line, E1INP_TS_TYPE_SIGN); - bts->c0->rsl_link = - e1inp_sign_link_create(e1i_ts, - E1INP_SIGN_RSL, bts->c0, - 0, 0); + trx->rsl_link = e1inp_sign_link_create(e1i_ts, + E1INP_SIGN_RSL, trx, + trx->rsl_tei, 0); /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); bsc_unregister_fd(bfd); @@ -337,7 +337,7 @@ static int handle_ts1_read(struct bsc_fd *bfd) /* BIG FAT WARNING: bfd might no longer exist here, since ipaccess_rcvmsg() * might have free'd it !!! */ - link = e1inp_lookup_sign_link(e1i_ts, 0, hh->proto); + link = e1inp_lookup_sign_link(e1i_ts, hh->proto, 0); if (!link) { printf("no matching signalling link for hh->proto=0x%02x\n", hh->proto); msgb_free(msg); @@ -345,17 +345,17 @@ static int handle_ts1_read(struct bsc_fd *bfd) } msg->trx = link->trx; - switch (hh->proto) { - case IPAC_PROTO_RSL: + switch (link->type) { + case E1INP_SIGN_RSL: if (!rsl_up) { - e1inp_event(e1i_ts, EVT_E1_TEI_UP, 0, IPAC_PROTO_RSL); + e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); rsl_up = 1; } ret = abis_rsl_rcvmsg(msg); break; - case IPAC_PROTO_OML: + case E1INP_SIGN_OML: if (!oml_up) { - e1inp_event(e1i_ts, EVT_E1_TEI_UP, 0, IPAC_PROTO_OML); + e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); oml_up = 1; } ret = abis_nm_rcvmsg(msg); @@ -426,9 +426,8 @@ static int handle_ts1_write(struct bsc_fd *bfd) return -EINVAL; } - msg->l2h = msg->data; - ipaccess_prepend_header(msg, proto); + ipaccess_prepend_header(msg, sign_link->tei); DEBUGP(DMI, "TX %u: %s\n", ts_nr, hexdump(msg->l2h, msgb_l2len(msg))); @@ -505,7 +504,6 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) //line->driver_data = e1h; /* create virrtual E1 timeslots for signalling */ e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN); - e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN); e1i_ts = &line->ts[idx]; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index d6f1bb54e..9aa970696 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -127,17 +127,19 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts) if (bts->cell_barred) vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE); if (is_ipaccess_bts(bts)) - vty_out(vty, " Unit ID: %u/%u/0%s", + vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s", bts->ip_access.site_id, bts->ip_access.bts_id, - VTY_NEWLINE); + bts->oml_tei, VTY_NEWLINE); vty_out(vty, " NM State: "); net_dump_nmstate(vty, &bts->nm_state); vty_out(vty, " Site Mgr NM State: "); net_dump_nmstate(vty, &bts->site_mgr.nm_state); vty_out(vty, " Paging: FIXME pending requests, %u free slots%s", bts->paging.available_slots, VTY_NEWLINE); - vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); - e1isl_dump_vty(vty, bts->oml_link); + if (!is_ipaccess_bts(bts)) { + vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); + e1isl_dump_vty(vty, bts->oml_link); + } /* FIXME: oml_link, chan_desc */ } @@ -238,10 +240,11 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) VTY_NEWLINE); if (bts->cell_barred) vty_out(vty, " cell barred 1%s", VTY_NEWLINE); - if (is_ipaccess_bts(bts)) + if (is_ipaccess_bts(bts)) { vty_out(vty, " ip.access unit_id %u %u%s", bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE); - else { + vty_out(vty, " oml ip.access stream_id %u%s", bts->oml_tei, VTY_NEWLINE); + } else { config_write_e1_link(vty, &bts->oml_e1_link, " oml "); vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE); } @@ -285,8 +288,13 @@ static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx) net_dump_nmstate(vty, &trx->nm_state); vty_out(vty, " Baseband Transceiver NM State: "); net_dump_nmstate(vty, &trx->bb_transc.nm_state); - vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); - e1isl_dump_vty(vty, trx->rsl_link); + if (is_ipaccess_bts(trx->bts)) { + vty_out(vty, " ip.access stream ID: 0x%02x%s", + trx->rsl_tei, VTY_NEWLINE); + } else { + vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE); + e1isl_dump_vty(vty, trx->rsl_link); + } } DEFUN(show_trx, @@ -819,6 +827,11 @@ DEFUN(cfg_bts_type, bts->type = parse_btstype(argv[0]); + if (is_ipaccess_bts(bts)) { + /* Set the default OML Stream ID to 0xff */ + bts->oml_tei = 0xff; + } + return CMD_SUCCESS; } @@ -941,6 +954,25 @@ DEFUN(cfg_bts_unit_id, return CMD_SUCCESS; } +DEFUN(cfg_bts_stream_id, + cfg_bts_stream_id_cmd, + "oml ip.access stream_id <0-255>", + "Set the ip.access Stream ID of the OML link of this BTS\n") +{ + struct gsm_bts *bts = vty->index; + int stream_id = atoi(argv[0]); + + if (!is_ipaccess_bts(bts)) { + vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE); + return CMD_WARNING; + } + + bts->oml_tei = stream_id; + + return CMD_SUCCESS; +} + + DEFUN(cfg_bts_oml_e1, cfg_bts_oml_e1_cmd, "oml e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)", @@ -1207,6 +1239,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(BTS_NODE, &cfg_bts_tsc_cmd); install_element(BTS_NODE, &cfg_bts_bsic_cmd); install_element(BTS_NODE, &cfg_bts_unit_id_cmd); + install_element(BTS_NODE, &cfg_bts_stream_id_cmd); install_element(BTS_NODE, &cfg_bts_oml_e1_cmd); install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd); install_element(BTS_NODE, &cfg_bts_challoc_cmd); -- cgit v1.2.3 From 9bd7bc1b4c4a3ba42da46931df650837c1a7e889 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 00:50:03 +0200 Subject: input/ipaccess: remove one more static variable --- openbsc/src/input/ipaccess.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 1265982d2..386d2374e 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -236,6 +236,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, trx->rsl_link = e1inp_sign_link_create(e1i_ts, E1INP_SIGN_RSL, trx, trx->rsl_tei, 0); + e1inp_event(e1i_ts, EVT_E1_TEI_UP, trx->rsl_tei, 0); /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); bsc_unregister_fd(bfd); @@ -249,7 +250,6 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, /* FIXME: this is per BTS */ static int oml_up = 0; -static int rsl_up = 0; /* * read one ipa message from the socket @@ -347,10 +347,6 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: - if (!rsl_up) { - e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); - rsl_up = 1; - } ret = abis_rsl_rcvmsg(msg); break; case E1INP_SIGN_OML: -- cgit v1.2.3 From 77a838dff729a2d2c9bd7a4ee0b99f7dcc394ab2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 00:51:01 +0200 Subject: ip.access: use correct stream identifier when connecting RSL --- openbsc/src/bsc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 40047c24c..4010a7f31 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -409,7 +409,7 @@ static int sw_activ_rep(struct msgb *mb) switch (foh->obj_class) { case NM_OC_BASEB_TRANSC: /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_rsl_connect(trx, 0, 3003, 0); + abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, trx->bts->bts_nr, trx->nr, 0xff); abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, -- cgit v1.2.3 From a8bd6d4a341a38a65315def89f8c6e300b758bed Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 09:56:18 +0200 Subject: [abis_nm] introduce debugp_foh() function for object class printing --- openbsc/src/abis_nm.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 088794e0f..9018417d9 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -585,6 +585,14 @@ const char *nm_adm_name(u_int8_t adm) } } +static void debugp_foh(struct abis_om_fom_hdr *foh) +{ + DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", + obj_class_name(foh->obj_class), foh->obj_class, + foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, + foh->obj_inst.ts_nr); +} + /* obtain the gsm_nm_state data structure for a given object instance */ static struct gsm_nm_state * objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, @@ -799,10 +807,7 @@ static int abis_nm_rcvmsg_report(struct msgb *mb) struct abis_om_fom_hdr *foh = msgb_l3(mb); u_int8_t mt = foh->msg_type; - DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", - obj_class_name(foh->obj_class), foh->obj_class, - foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr); + debugp_foh(foh); //nmh->cfg->report_cb(mb, foh); @@ -860,7 +865,9 @@ static int abis_nm_rx_sw_act_req(struct msgb *mb) int nack = 0; int ret; - DEBUGP(DNM, "Software Activate Request "); + debugp_foh(foh); + + DEBUGPC(DNM, "SW Activate Request: "); if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) { DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class); @@ -965,10 +972,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) { struct tlv_parsed tp; - DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", - obj_class_name(foh->obj_class), foh->obj_class, - foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr); + debugp_foh(foh); if (nack_names[mt]) DEBUGPC(DNM, "%s NACK ", nack_names[mt]); @@ -1851,11 +1855,12 @@ int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8 struct abis_om_hdr *oh; struct msgb *msg = nm_msgb_alloc(); - DEBUGP(DNM, "Sending OPSTART obj_class=0x%02x obj_inst=(0x%02x, 0x%02x, 0x%02x)\n", - obj_class, i0, i1, i2); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2); + debugp_foh((struct abis_om_fom_hdr *) oh->data); + DEBUGPC(DNM, "Sending OPSTART\n"); + return abis_nm_sendmsg(bts, msg); } @@ -2474,10 +2479,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen); abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh)); - DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", - obj_class_name(foh->obj_class), foh->obj_class, - foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, - foh->obj_inst.ts_nr); + debugp_foh(foh); DEBUGPC(DNM, "IPACCESS(0x%02x): ", foh->msg_type); -- cgit v1.2.3 From 8406ec2437fcc28906b2085e305d79ae73accc2a Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 17:31:00 +0200 Subject: [nanoBTS] move nanoBTS initialization completely into state event handler --- openbsc/include/openbsc/abis_nm.h | 1 + openbsc/src/bsc_init.c | 141 ++++++++++++++++++++------------------ 2 files changed, 76 insertions(+), 66 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index c3b8e556b..599f53531 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -482,6 +482,7 @@ enum abis_nm_avail_state { NM_AVSTATE_DEPENDENCY = 5, NM_AVSTATE_DEGRADED = 6, NM_AVSTATE_NOT_INSTALLED= 7, + NM_AVSTATE_OK = 0xff, }; /* Section 9.4.13: Channel Combination */ diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 4010a7f31..3e68d7808 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -346,51 +346,84 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, struct gsm_bts_trx *trx; struct gsm_bts_trx_ts *ts; - /* This is currently only required on nanoBTS */ - - switch (evt) { - case EVT_STATECHG_OPER: - switch (obj_class) { - case NM_OC_SITE_MANAGER: - bts = container_of(obj, struct gsm_bts, site_mgr); - if (old_state->operational != 2 && new_state->operational == 2) { - abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff); - } - break; - case NM_OC_BTS: - bts = obj; - if (new_state->availability == NM_AVSTATE_DEPENDENCY) { - patch_nm_tables(bts); - abis_nm_set_bts_attr(bts, nanobts_attr_bts, - sizeof(nanobts_attr_bts)); - abis_nm_opstart(bts, NM_OC_BTS, - bts->bts_nr, 0xff, 0xff); - abis_nm_chg_adm_state(bts, NM_OC_BTS, - bts->bts_nr, 0xff, 0xff, - NM_STATE_UNLOCKED); - } - break; - case NM_OC_CHANNEL: - ts = obj; - trx = ts->trx; - if (new_state->availability == NM_AVSTATE_DEPENDENCY) { - if (ts->nr == 0 && trx == trx->bts->c0) - abis_nm_set_channel_attr(ts, NM_CHANC_BCCHComb); - else - abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull); - abis_nm_opstart(trx->bts, NM_OC_CHANNEL, - trx->bts->bts_nr, trx->nr, ts->nr); - abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL, - trx->bts->bts_nr, trx->nr, ts->nr, - NM_STATE_UNLOCKED); - } - break; - default: - break; + /* This event-driven BTS setup is currently only required on nanoBTS */ + + /* EVT_STATECHG_ADM is called after we call chg_adm_state() and would create + * endless loop */ + if (evt != EVT_STATECHG_OPER) + return 0; + + switch (obj_class) { + case NM_OC_SITE_MANAGER: + bts = container_of(obj, struct gsm_bts, site_mgr); + if (new_state->operational == 2 && + new_state->availability == NM_AVSTATE_OK) + abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff); + break; + case NM_OC_BTS: + bts = obj; + if (new_state->availability == NM_AVSTATE_DEPENDENCY) { + patch_nm_tables(bts); + abis_nm_set_bts_attr(bts, nanobts_attr_bts, + sizeof(nanobts_attr_bts)); + abis_nm_chg_adm_state(bts, obj_class, + bts->bts_nr, 0xff, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(bts, obj_class, + bts->bts_nr, 0xff, 0xff); + } + break; + case NM_OC_CHANNEL: + ts = obj; + trx = ts->trx; + if (new_state->operational == 1 && + new_state->availability == NM_AVSTATE_DEPENDENCY) { + if (ts->nr == 0 && trx == trx->bts->c0) + abis_nm_set_channel_attr(ts, NM_CHANC_BCCHComb); + else + abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull); + abis_nm_chg_adm_state(trx->bts, obj_class, + trx->bts->bts_nr, trx->nr, ts->nr, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, obj_class, + trx->bts->bts_nr, trx->nr, ts->nr); + } + break; + case NM_OC_RADIO_CARRIER: + trx = obj; + if (new_state->operational == 1 && + new_state->availability == NM_AVSTATE_OFF_LINE) { + /* Patch ARFCN into radio attribute */ + nanobts_attr_radio[5] &= 0xf0; + nanobts_attr_radio[5] |= trx->arfcn >> 8; + nanobts_attr_radio[6] = trx->arfcn & 0xff; + abis_nm_set_radio_attr(trx, nanobts_attr_radio, + sizeof(nanobts_attr_radio)); + abis_nm_chg_adm_state(trx->bts, obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, + trx->nr, 0xff); + } + if (new_state->operational == 1 && + new_state->availability == NM_AVSTATE_OK) + abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, + trx->nr, 0xff); + break; + case NM_OC_BASEB_TRANSC: + trx = container_of(obj, struct gsm_bts_trx, bb_transc); + if (new_state->operational == 1 && + new_state->availability == NM_AVSTATE_DEPENDENCY) { + abis_nm_chg_adm_state(trx->bts, obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, obj_class, + trx->bts->bts_nr, trx->nr, 0xff); + /* TRX software is active, tell it to initiate RSL Link */ + abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); } break; default: - //DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__); break; } return 0; @@ -403,29 +436,8 @@ static int sw_activ_rep(struct msgb *mb) struct gsm_bts *bts = mb->trx->bts; struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr); - if (!trx) - return -ENODEV; switch (foh->obj_class) { - case NM_OC_BASEB_TRANSC: - /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); - abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff); - abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - break; - case NM_OC_RADIO_CARRIER: - patch_nm_tables(trx->bts); - abis_nm_set_radio_attr(trx, nanobts_attr_radio, - sizeof(nanobts_attr_radio)); - abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff); - abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - break; } return 0; } @@ -881,9 +893,6 @@ static void patch_nm_tables(struct gsm_bts *bts) bs11_attr_radio[2] &= 0xf0; bs11_attr_radio[2] |= arfcn_high; bs11_attr_radio[3] = arfcn_low; - nanobts_attr_radio[5] &= 0xf0; - nanobts_attr_radio[5] |= arfcn_high; - nanobts_attr_radio[6] = arfcn_low; /* patch BSIC */ bs11_attr_bts[1] = bts->bsic; -- cgit v1.2.3 From d99fb99647cad05a8b652b5ef471ac6cdd9d527f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Oct 2009 21:54:06 +0200 Subject: [ipaccess] fix ipaccess-config (we now use TEI as stream ID) --- openbsc/src/e1_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/e1_config.c b/openbsc/src/e1_config.c index 16fd0d999..62bacf2ca 100644 --- a/openbsc/src/e1_config.c +++ b/openbsc/src/e1_config.c @@ -219,7 +219,7 @@ int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin) sign_ts = &line->ts[1-1]; rsl_ts = &line->ts[2-1]; oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, - bts->c0, 0, 0xff); + bts->c0, 0xff, 0); rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL, bts->c0, 0, 0); -- cgit v1.2.3 From cbbd49807f3f66f4a7ff6be03b5e63a95650a1c8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Oct 2009 07:33:36 +0200 Subject: [msgb] Add msgb_reset to reset an existing msgb* to the initial state The reset is useful if one msgb is supposed to be used over and over again and is avoiding to use msgb_free,msgb_alloc in the application code. --- openbsc/include/openbsc/msgb.h | 1 + openbsc/src/msgb.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/msgb.h b/openbsc/include/openbsc/msgb.h index 5ecac459b..ab3c03396 100644 --- a/openbsc/include/openbsc/msgb.h +++ b/openbsc/include/openbsc/msgb.h @@ -51,6 +51,7 @@ extern struct msgb *msgb_alloc(u_int16_t size, const char *name); extern void msgb_free(struct msgb *m); extern void msgb_enqueue(struct llist_head *queue, struct msgb *msg); extern struct msgb *msgb_dequeue(struct llist_head *queue); +extern void msgb_reset(struct msgb *m); #define msgb_l2(m) ((void *)(m->l2h)) #define msgb_l3(m) ((void *)(m->l3h)) diff --git a/openbsc/src/msgb.c b/openbsc/src/msgb.c index 52edf2dcd..edeb975a9 100644 --- a/openbsc/src/msgb.c +++ b/openbsc/src/msgb.c @@ -74,6 +74,26 @@ struct msgb *msgb_dequeue(struct llist_head *queue) return llist_entry(lh, struct msgb, list); } +void msgb_reset(struct msgb *msg) +{ + msg->len = 0; + msg->len = 0; + msg->data = msg->_data; + + msg->head = msg->data; + msg->data = msg->data; + /* reset tail pointer */ + msg->tail = msg->data; + + /* reset pointers */ + msg->bts_link = NULL; + msg->trx = NULL; + msg->lchan = NULL; + msg->l2h = NULL; + msg->l3h = NULL; + msg->smsh = NULL; +} + static __attribute__((constructor)) void on_dso_load_trau_msgb(void) { tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 1, "msgb"); -- cgit v1.2.3 From 1565bd3226594badb60cb74f0aca9ded25b4b135 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 21 Oct 2009 15:58:36 +0200 Subject: [timer] Initialize i with zero In case no timers were registered the result was not defined. --- openbsc/src/timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/timer.c b/openbsc/src/timer.c index 6f974a2c3..ffeb4aba3 100644 --- a/openbsc/src/timer.c +++ b/openbsc/src/timer.c @@ -176,7 +176,7 @@ restart: int bsc_timer_check(void) { struct timer_list *timer; - int i; + int i = 0; llist_for_each_entry(timer, &timer_list, entry) { i++; -- cgit v1.2.3 From 02c28a0fa84f52aeac074a83a3d7ffb0d8fcd814 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 20 Oct 2009 08:56:06 +0200 Subject: [debug] Use gcc attribute to enable printf checking Inform the compiler that the same rules as printf apply to the debugp method. This will check if the arguments match the format string. --- openbsc/include/openbsc/debug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 089132ea9..6ac3a5409 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -31,7 +31,7 @@ #define static_assert(exp, name) typedef int dummy##name [(exp) ? 1 : -1]; char *hexdump(const unsigned char *buf, int len); -void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...); +void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...) __attribute__ ((format (printf, 5, 6))); void debug_parse_category_mask(const char* mask); void debug_use_color(int use_color); void debug_timestamp(int enable); -- cgit v1.2.3 From e73501a4f689b658554ad8b5b511fb8576ac4034 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 21 Oct 2009 21:16:00 +0200 Subject: [ipaccess] revert commit 9bd7bc1b4c4a3ba42da46931df650837c1a7e889 Commit 9bd7bc1b4c4a3ba42da46931df650837c1a7e889 caused the RSL initialization to happen too early, resulting in the BTS bootstrapping but missing [some of?] the system information types. --- openbsc/src/input/ipaccess.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 386d2374e..1265982d2 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -236,7 +236,6 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, trx->rsl_link = e1inp_sign_link_create(e1i_ts, E1INP_SIGN_RSL, trx, trx->rsl_tei, 0); - e1inp_event(e1i_ts, EVT_E1_TEI_UP, trx->rsl_tei, 0); /* get rid of our old temporary bfd */ memcpy(newbfd, bfd, sizeof(*newbfd)); bsc_unregister_fd(bfd); @@ -250,6 +249,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg, /* FIXME: this is per BTS */ static int oml_up = 0; +static int rsl_up = 0; /* * read one ipa message from the socket @@ -347,6 +347,10 @@ static int handle_ts1_read(struct bsc_fd *bfd) switch (link->type) { case E1INP_SIGN_RSL: + if (!rsl_up) { + e1inp_event(e1i_ts, EVT_E1_TEI_UP, link->tei, link->sapi); + rsl_up = 1; + } ret = abis_rsl_rcvmsg(msg); break; case E1INP_SIGN_OML: -- cgit v1.2.3 From 2657abfe354bc548f2c90be2a627d927137cf1c8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:34:37 +0200 Subject: [db] Fix compile warnings in db.c For the compiler classmark1 is a struct and the compiler is unaware that it fits into an unsigned int. Use memcpy to copy it to a u_int8_t (the compiler should inline this). dbi_conn_quote_binary_copy works on unsigned char* change q_apdu to be unsigned char. --- openbsc/src/db.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/db.c b/openbsc/src/db.c index 270d4d90b..b86348c55 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -439,9 +439,11 @@ int db_sync_equipment(struct gsm_equipment *equip) { dbi_result result; unsigned char *cm2, *cm3; + u_int8_t classmark1; + memcpy(&classmark1, &equip->classmark1, sizeof(classmark1)); printf("DB: Sync Equipment IMEI=%s, classmark1=%02x", - equip->imei, equip->classmark1); + equip->imei, classmark1); if (equip->classmark2_len) printf(", classmark2=%s", hexdump(equip->classmark2, equip->classmark2_len)); @@ -462,7 +464,7 @@ int db_sync_equipment(struct gsm_equipment *equip) "classmark2 = %s, " "classmark3 = %s " "WHERE imei = '%s' ", - equip->classmark1, cm2, cm3, equip->imei); + classmark1, cm2, cm3, equip->imei); free(cm2); free(cm3); @@ -853,7 +855,7 @@ int db_apdu_blob_store(struct gsm_subscriber *subscr, u_int8_t *apdu) { dbi_result result; - char *q_apdu; + unsigned char *q_apdu; dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu); -- cgit v1.2.3 From 65fb0fda9d8c3de42ad86283b076c5a96763ed96 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:39:37 +0200 Subject: Forward declare methods to fix compiler warnings Put the used method in the header files or use extern in the case of a vty method used by token_auth --- openbsc/include/openbsc/gsm_04_11.h | 3 +++ openbsc/include/openbsc/timer.h | 1 + openbsc/src/token_auth.c | 3 +++ 3 files changed, 7 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h index bfa90b522..1851bba53 100644 --- a/openbsc/include/openbsc/gsm_04_11.h +++ b/openbsc/include/openbsc/gsm_04_11.h @@ -210,4 +210,7 @@ int gsm411_send_sms_lchan(struct gsm_lchan *lchan, struct gsm_sms *sms); struct gsm_sms *sms_alloc(void); void sms_free(struct gsm_sms *sms); +void _gsm411_sms_trans_free(struct gsm_trans *trans); +int gsm411_send_sms_subscr(struct gsm_subscriber *subscr, + struct gsm_sms *sms); #endif diff --git a/openbsc/include/openbsc/timer.h b/openbsc/include/openbsc/timer.h index ae67a5a1a..a1ad92cfc 100644 --- a/openbsc/include/openbsc/timer.h +++ b/openbsc/include/openbsc/timer.h @@ -67,5 +67,6 @@ int bsc_timer_pending(struct timer_list *timer); struct timeval *bsc_nearest_timer(); void bsc_prepare_timers(); int bsc_update_timers(); +int bsc_timer_check(void); #endif diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c index 695b55243..0931007ef 100644 --- a/openbsc/src/token_auth.c +++ b/openbsc/src/token_auth.c @@ -33,6 +33,9 @@ #define TOKEN_SMS_TEXT "HAR 2009 GSM. Register at http://har2009.gnumonks.org/ " \ "Your IMSI is %s, auth token is %08X, phone no is %s." +extern struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, + const char *text); + static char *build_sms_string(struct gsm_subscriber *subscr, u_int32_t token) { char *sms_str; -- cgit v1.2.3 From dc1e1058f3407dcda6c2cf42deabb863e2a80702 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:40:33 +0200 Subject: Fix warnings by removing unused variables --- openbsc/src/gsm_04_08.c | 2 -- openbsc/src/gsm_04_11.c | 4 +--- openbsc/src/transaction.c | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 9467d79a6..addfeb017 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1128,9 +1128,7 @@ int gsm48_tx_mm_info(struct gsm_lchan *lchan) struct gsm48_hdr *gh; struct gsm_network *net = lchan->ts->trx->bts->network; u_int8_t *ptr8; - u_int16_t *ptr16; int name_len, name_pad; - int i; #if 0 time_t cur_t; struct tm* cur_time; diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 59020746f..6e59eafe4 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -674,7 +674,7 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, * successfully receive the SMS. We need to investigate * the cause and take action depending on it */ - DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d (%s)\n", cause, + DEBUGP(DSMS, "RX SMS RP-ERROR, cause %d:%d (%s)\n", cause_len, cause, get_value_string(rp_cause_strs, cause)); if (!trans->sms.is_mt) { @@ -1068,8 +1068,6 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal, struct gsm_lchan *lchan; struct gsm_sms *sms; - u_int32_t token; - switch (signal) { case S_SUBSCR_ATTACHED: /* A subscriber has attached. Check if there are diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c index 950faa2f1..04eaa3c99 100644 --- a/openbsc/src/transaction.c +++ b/openbsc/src/transaction.c @@ -86,8 +86,6 @@ struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr, void trans_free(struct gsm_trans *trans) { - struct gsm_bts *bts; - switch (trans->protocol) { case GSM48_PDISC_CC: _gsm48_cc_trans_free(trans); -- cgit v1.2.3 From 8b77a34131243986fd1f0d4b9a637c652e6109d8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:42:19 +0200 Subject: [rrlp] Fix compiler warnings The apdu is static const u_int8_t. Change the signature to have a const in there to make the compiler happy, include chan_alloc.h for lchan methods. --- openbsc/include/openbsc/gsm_04_08.h | 2 +- openbsc/src/gsm_04_08.c | 2 +- openbsc/src/rrlp.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 485e240cd..8c944e6ac 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -726,7 +726,7 @@ int gsm48_mi_to_string(char *string, const int str_len, const u_int8_t *mi, cons int gsm48_send_rr_release(struct gsm_lchan *lchan); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, - u_int8_t apdu_len, u_int8_t *apdu); + u_int8_t apdu_len, const u_int8_t *apdu); int bsc_upqueue(struct gsm_network *net); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index addfeb017..40505e651 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1643,7 +1643,7 @@ static int gsm0408_rcv_rr(struct msgb *msg) } int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, - u_int8_t apdu_len, u_int8_t *apdu) + u_int8_t apdu_len, const u_int8_t *apdu) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 61bb20244..523b53f0b 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -26,6 +26,7 @@ #include #include #include +#include /* RRLP MS based position request */ static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 }; -- cgit v1.2.3 From ddd918f7ec6812f3b10835cdc317428d3e413e9b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:43:55 +0200 Subject: Fix compiler warning and cast const away. TLVP_VAL returns a const u_int8_t* and we assign it to a non const, cast const away. --- openbsc/src/abis_rsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 800f2027f..da12d9373 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -971,7 +971,7 @@ static int rsl_rx_meas_res(struct msgb *msg) } if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) { DEBUGPC(DMEAS, "L3\n"); - msg->l3h = TLVP_VAL(&tp, RSL_IE_L3_INFO); + msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO); return gsm0408_rcvmsg(msg, 0); } else DEBUGPC(DMEAS, "\n"); -- cgit v1.2.3 From 2c481b27fcd7bf109a3dbf1236e8aafd30412c30 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:44:30 +0200 Subject: Fix compiler warning. 0 does not work on strings --- openbsc/src/abis_nm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 9018417d9..369eaf6b4 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -759,7 +759,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) } if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) { new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE); - DEBUGPC(DNM, "ADM=%02s ", nm_adm_name(new_state.administrative)); + DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative)); } DEBUGPC(DNM, "\n"); -- cgit v1.2.3 From 555eba140d46a34168e2ec7c3533bb35eb8e6f25 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:46:16 +0200 Subject: Fix spelling of default --- openbsc/src/bsc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 3e68d7808..d89ab941c 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -545,7 +545,7 @@ static void nm_reconfig_trx(struct gsm_bts_trx *trx) case GSM_BAND_1900: trx->nominal_power = 23; break; - dedfault: + default: fprintf(stderr, "Unsupported nanoBTS GSM band %s\n", gsm_band_name(trx->bts->band)); break; -- cgit v1.2.3 From 0e7b0732f6651bfe5ad118bf49fbd49d356860b0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:48:59 +0200 Subject: Include e1_input.h for the e1inp_line --- openbsc/include/openbsc/ipaccess.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index 87942f270..eb17167b5 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -1,6 +1,8 @@ #ifndef _IPACCESS_H #define _IPACCESS_H +#include "e1_input.h" + struct ipaccess_head { u_int8_t zero; u_int8_t len; -- cgit v1.2.3 From ca0fcbe1573b33924b3cba8349e5777688f2ef7a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 23 Oct 2009 13:48:54 +0200 Subject: [gsm48] Make method name consistent... We use rx_rr to indicate that we have received a radio resource message but one method was using rr_rx. Fix that. --- openbsc/src/gsm_04_08.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 40505e651..cd883a3fa 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1456,7 +1456,7 @@ static int gsm0408_rcv_mm(struct msgb *msg) } /* Receive a PAGING RESPONSE message from the MS */ -static int gsm48_rr_rx_pag_resp(struct msgb *msg) +static int gsm48_rx_rr_pag_resp(struct msgb *msg) { struct gsm_bts *bts = msg->lchan->ts->trx->bts; struct gsm48_hdr *gh = msgb_l3(msg); @@ -1611,7 +1611,7 @@ static int gsm0408_rcv_rr(struct msgb *msg) DEBUGP(DRR, "GRPS SUSPEND REQUEST\n"); break; case GSM48_MT_RR_PAG_RESP: - rc = gsm48_rr_rx_pag_resp(msg); + rc = gsm48_rx_rr_pag_resp(msg); break; case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); -- cgit v1.2.3 From 73310c3c835886525b7c6eca73c79bd70d2dd21b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 10:04:02 +0200 Subject: [TLV] extend TLV parser with support for TvLV Tag-variableLength-Value is an encoding scheme used in the GPRS NS and BSSGP protocols, where the length value can be 8 or 16 bits, depending on actual demand. --- openbsc/include/openbsc/tlv.h | 46 +++++++++++++++++++++++++++++++++++++++++++ openbsc/src/tlv_parser.c | 23 ++++++++++++++++++++++ 2 files changed, 69 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/tlv.h b/openbsc/include/openbsc/tlv.h index ae88e6ed3..6da4fb16a 100644 --- a/openbsc/include/openbsc/tlv.h +++ b/openbsc/include/openbsc/tlv.h @@ -6,11 +6,33 @@ #include +/* Terminology / wording + tag length value (in bits) + + V - - 8 + LV - 8 N * 8 + TLV 8 8 N * 8 + TL16V 8 16 N * 8 + TLV16 8 8 N * 16 + TvLV 8 8/16 N * 8 + +*/ + #define LV_GROSS_LEN(x) (x+1) #define TLV_GROSS_LEN(x) (x+2) #define TLV16_GROSS_LEN(x) ((2*x)+2) #define TL16V_GROSS_LEN(x) (x+3) +#define TVLV_MAX_ONEBYTE 0x7f + +static inline u_int16_t TVLV_GROSS_LEN(u_int16_t len) +{ + if (len <= TVLV_MAX_ONEBYTE) + return TLV_GROSS_LEN(len); + else + return TL16V_GROSS_LEN(len); +} + /* TLV generation */ static inline u_int8_t *lv_put(u_int8_t *buf, u_int8_t len, @@ -49,6 +71,20 @@ static inline u_int8_t *tl16v_put(u_int8_t *buf, u_int8_t tag, u_int16_t len, return buf + len*2; } +static inline u_int8_t *tvlv_put(u_int8_t *buf, u_int8_t tag, u_int16_t len, + const u_int8_t *val) +{ + u_int8_t *ret; + + if (len <= TVLV_MAX_ONEBYTE) { + ret = tlv_put(buf, tag, len, val); + buf[1] |= 0x80; + } else + ret = tl16v_put(buf, tag, len, val); + + return ret; +} + static inline u_int8_t *msgb_tlv16_put(struct msgb *msg, u_int8_t tag, u_int8_t len, const u_int16_t *val) { u_int8_t *buf = msgb_put(msg, TLV16_GROSS_LEN(len)); @@ -62,6 +98,13 @@ static inline u_int8_t *msgb_tl16v_put(struct msgb *msg, u_int8_t tag, u_int16_t return tl16v_put(buf, tag, len, val); } +static inline u_int8_t *msgb_tvlv_put(struct msgb *msg, u_int8_t tag, u_int16_t len, + const u_int8_t *val) +{ + u_int8_t *buf = msgb_put(msg, TVLV_GROSS_LEN(len)); + return tvlv_put(buf, tag, len, val); +} + static inline u_int8_t *v_put(u_int8_t *buf, u_int8_t val) { *buf++ = val; @@ -146,6 +189,7 @@ enum tlv_type { TLV_TYPE_TV, TLV_TYPE_TLV, TLV_TYPE_TL16V, + TLV_TYPE_TvLV, }; struct tlv_def { @@ -161,6 +205,8 @@ struct tlv_parsed { struct tlv_p_entry lv[0xff]; }; +extern struct tlv_definition tvlv_att_def; + int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_t lv_tag2); diff --git a/openbsc/src/tlv_parser.c b/openbsc/src/tlv_parser.c index e835f951f..8321b880e 100644 --- a/openbsc/src/tlv_parser.c +++ b/openbsc/src/tlv_parser.c @@ -1,5 +1,8 @@ #include #include +#include + +struct tlv_definition tvlv_att_def; int tlv_dump(struct tlv_parsed *dec) { @@ -87,6 +90,20 @@ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, return -2; num_parsed++; break; + case TLV_TYPE_TvLV: + if (*(pos+1) & 0x80) { + /* like TLV, but without highest bit of len */ + if (pos + 1 > buf + buf_len) + return -1; + dec->lv[tag].val = pos+2; + dec->lv[tag].len = *(pos+1) & 0x7f; + len = dec->lv[tag].len + 2; + if (pos + len > buf + buf_len) + return -2; + num_parsed++; + break; + } + /* like TL16V, fallthrough */ case TLV_TYPE_TL16V: if (pos + 2 > buf + buf_len) return -1; @@ -103,3 +120,9 @@ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, return num_parsed; } +static __attribute__((constructor)) void on_dso_load_tlv(void) +{ + int i; + for (i = 0; i < ARRAY_SIZE(tvlv_att_def.def); i++) + tvlv_att_def.def[i].type = TLV_TYPE_TvLV; +} -- cgit v1.2.3 From 55dd443ac2c69b4a1e6cd29c3899a059d2f1905b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 10:19:14 +0200 Subject: [GPRS] add data structures for OML of NSE,CELL,NSVCE Supporting GPRS means we have a number of additional OML objects to deal with. We need to extend our gsm_bts structure to at least include the nm_state for each of those objects. --- openbsc/include/openbsc/gsm_data.h | 17 +++++++++++++++++ openbsc/src/abis_nm.c | 22 ++++++++++++++++++++++ openbsc/src/gsm_data.c | 6 ++++++ 3 files changed, 45 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index a493a69d9..d04b0c76c 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -289,6 +289,12 @@ struct gsm_envabtse { struct gsm_nm_state nm_state; }; +struct gsm_bts_gprs_nsvc { + struct gsm_bts *bts; + int id; + struct gsm_nm_state nm_state; +}; + /* One BTS */ struct gsm_bts { /* list header in net->bts_list */ @@ -356,6 +362,17 @@ struct gsm_bts { struct gsm_envabtse envabtse[4]; } bs11; }; + + /* Not entirely sure how ip.access specific this is */ + struct { + struct { + struct gsm_nm_state nm_state; + } nse; + struct { + struct gsm_nm_state nm_state; + } cell; + struct gsm_bts_gprs_nsvc nsvc[2]; + } gprs; /* transceivers */ int num_trx; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 369eaf6b4..b5f10bd19 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -656,6 +656,17 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, return NULL; nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state; break; + case NM_OC_GPRS_NSE: + nm_state = &bts->gprs.nse.nm_state; + break; + case NM_OC_GPRS_CELL: + nm_state = &bts->gprs.cell.nm_state; + break; + case NM_OC_GPRS_NSVC: + if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + return NULL; + nm_state = &bts->gprs.nsvc[obj_inst->trx_nr].nm_state; + break; } return nm_state; } @@ -695,6 +706,17 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, case NM_OC_SITE_MANAGER: obj = &bts->site_mgr; break; + case NM_OC_GPRS_NSE: + obj = &bts->gprs.nse; + break; + case NM_OC_GPRS_CELL: + obj = &bts->gprs.cell; + break; + case NM_OC_GPRS_NSVC: + if (obj_inst->trx_nr > ARRAY_SIZE(bts->gprs.nsvc)) + return NULL; + obj = &bts->gprs.nsvc[obj_inst->trx_nr]; + break; } return obj; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 6767c3fd5..de9f4b986 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -139,6 +139,7 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic) { struct gsm_bts *bts = talloc(net, struct gsm_bts); + int i; if (!bts) return NULL; @@ -153,6 +154,11 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, INIT_LLIST_HEAD(&bts->trx_list); bts->ms_max_power = 15; /* dBm */ + for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) { + bts->gprs.nsvc[i].bts = bts; + bts->gprs.nsvc[i].id = i; + } + /* create our primary TRX */ bts->c0 = gsm_bts_trx_alloc(bts); if (!bts->c0) { -- cgit v1.2.3 From daef521ea56450865d200c6384ef360dd16518e6 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 10:20:41 +0200 Subject: [OML] Add support for ip.access SET ATTRIBUTE message Since TS 12.21 implements only SET ATTRIBUTE for some object classes, ip.access had to extend it to be able to set attributes on arbitrary objects. We now introduce a function implementing that message. --- openbsc/include/openbsc/abis_nm.h | 3 +++ openbsc/src/abis_nm.c | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 599f53531..8765a7a00 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -749,6 +749,9 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type, int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr, int attr_len); int abis_nm_ipaccess_restart(struct gsm_bts *bts); +int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, + u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr, + u_int8_t *attr, u_int8_t attr_len); int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, u_int32_t ip, u_int16_t port, u_int8_t stream); diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index b5f10bd19..e00e569c7 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2662,3 +2662,12 @@ int abis_nm_ipaccess_restart(struct gsm_bts *bts) { return __simple_cmd(bts, NM_MT_IPACC_RESTART); } + +int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, + u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr, + u_int8_t *attr, u_int8_t attr_len) +{ + return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR, + obj_class, bts_nr, trx_nr, ts_nr, + attr, attr_len); +} -- cgit v1.2.3 From a1499d00a561888baa184a0113f648c3e41e01c1 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 10:25:50 +0200 Subject: [GPRS] introudce PDCH and PDCH/TCH physical channels GPRS needs PDCH (Packet Data Channels), and we need support in our data model as well as OML and RSL for it --- openbsc/include/openbsc/gsm_data.h | 2 ++ openbsc/src/abis_nm.c | 2 ++ openbsc/src/abis_rsl.c | 6 +++++- openbsc/src/gsm_data.c | 2 ++ 4 files changed, 11 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index d04b0c76c..9a277aeee 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -18,6 +18,8 @@ enum gsm_phys_chan_config { GSM_PCHAN_TCH_F, GSM_PCHAN_TCH_H, GSM_PCHAN_SDCCH8_SACCH8C, + GSM_PCHAN_PDCH, /* GPRS PDCH */ + GSM_PCHAN_TCH_F_PDCH, /* TCH/F if used, PDCH otherwise */ GSM_PCHAN_UNKNOWN, }; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index e00e569c7..03d9deff0 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -410,6 +410,8 @@ static const enum abis_nm_chan_comb chcomb4pchan[] = { [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull, [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf, [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH, + [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH, + [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH, /* FIXME: bounds check */ }; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index da12d9373..1a42b75b0 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -202,7 +202,9 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) if (cbits == 0x01) { lch_idx = 0; /* TCH/F */ - if (ts->pchan != GSM_PCHAN_TCH_F) + if (ts->pchan != GSM_PCHAN_TCH_F && + ts->pchan != GSM_PCHAN_PDCH && + ts->pchan != GSM_PCHAN_TCH_F_PDCH) fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n", chan_nr, ts->pchan); } else if ((cbits & 0x1e) == 0x02) { @@ -244,6 +246,8 @@ u_int8_t lchan2chan_nr(struct gsm_lchan *lchan) switch (ts->pchan) { case GSM_PCHAN_TCH_F: + case GSM_PCHAN_PDCH: + case GSM_PCHAN_TCH_F_PDCH: cbits = 0x01; break; case GSM_PCHAN_TCH_H: diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index de9f4b986..34642900b 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -45,6 +45,8 @@ static const char *pchan_names[] = { [GSM_PCHAN_TCH_F] = "TCH/F", [GSM_PCHAN_TCH_H] = "TCH/H", [GSM_PCHAN_SDCCH8_SACCH8C] = "SDCCH8", + [GSM_PCHAN_PDCH] = "PDCH", + [GSM_PCHAN_TCH_F_PDCH] = "TCH/F_PDCH", [GSM_PCHAN_UNKNOWN] = "UNKNOWN", }; -- cgit v1.2.3 From 9c880c9a9bbea475f8c1af48c6a836e6ce6eb91e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 10:29:22 +0200 Subject: [GPRS] Add RSL function for ip.access PDCH activation If we have a dynamic TCH/F / PDCH channel configuration, then we can either ACTIVATE CHANNEL it for a TCH/F, or we need to send this vendor-specific PDCH ACTIVATE command to use it as a PDCH. As opposed to a fixed configuration, this allows an intelligent BSC channel allocator to use otherwise idle channels as PDCH as long as no more TCH's are needed. --- openbsc/include/openbsc/abis_rsl.h | 1 + openbsc/src/abis_rsl.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 8c5547d1d..1ffea3f14 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -539,6 +539,7 @@ int rsl_ipacc_bind(struct gsm_lchan *lchan); int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, u_int16_t conn_id, u_int8_t rtp_payload2); +int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan); int abis_rsl_rcvmsg(struct msgb *msg); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 1a42b75b0..6b328bb28 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1020,6 +1020,18 @@ static int abis_rsl_rx_dchan(struct msgb *msg) case RSL_MT_MODE_MODIFY_NACK: DEBUGPC(DRSL, "CHANNEL MODE MODIFY NACK\n"); break; + case RSL_MT_IPAC_PDCH_ACT_ACK: + DEBUGPC(DRSL, "IPAC PDCH ACT ACK\n"); + break; + case RSL_MT_IPAC_PDCH_ACT_NACK: + DEBUGPC(DRSL, "IPAC PDCH ACT NACK\n"); + break; + case RSL_MT_IPAC_PDCH_DEACT_ACK: + DEBUGPC(DRSL, "IPAC PDCH DEACT ACK\n"); + break; + case RSL_MT_IPAC_PDCH_DEACT_NACK: + DEBUGPC(DRSL, "IPAC PDCH DEACT NACK\n"); + break; case RSL_MT_PHY_CONTEXT_CONF: case RSL_MT_PREPROC_MEAS_RES: case RSL_MT_TALKER_DET: @@ -1418,6 +1430,24 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, return abis_rsl_sendmsg(msg); } +int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) +{ + struct msgb *msg = rsl_msgb_alloc(); + struct abis_rsl_dchan_hdr *dh; + + dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); + init_dchan_hdr(dh, RSL_MT_IPAC_PDCH_ACT); + dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; + dh->chan_nr = lchan2chan_nr(lchan); + + DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_PDCH_ACT\n", + gsm_ts_name(lchan->ts), dh->chan_nr); + + msg->trx = lchan->ts->trx; + + return abis_rsl_sendmsg(msg); +} + static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); -- cgit v1.2.3 From 0f890b02f6e42fac6f74f786a4c194c76d8433ab Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 24 Oct 2009 09:09:05 +0200 Subject: ip.access: Use Channel Combination from config file bsc_init.c still contained a hard-coded channel configuration, i.e. CCCH_combined on TS0 of C0, and TCH/F on all other channels. Now it correctly uses the value as specified in the config file. --- openbsc/src/bsc_init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index d89ab941c..1394dd89c 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -378,10 +378,10 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, trx = ts->trx; if (new_state->operational == 1 && new_state->availability == NM_AVSTATE_DEPENDENCY) { - if (ts->nr == 0 && trx == trx->bts->c0) - abis_nm_set_channel_attr(ts, NM_CHANC_BCCHComb); - else - abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull); + patch_nm_tables(bts); + enum abis_nm_chan_comb ccomb = + abis_nm_chcomb4pchan(ts->pchan); + abis_nm_set_channel_attr(ts, ccomb); abis_nm_chg_adm_state(trx->bts, obj_class, trx->bts->bts_nr, trx->nr, ts->nr, NM_STATE_UNLOCKED); -- cgit v1.2.3 From 65bdc914f64c7ea2ccd417ef7507819bb85983f7 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Oct 2009 20:14:33 +0100 Subject: Fix segfault, use trx->bts rather than bts in patch_nm_tables() --- openbsc/src/bsc_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 1394dd89c..815fe2b6e 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -378,7 +378,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, trx = ts->trx; if (new_state->operational == 1 && new_state->availability == NM_AVSTATE_DEPENDENCY) { - patch_nm_tables(bts); + patch_nm_tables(trx->bts); enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan); abis_nm_set_channel_attr(ts, ccomb); -- cgit v1.2.3 From 288a0cf912d3a3218db3b88567590f396f43787a Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 26 Oct 2009 20:16:27 +0100 Subject: [ip.access] Add an example configuration file --- openbsc/src/openbsc.cfg.nanobts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 openbsc/src/openbsc.cfg.nanobts (limited to 'openbsc') diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts new file mode 100644 index 000000000..a12794ffd --- /dev/null +++ b/openbsc/src/openbsc.cfg.nanobts @@ -0,0 +1,38 @@ +! +! OpenBSC configuration saved from vty +! +password foo +! +line vty + no login +! +network + network country code 1 + mobile network code 1 + short name OpenBSC + long name OpenBSC + bts 0 + type nanobts + ip.access unit_id 1801 0 + band GSM1800 + location_area_code 1 + training_sequence_code 7 + base_station_id_code 63 + trx 0 + arfcn 514 + timeslot 0 + phys_chan_config CCCH+SDCCH4 + timeslot 1 + phys_chan_config SDCCH8 + timeslot 2 + phys_chan_config TCH/F + timeslot 3 + phys_chan_config TCH/F + timeslot 4 + phys_chan_config TCH/F + timeslot 5 + phys_chan_config TCH/F + timeslot 6 + phys_chan_config TCH/F + timeslot 7 + phys_chan_config TCH/F -- cgit v1.2.3 From eb429b7b44f1c39548a1995cb93484b9cbe2996e Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Mon, 26 Oct 2009 20:19:59 +0100 Subject: [TLV] Split the parser into 'parse loop' and 'parse single value' This is needed when you need to manually parse TLV blocks that don't follow the logic supported by tlv_parse but you still want to rely on working code and not fiddle with details. --- openbsc/include/openbsc/tlv.h | 3 + openbsc/src/tlv_parser.c | 173 ++++++++++++++++++++++++------------------ 2 files changed, 104 insertions(+), 72 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/tlv.h b/openbsc/include/openbsc/tlv.h index 6da4fb16a..0cf4388d8 100644 --- a/openbsc/include/openbsc/tlv.h +++ b/openbsc/include/openbsc/tlv.h @@ -207,6 +207,9 @@ struct tlv_parsed { extern struct tlv_definition tvlv_att_def; +int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val, + const struct tlv_definition *def, + const u_int8_t *buf, int buf_len); int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_t lv_tag2); diff --git a/openbsc/src/tlv_parser.c b/openbsc/src/tlv_parser.c index 8321b880e..fd0045f97 100644 --- a/openbsc/src/tlv_parser.c +++ b/openbsc/src/tlv_parser.c @@ -16,6 +16,82 @@ int tlv_dump(struct tlv_parsed *dec) return 0; } +/* o_tag: output: tag found + * o_len: output: length of the data + * o_val: output: pointer to the data + * def: input: a structure defining the valid TLV tags / configurations + * buf: input: the input data buffer to be parsed + * buf_len: input: the length of the input data buffer + * + * Also, returns the number of bytes consumed by the TLV entry + */ +int tlv_parse_one(u_int8_t *o_tag, u_int16_t *o_len, const u_int8_t **o_val, + const struct tlv_definition *def, + const u_int8_t *buf, int buf_len) +{ + u_int8_t tag; + int len; + + tag = *buf; + *o_tag = tag; + + /* FIXME: use tables for knwon IEI */ + switch (def->def[tag].type) { + case TLV_TYPE_T: + /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */ + *o_val = buf; + *o_len = 0; + len = 1; + break; + case TLV_TYPE_TV: + *o_val = buf+1; + *o_len = 1; + len = 2; + break; + case TLV_TYPE_FIXED: + *o_val = buf+1; + *o_len = def->def[tag].fixed_len; + len = def->def[tag].fixed_len + 1; + break; + case TLV_TYPE_TLV: + /* GSM TS 04.07 11.2.4: Type 4 TLV */ + if (buf + 1 > buf + buf_len) + return -1; + *o_val = buf+2; + *o_len = *(buf+1); + len = *o_len + 2; + if (len > buf_len) + return -2; + break; + case TLV_TYPE_TvLV: + if (*(buf+1) & 0x80) { + /* like TLV, but without highest bit of len */ + if (buf + 1 > buf + buf_len) + return -1; + *o_val = buf+2; + *o_len = *(buf+1) & 0x7f; + len = *o_len + 2; + if (len > buf_len) + return -2; + break; + } + /* like TL16V, fallthrough */ + case TLV_TYPE_TL16V: + if (2 > buf_len) + return -1; + *o_val = buf+3; + *o_len = *(buf+1) << 8 | *(buf+2); + len = *o_len + 3; + if (len > buf_len) + return -2; + break; + default: + return -3; + } + + return len; +} + /* dec: output: a caller-allocated pointer to a struct tlv_parsed, * def: input: a structure defining the valid TLV tags / configurations * buf: input: the input data buffer to be parsed @@ -27,94 +103,47 @@ int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def, const u_int8_t *buf, int buf_len, u_int8_t lv_tag, u_int8_t lv_tag2) { - u_int8_t tag, len = 1; - const u_int8_t *pos = buf; - int num_parsed = 0; + int ofs = 0, num_parsed = 0; + u_int16_t len; memset(dec, 0, sizeof(*dec)); if (lv_tag) { - if (pos > buf + buf_len) + if (ofs > buf_len) return -1; - dec->lv[lv_tag].val = pos+1; - dec->lv[lv_tag].len = *pos; + dec->lv[lv_tag].val = &buf[ofs+1]; + dec->lv[lv_tag].len = buf[ofs]; len = dec->lv[lv_tag].len + 1; - if (pos + len > buf + buf_len) + if (ofs + len > buf_len) return -2; num_parsed++; - pos += len; + ofs += len; } if (lv_tag2) { - if (pos > buf + buf_len) + if (ofs > buf_len) return -1; - dec->lv[lv_tag2].val = pos+1; - dec->lv[lv_tag2].len = *pos; + dec->lv[lv_tag2].val = &buf[ofs+1]; + dec->lv[lv_tag2].len = buf[ofs]; len = dec->lv[lv_tag2].len + 1; - if (pos + len > buf + buf_len) + if (ofs + len > buf_len) return -2; num_parsed++; - pos += len; + ofs += len; } - for (; pos < buf+buf_len; pos += len) { - tag = *pos; - /* FIXME: use tables for knwon IEI */ - switch (def->def[tag].type) { - case TLV_TYPE_T: - /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */ - dec->lv[tag].val = pos; - dec->lv[tag].len = 0; - len = 1; - num_parsed++; - break; - case TLV_TYPE_TV: - dec->lv[tag].val = pos+1; - dec->lv[tag].len = 1; - len = 2; - num_parsed++; - break; - case TLV_TYPE_FIXED: - dec->lv[tag].val = pos+1; - dec->lv[tag].len = def->def[tag].fixed_len; - len = def->def[tag].fixed_len + 1; - num_parsed++; - break; - case TLV_TYPE_TLV: - /* GSM TS 04.07 11.2.4: Type 4 TLV */ - if (pos + 1 > buf + buf_len) - return -1; - dec->lv[tag].val = pos+2; - dec->lv[tag].len = *(pos+1); - len = dec->lv[tag].len + 2; - if (pos + len > buf + buf_len) - return -2; - num_parsed++; - break; - case TLV_TYPE_TvLV: - if (*(pos+1) & 0x80) { - /* like TLV, but without highest bit of len */ - if (pos + 1 > buf + buf_len) - return -1; - dec->lv[tag].val = pos+2; - dec->lv[tag].len = *(pos+1) & 0x7f; - len = dec->lv[tag].len + 2; - if (pos + len > buf + buf_len) - return -2; - num_parsed++; - break; - } - /* like TL16V, fallthrough */ - case TLV_TYPE_TL16V: - if (pos + 2 > buf + buf_len) - return -1; - dec->lv[tag].val = pos+3; - dec->lv[tag].len = *(pos+1) << 8 | *(pos+2); - len = dec->lv[tag].len + 3; - if (pos + len > buf + buf_len) - return -2; - num_parsed++; - break; - } + while (ofs < buf_len) { + int rv; + u_int8_t tag; + const u_int8_t *val; + + rv = tlv_parse_one(&tag, &len, &val, def, + &buf[ofs], buf_len-ofs); + if (rv < 0) + return rv; + dec->lv[tag].val = val; + dec->lv[tag].len = len; + ofs += rv; + num_parsed++; } //tlv_dump(dec); return num_parsed; -- cgit v1.2.3 From 143f1f56d94804fdfdd3302aa65cdc14f0b955e9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Oct 2009 20:38:37 +0100 Subject: add some random thoughts on hopping and the oml interface --- openbsc/doc/gsm-hopping.txt | 54 +++++++++++++++++++++++++++++++++++++++++++ openbsc/doc/oml-interface.txt | 21 +++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 openbsc/doc/gsm-hopping.txt create mode 100644 openbsc/doc/oml-interface.txt (limited to 'openbsc') diff --git a/openbsc/doc/gsm-hopping.txt b/openbsc/doc/gsm-hopping.txt new file mode 100644 index 000000000..591093999 --- /dev/null +++ b/openbsc/doc/gsm-hopping.txt @@ -0,0 +1,54 @@ +according to GSM 05.02: + +general parameters from CCCH: +* CA cell allocation of ARFCN's (System Information / BCCH) +* FN: TDMA frame number (t1,t2,t3') in SCH + +specific parameters from channel assignment: +* MA: mobile allocation, defines set of ARFCN's, up to 64 +* MAIO: index +* HSN: hopping sequence generator number (0..64) + + +hopping sequence generation (6.2.3): + +u_int8_t rntable[114] = { + 48, 98, 63, 1, 36, 95, 78, 102, 94, 73, + 0, 64, 25, 81, 76, 59, 124, 23, 104, 100, + 101, 47, 118, 85, 18, 56, 96, 86, 54, 2, + 80, 34, 127, 13, 6, 89, 57, 103, 12, 74, + 55, 111, 75, 38, 109, 71, 112, 29, 11, 88, + 87, 19, 3, 68, 110, 26, 33, 31, 8, 45, + 82, 58, 40, 107, 32, 5, 106, 92, 62, 67, + 77, 108, 122, 37, 60, 66, 121, 42, 51, 126, + 117, 114, 4, 90, 43, 52, 53, 113, 120, 72, + 16, 49, 7, 79, 119, 61, 22, 84, 9, 97, + 125, 99, 17, 123 +}; + +/* mai=0 represents lowest ARFCN in the MA */ + + +u_int8_t hopping_mai(u_int8_t hsn, u_int32_t fn, u_int8_t maio, + u_int8_t t1, u_int8_t t2, u_int8_t t3_) +{ + u_int8_t mai; + + if (hsn == 0) /* cyclic hopping */ + mai = (fn + maio) % n; + else { + u_int32_t m, m_, t_, s; + + m = t2 + rntable[(hsn xor (t1 % 64)) + t3]; + m_ = m % (2^NBIN); + t_ = t3 % (2^NBIN); + if (m_ < n then) + s = m_; + else + s = (m_ + t_) % n; + mai = (s + maio) % n; + } + + return mai; +} + diff --git a/openbsc/doc/oml-interface.txt b/openbsc/doc/oml-interface.txt new file mode 100644 index 000000000..8ddcfea5c --- /dev/null +++ b/openbsc/doc/oml-interface.txt @@ -0,0 +1,21 @@ +oml interface design notes + +problems: + +* there is no way how to tag a command sent to the BTS, with the response + having the same tag to identify the originator of the command +* therefore, we can have e.g. both the BSC and the OML interface send a + SET ATTRIBUTE message, where the responses would end up at the wrong + query. + +the only possible solutions i can imagine: +* have some kind of exclusive locking, where the OML interface gets blocked + from the BSC and is exclusively assigned to the OML console until all commands + of the OML console have terminated. This can either be done explicitly + dynamically or on demand + +* use the OML interface synchronously, i.e. always wait for the response from + the BTS before + +* unilateral / unsolicited messages need to be broadcasted to both the BSC and + the OML console -- cgit v1.2.3 From 6eafe9137ca345078531fc607a461f397faa505b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 16 Oct 2009 08:32:58 +0200 Subject: Add USDD code from Mike Haben This is the initial checkin of the USSD code from Mike Haben. I didn't put it in the main branch as I think it still needs some cleanup. --- openbsc/include/openbsc/gsm_04_80.h | 132 ++++++++++++++++ openbsc/include/openbsc/ussd.h | 10 ++ openbsc/src/Makefile.am | 2 +- openbsc/src/gsm_04_08.c | 5 +- openbsc/src/gsm_04_80.c | 306 ++++++++++++++++++++++++++++++++++++ openbsc/src/ussd.c | 68 ++++++++ 6 files changed, 521 insertions(+), 2 deletions(-) create mode 100644 openbsc/include/openbsc/gsm_04_80.h create mode 100644 openbsc/include/openbsc/ussd.h create mode 100644 openbsc/src/gsm_04_80.c create mode 100644 openbsc/src/ussd.c (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h new file mode 100644 index 000000000..11962d81d --- /dev/null +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -0,0 +1,132 @@ +#ifndef _GSM_04_80_H +#define _GSM_04_80_H + +/* GSM TS 04.80 definitions (Supplementary Services Specification, Formats and Coding) */ + +/* Section 3.4 */ +#define GSM0480_MTYPE_RELEASE_COMPLETE 0x2A +#define GSM0480_MTYPE_FACILITY 0x3A +#define GSM0480_MTYPE_REGISTER 0x3B + +/* Section 3.5 */ +#define GSM0480_IE_FACILITY 0x1C +#define GSM0480_IE_SS_VERSION 0x7F + +/* Section 3.6.2 */ +#define GSM0480_CTYPE_INVOKE 0xA1 +#define GSM0480_CTYPE_RETURN_RESULT 0xA2 +#define GSM0480_CTYPE_RETURN_ERROR 0xA3 +#define GSM0480_CTYPE_REJECT 0xA4 + +/* Section 3.6.3 */ +#define GSM0480_COMPIDTAG_INVOKE_ID 0x02 +#define GSM0480_COMPIDTAG_LINKED_ID 0x80 + +/* Section 3.6.4 */ +#define GSM0480_OPERATION_CODE 0x02 + +/* Section 3.6.5 */ +#define GSM_0480_SEQUENCE_TAG 0x30 +#define GSM_0480_SET_TAG 0x31 + +/* Section 3.6.6 */ +#define GSM_0480_ERROR_CODE_TAG 0x02 + +/* Section 3.6.7 */ +/* Table 3.13 */ +#define GSM_0480_PROBLEM_CODE_TAG_GENERAL 0x80 +#define GSM_0480_PROBLEM_CODE_TAG_INVOKE 0x81 +#define GSM_0480_PROBLEM_CODE_TAG_RETURN_RESULT 0x82 +#define GSM_0480_PROBLEM_CODE_TAG_RETURN_ERROR 0x83 + +/* Table 3.14 */ +#define GSM_0480_GEN_PROB_CODE_UNRECOGNISED 0x00 +#define GSM_0480_GEN_PROB_CODE_MISTYPED 0x01 +#define GSM_0480_GEN_PROB_CODE_BAD_STRUCTURE 0x02 + +/* Table 3.15 */ +#define GSM_0480_INVOKE_PROB_CODE_DUPLICATE_INVOKE_ID 0x00 +#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_OPERATION 0x01 +#define GSM_0480_INVOKE_PROB_CODE_MISTYPED_PARAMETER 0x02 +#define GSM_0480_INVOKE_PROB_CODE_RESOURCE_LIMITATION 0x03 +#define GSM_0480_INVOKE_PROB_CODE_INITIATING_RELEASE 0x04 +#define GSM_0480_INVOKE_PROB_CODE_UNRECOGNISED_LINKED_ID 0x05 +#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_RESPONSE 0x06 +#define GSM_0480_INVOKE_PROB_CODE_UNEXPECTED_LINKED_OPERATION 0x07 + +/* Table 3.16 */ +#define GSM_0480_RESULT_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00 +#define GSM_0480_RESULT_PROB_CODE_RETURN_RESULT_UNEXPECTED 0x01 +#define GSM_0480_RESULT_PROB_CODE_MISTYPED_PARAMETER 0x02 + +/* Table 3.17 */ +#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_INVOKE_ID 0x00 +#define GSM_0480_ERROR_PROB_CODE_RETURN_ERROR_UNEXPECTED 0x01 +#define GSM_0480_ERROR_PROB_CODE_UNRECOGNISED_ERROR 0x02 +#define GSM_0480_ERROR_PROB_CODE_UNEXPECTED_ERROR 0x03 +#define GSM_0480_ERROR_PROB_CODE_MISTYPED_PARAMETER 0x04 + +/* Section 4.5 */ +#define GSM0480_OP_CODE_REGISTER_SS 0x0A +#define GSM0480_OP_CODE_ERASE_SS 0x0B +#define GSM0480_OP_CODE_ACTIVATE_SS 0x0C +#define GSM0480_OP_CODE_DEACTIVATE_SS 0x0D +#define GSM0480_OP_CODE_INTERROGATE_SS 0x0E +#define GSM0480_OP_CODE_NOTIFY_SS 0x10 +#define GSM0480_OP_CODE_REGISTER_PASSWORD 0x11 +#define GSM0480_OP_CODE_GET_PASSWORD 0x12 +#define GSM0480_OP_CODE_PROCESS_USS_DATA 0x13 +#define GSM0480_OP_CODE_FORWARD_CHECK_SS_IND 0x26 +#define GSM0480_OP_CODE_PROCESS_USS_REQ 0x3B +#define GSM0480_OP_CODE_USS_REQUEST 0x3C +#define GSM0480_OP_CODE_USS_NOTIFY 0x3D +#define GSM0480_OP_CODE_FORWARD_CUG_INFO 0x78 +#define GSM0480_OP_CODE_SPLIT_MPTY 0x79 +#define GSM0480_OP_CODE_RETRIEVE_MPTY 0x7A +#define GSM0480_OP_CODE_HOLD_MPTY 0x7B +#define GSM0480_OP_CODE_BUILD_MPTY 0x7C +#define GSM0480_OP_CODE_FORWARD_CHARGE_ADVICE 0x7D + +#define GSM0480_ERR_CODE_UNKNOWN_SUBSCRIBER 0x01 +#define GSM0480_ERR_CODE_ILLEGAL_SUBSCRIBER 0x09 +#define GSM0480_ERR_CODE_BEARER_SERVICE_NOT_PROVISIONED 0x0A +#define GSM0480_ERR_CODE_TELESERVICE_NOT_PROVISIONED 0x0B +#define GSM0480_ERR_CODE_ILLEGAL_EQUIPMENT 0x0C +#define GSM0480_ERR_CODE_CALL_BARRED 0x0D +#define GSM0480_ERR_CODE_ILLEGAL_SS_OPERATION 0x10 +#define GSM0480_ERR_CODE_SS_ERROR_STATUS 0x11 +#define GSM0480_ERR_CODE_SS_NOT_AVAILABLE 0x12 +#define GSM0480_ERR_CODE_SS_SUBSCRIPTION_VIOLATION 0x13 +#define GSM0480_ERR_CODE_SS_INCOMPATIBILITY 0x14 +#define GSM0480_ERR_CODE_FACILITY_NOT_SUPPORTED 0x15 +#define GSM0480_ERR_CODE_ABSENT_SUBSCRIBER 0x1B +#define GSM0480_ERR_CODE_SYSTEM_FAILURE 0x22 +#define GSM0480_ERR_CODE_DATA_MISSING 0x23 +#define GSM0480_ERR_CODE_UNEXPECTED_DATA_VALUE 0x24 +#define GSM0480_ERR_CODE_PW_REGISTRATION_FAILURE 0x25 +#define GSM0480_ERR_CODE_NEGATIVE_PW_CHECK 0x26 +#define GSM0480_ERR_CODE_NUM_PW_ATTEMPTS_VIOLATION 0x2B +#define GSM0480_ERR_CODE_UNKNOWN_ALPHABET 0x47 +#define GSM0480_ERR_CODE_USSD_BUSY 0x48 +#define GSM0480_ERR_CODE_MAX_MPTY_PARTICIPANTS 0x7E +#define GSM0480_ERR_CODE_RESOURCES_NOT_AVAILABLE 0x7F + +/* ASN.1 type-tags */ +#define ASN1_BOOLEAN_TAG 0x01 +#define ASN1_INTEGER_TAG 0x02 +#define ASN1_BIT_STRING_TAG 0x03 +#define ASN1_OCTET_STRING_TAG 0x04 +#define ASN1_NULL_TYPE_TAG 0x05 +#define ASN1_OBJECT_ID_TAG 0x06 +#define ASN1_UTF8_STRING_TAG 0x0C +#define ASN1_PRINTABLE_STRING_TAG 0x13 +#define ASN1_IA5_STRING_TAG 0x16 +#define ASN1_UNICODE_STRING_TAG 0x1E + +#include + +char* gsm0480_rcv_ussd(struct msgb *msg); +int gsm0480_send_ussd_response(struct msgb *msg, const char* response_text); +int gsm0480_send_ussd_reject(struct msgb *msg); + +#endif diff --git a/openbsc/include/openbsc/ussd.h b/openbsc/include/openbsc/ussd.h new file mode 100644 index 000000000..e7bd6d69d --- /dev/null +++ b/openbsc/include/openbsc/ussd.h @@ -0,0 +1,10 @@ +#ifndef _USSD_H +#define _USSD_H + +/* Handler function for mobile-originated USSD messages */ + +#include + +int handle_rcv_ussd(struct msgb *msg); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 919e07574..2f715bbaf 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -14,7 +14,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ - token_auth.c rrlp.c + token_auth.c rrlp.c gsm_04_80.c ussd.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index cd883a3fa..23739657d 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -48,6 +48,7 @@ #include #include #include +#include #define GSM_MAX_FACILITY 128 #define GSM_MAX_SSVERSION 128 @@ -3540,10 +3541,12 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id) break; case GSM48_PDISC_MM_GPRS: case GSM48_PDISC_SM_GPRS: - case GSM48_PDISC_NC_SS: /* mobile-originated USSD */ fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02x\n", pdisc); break; + case GSM48_PDISC_NC_SS: + rc = handle_rcv_ussd(msg); + break; default: fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02x\n", pdisc); diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c new file mode 100644 index 000000000..d0dcbc2c3 --- /dev/null +++ b/openbsc/src/gsm_04_80.c @@ -0,0 +1,306 @@ +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface + * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ + +/* (C) 2008-2009 by Harald Welte + * (C) 2008, 2009 by Holger Hans Peter Freyther + * (C) 2009 by Mike Haben + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static char ussd_string_buff[32]; +static u_int8_t last_transaction_id; +static u_int8_t last_invoke_id; + +/* Forward declarations */ +static int parse_ussd(u_int8_t *ussd); +static int parse_ussd_information_elements(u_int8_t *ussd_ie); +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length); +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length); +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length); + +static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag) +{ + msgb->data -= 2; + msgb->data[0] = tag; + msgb->data[1] = msgb->len; + msgb->len += 2; + return msgb->data; +} + +static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, u_int8_t value) +{ + msgb->data -= 3; + msgb->len += 3; + msgb->data[0] = tag; + msgb->data[1] = 1; + msgb->data[2] = value; + return msgb->data; +} + + +/* Receive a mobile-originated USSD message and return the decoded text */ +char* gsm0480_rcv_ussd(struct msgb *msg) +{ + int rc = 0; + u_int8_t* parse_ptr = msgb_l3(msg); + + memset(ussd_string_buff, 0, sizeof(ussd_string_buff)); + + if ((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) { + last_transaction_id = *parse_ptr & 0x70; + rc = parse_ussd(parse_ptr + 1); + } + + if (!rc) + DEBUGP(DMM, "Error occurred while parsing received USSD!\n"); + + return ussd_string_buff; +} + +static int parse_ussd(u_int8_t *ussd) +{ + int rc = 1; + u_int8_t msg_type = ussd[0] & 0xBF; /* message-type - section 3.4 */ + + switch(msg_type) { + case GSM0480_MTYPE_RELEASE_COMPLETE: + DEBUGP(DMM, "USS Release Complete\n"); /* could also parse out the optional Cause/Facility data */ + ussd_string_buff[0] = 0xFF; + break; + case GSM0480_MTYPE_REGISTER: + case GSM0480_MTYPE_FACILITY: + rc &= parse_ussd_information_elements(ussd+1); + break; + default: + fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n", + ussd[0]); + rc = 0; + break; + } + + return rc; +} + +static int parse_ussd_information_elements(u_int8_t *ussd_ie) +{ + int rc; + + u_int8_t iei = ussd_ie[0]; /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ + u_int8_t iei_length = ussd_ie[1]; + switch(iei) { + case GSM48_IE_CAUSE: + break; + case GSM0480_IE_FACILITY: + rc = parse_facility_ie(ussd_ie+2, iei_length); + break; + case GSM0480_IE_SS_VERSION: + break; + default: + fprintf(stderr, "Unhandled GSM 04.08 or 04.80 Information Element Identifier 0x%02x\n", + iei); + rc = 0; + break; + } + + return rc; +} + +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) +{ + int rc = 1; + u_int8_t offset = 0; + + do { + u_int8_t component_type = facility_ie[offset]; /* Component Type tag - table 3.7 */ + u_int8_t component_length = facility_ie[offset+1]; + switch(component_type) { + case GSM0480_CTYPE_INVOKE: + rc &= parse_ss_invoke(facility_ie+2, component_length); + break; + case GSM0480_CTYPE_RETURN_RESULT: + break; + case GSM0480_CTYPE_RETURN_ERROR: + break; + case GSM0480_CTYPE_REJECT: + break; + default: + fprintf(stderr, "Unknown GSM 04.80 Facility Component Type 0x%02x\n", + component_type); + rc = 0; + break; + } + offset += (component_length+2); + } while(offset < length); + + return rc; +} + +/* Parse an Invoke component - see table 3.3 */ +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) +{ + int rc = 1; + + if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) { /* mandatory part */ + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Invoke ID tag)\n", + invoke_data[0]); + } + u_int8_t offset = invoke_data[1] + 2; + last_invoke_id = invoke_data[2]; + + if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) /* optional part */ + offset += invoke_data[offset+1] + 2; /* skip over it */ + + if (invoke_data[offset] == GSM0480_OPERATION_CODE) { /* mandatory part */ + u_int8_t operation_code = invoke_data[offset+2]; + switch(operation_code) { + case GSM0480_OP_CODE_PROCESS_USS_REQ: + rc = parse_process_uss_req(invoke_data + offset + 3, length - offset - 3); + break; + default: + fprintf(stderr, "GSM 04.80 operation code 0x%02x is not yet handled\n", + operation_code); + rc = 0; + break; + } + } else { + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Operation Code tag)\n", + invoke_data[0]); + rc = 0; + } + + return rc; +} + +/* Parse the parameters of a Process UnstructuredSS Request */ +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length) +{ + int rc = 1; + int num_chars; + u_int8_t dcs; + + /* FIXME: most phones send USSD text as a 7-bit encoded octet string; the following code + also handles the case of plain ASCII text (IA5String), but other encodings might be used */ + if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) { + if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) { + dcs = uss_req_data[4]; + if ((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { + num_chars = (uss_req_data[6] * 8) / 7; + gsm_7bit_decode(ussd_string_buff, &(uss_req_data[7]), num_chars); + } + } + } else if (uss_req_data[0] == ASN1_IA5_STRING_TAG) { + num_chars = uss_req_data[1]; + memcpy(ussd_string_buff, &(uss_req_data[2]), num_chars); + } + + return rc; +} + +/* Send response to a mobile-originated ProcessUnstructuredSS-Request */ +int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + u_int8_t *ptr8; + int response_len; + + response_len = (strlen(response_text) * 7) / 8; + if (((strlen(response_text) * 7) % 8) != 0) + response_len += 1; + + msg->bts_link = in_msg->bts_link; + msg->lchan = in_msg->lchan; + + /* First put the payload text into the message */ + ptr8 = msgb_put(msg, response_len); + gsm_7bit_encode(ptr8, response_text); + + /* Then wrap it as an Octet String */ + msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG); + + /* Pre-pend the DCS octet string */ + msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F); + + /* Then wrap these as a Sequence */ + msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); + + /* Pre-pend the operation code */ + msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, GSM0480_OP_CODE_PROCESS_USS_REQ); + + /* Wrap the operation code and IA5 string as a sequence */ + msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); + + /* Pre-pend the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, last_invoke_id); + + /* Wrap this up as a Return Result component */ + msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); + + /* Wrap the component in a Facility message */ + msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + + /* And finally pre-pend the L3 header */ + gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | (1<<7); /* TI direction = 1 */ + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + return gsm48_sendmsg(msg, NULL); +} + +int gsm0480_send_ussd_reject(struct msgb *in_msg) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh; + + msg->bts_link = in_msg->bts_link; + msg->lchan = in_msg->lchan; + + /* First insert the problem code */ + msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL, GSM_0480_GEN_PROB_CODE_UNRECOGNISED); + + /* Before it insert the invoke ID */ + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, last_invoke_id); + + /* Wrap this up as a Reject component */ + msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT); + + /* Wrap the component in a Facility message */ + msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY); + + /* And finally pre-pend the L3 header */ + gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); + gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | (1<<7); /* TI direction = 1 */ + gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; + + return gsm48_sendmsg(msg, NULL); +} diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c new file mode 100644 index 000000000..5f9a45725 --- /dev/null +++ b/openbsc/src/ussd.c @@ -0,0 +1,68 @@ +/* Network-specific handling of mobile-originated USSDs. */ + +/* (C) 2008-2009 by Harald Welte + * (C) 2008, 2009 by Holger Hans Peter Freyther + * (C) 2009 by Mike Haben + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +/* This module defines the network-specific handling of mobile-originated USSD messages. */ + +#include +#include +#include +#include + +#include +#include +#include + +/* Declarations of USSD strings to be recognised */ +const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; + +/* Forward declarations of network-specific handler functions */ +static int send_own_number(struct msgb *msg); + + +/* Entrypoint - handler function common to all mobile-originated USSDs */ +int handle_rcv_ussd(struct msgb *msg) +{ + char* ussd_text_rcvd = gsm0480_rcv_ussd(msg); + + if(ussd_text_rcvd[0] == 0xFF) /* Release-Complete */ + return 0; + + if(strstr(USSD_TEXT_OWN_NUMBER, ussd_text_rcvd) != NULL) { + DEBUGP(DMM, "USSD: Own number requested\n"); + return send_own_number(msg); + } else { + DEBUGP(DMM, "Unhandled USSD %s\n", ussd_text_rcvd); + return gsm0480_send_ussd_reject(msg); + } +} + +/* A network-specific handler function */ +static int send_own_number(struct msgb *msg) +{ + char response_string[] = "Your extension is xxxxx\r"; /* Need trailing CR as EOT character */ + + char* own_number = msg->lchan->subscr->extension; + memcpy(response_string + 18, own_number, 5); + return gsm0480_send_ussd_response(msg, response_string); +} -- cgit v1.2.3 From 6307b8570061597d165d1e2cfdfbf77ca6f90073 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 16 Oct 2009 08:41:51 +0200 Subject: whitespace fixes for the USSD code This patch is not changing any actual code, just coding style fixes. --- openbsc/src/gsm_04_80.c | 91 ++++++++++++++++++++++++++++++------------------- openbsc/src/ussd.c | 16 +++++---- 2 files changed, 64 insertions(+), 43 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index d0dcbc2c3..052b0a77a 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -57,7 +57,8 @@ static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag) return msgb->data; } -static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, u_int8_t value) +static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, + u_int8_t value) { msgb->data -= 3; msgb->len += 3; @@ -69,16 +70,16 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, u_i /* Receive a mobile-originated USSD message and return the decoded text */ -char* gsm0480_rcv_ussd(struct msgb *msg) +char *gsm0480_rcv_ussd(struct msgb *msg) { int rc = 0; - u_int8_t* parse_ptr = msgb_l3(msg); + u_int8_t *parse_ptr = msgb_l3(msg); memset(ussd_string_buff, 0, sizeof(ussd_string_buff)); if ((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) { - last_transaction_id = *parse_ptr & 0x70; - rc = parse_ussd(parse_ptr + 1); + last_transaction_id = *parse_ptr & 0x70; + rc = parse_ussd(parse_ptr + 1); } if (!rc) @@ -92,9 +93,10 @@ static int parse_ussd(u_int8_t *ussd) int rc = 1; u_int8_t msg_type = ussd[0] & 0xBF; /* message-type - section 3.4 */ - switch(msg_type) { + switch (msg_type) { case GSM0480_MTYPE_RELEASE_COMPLETE: - DEBUGP(DMM, "USS Release Complete\n"); /* could also parse out the optional Cause/Facility data */ + DEBUGP(DMM, "USS Release Complete\n"); + /* could also parse out the optional Cause/Facility data */ ussd_string_buff[0] = 0xFF; break; case GSM0480_MTYPE_REGISTER: @@ -114,10 +116,11 @@ static int parse_ussd(u_int8_t *ussd) static int parse_ussd_information_elements(u_int8_t *ussd_ie) { int rc; - - u_int8_t iei = ussd_ie[0]; /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ + /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ + u_int8_t iei = ussd_ie[0]; u_int8_t iei_length = ussd_ie[1]; - switch(iei) { + + switch (iei) { case GSM48_IE_CAUSE: break; case GSM0480_IE_FACILITY: @@ -126,7 +129,7 @@ static int parse_ussd_information_elements(u_int8_t *ussd_ie) case GSM0480_IE_SS_VERSION: break; default: - fprintf(stderr, "Unhandled GSM 04.08 or 04.80 Information Element Identifier 0x%02x\n", + fprintf(stderr, "Unhandled GSM 04.08 or 04.80 IEI 0x%02x\n", iei); rc = 0; break; @@ -141,9 +144,11 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) u_int8_t offset = 0; do { - u_int8_t component_type = facility_ie[offset]; /* Component Type tag - table 3.7 */ + /* Component Type tag - table 3.7 */ + u_int8_t component_type = facility_ie[offset]; u_int8_t component_length = facility_ie[offset+1]; - switch(component_type) { + + switch (component_type) { case GSM0480_CTYPE_INVOKE: rc &= parse_ss_invoke(facility_ie+2, component_length); break; @@ -154,13 +159,13 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) case GSM0480_CTYPE_REJECT: break; default: - fprintf(stderr, "Unknown GSM 04.80 Facility Component Type 0x%02x\n", - component_type); + fprintf(stderr, "Unknown GSM 04.80 Facility " + "Component Type 0x%02x\n", component_type); rc = 0; break; } offset += (component_length+2); - } while(offset < length); + } while (offset < length); return rc; } @@ -169,31 +174,38 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) { int rc = 1; - - if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) { /* mandatory part */ - fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Invoke ID tag)\n", - invoke_data[0]); + u_int8_t offset; + + /* mandatory part */ + if (invoke_data[0] != GSM0480_COMPIDTAG_INVOKE_ID) { + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag " + "0x%02x (expecting Invoke ID tag)\n", invoke_data[0]); } - u_int8_t offset = invoke_data[1] + 2; + + offset = invoke_data[1] + 2; last_invoke_id = invoke_data[2]; - if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) /* optional part */ + /* optional part */ + if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) offset += invoke_data[offset+1] + 2; /* skip over it */ - - if (invoke_data[offset] == GSM0480_OPERATION_CODE) { /* mandatory part */ + + /* mandatory part */ + if (invoke_data[offset] == GSM0480_OPERATION_CODE) { u_int8_t operation_code = invoke_data[offset+2]; - switch(operation_code) { + switch (operation_code) { case GSM0480_OP_CODE_PROCESS_USS_REQ: - rc = parse_process_uss_req(invoke_data + offset + 3, length - offset - 3); + rc = parse_process_uss_req(invoke_data + offset + 3, + length - offset - 3); break; default: - fprintf(stderr, "GSM 04.80 operation code 0x%02x is not yet handled\n", - operation_code); + fprintf(stderr, "GSM 04.80 operation code 0x%02x " + "is not yet handled\n", operation_code); rc = 0; break; } } else { - fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x (expecting Operation Code tag)\n", + fprintf(stderr, "Unexpected GSM 04.80 Component-ID tag 0x%02x " + "(expecting Operation Code tag)\n", invoke_data[0]); rc = 0; } @@ -208,14 +220,18 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length) int num_chars; u_int8_t dcs; - /* FIXME: most phones send USSD text as a 7-bit encoded octet string; the following code - also handles the case of plain ASCII text (IA5String), but other encodings might be used */ + /* FIXME: most phones send USSD text as a 7-bit encoded octet string; + * the following code also handles the case of plain ASCII text + * (IA5String), but other encodings might be used */ + if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) { if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) { dcs = uss_req_data[4]; - if ((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { + if ((dcs == 0x0F) && + (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { num_chars = (uss_req_data[6] * 8) / 7; - gsm_7bit_decode(ussd_string_buff, &(uss_req_data[7]), num_chars); + gsm_7bit_decode(ussd_string_buff, + &(uss_req_data[7]), num_chars); } } } else if (uss_req_data[0] == ASN1_IA5_STRING_TAG) { @@ -255,7 +271,8 @@ int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); /* Pre-pend the operation code */ - msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, GSM0480_OP_CODE_PROCESS_USS_REQ); + msgb_push_TLV1(msg, GSM0480_OPERATION_CODE, + GSM0480_OP_CODE_PROCESS_USS_REQ); /* Wrap the operation code and IA5 string as a sequence */ msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); @@ -286,7 +303,8 @@ int gsm0480_send_ussd_reject(struct msgb *in_msg) msg->lchan = in_msg->lchan; /* First insert the problem code */ - msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL, GSM_0480_GEN_PROB_CODE_UNRECOGNISED); + msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL, + GSM_0480_GEN_PROB_CODE_UNRECOGNISED); /* Before it insert the invoke ID */ msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, last_invoke_id); @@ -299,7 +317,8 @@ int gsm0480_send_ussd_reject(struct msgb *in_msg) /* And finally pre-pend the L3 header */ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | (1<<7); /* TI direction = 1 */ + gh->proto_discr = GSM48_PDISC_NC_SS; + gh->proto_discr |= last_transaction_id | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; return gsm48_sendmsg(msg, NULL); diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c index 5f9a45725..9dc2205f1 100644 --- a/openbsc/src/ussd.c +++ b/openbsc/src/ussd.c @@ -22,7 +22,8 @@ * */ -/* This module defines the network-specific handling of mobile-originated USSD messages. */ +/* This module defines the network-specific handling of mobile-originated + USSD messages. */ #include #include @@ -43,12 +44,12 @@ static int send_own_number(struct msgb *msg); /* Entrypoint - handler function common to all mobile-originated USSDs */ int handle_rcv_ussd(struct msgb *msg) { - char* ussd_text_rcvd = gsm0480_rcv_ussd(msg); + char *ussd_text_rcvd = gsm0480_rcv_ussd(msg); - if(ussd_text_rcvd[0] == 0xFF) /* Release-Complete */ - return 0; + if (ussd_text_rcvd[0] == 0xFF) /* Release-Complete */ + return 0; - if(strstr(USSD_TEXT_OWN_NUMBER, ussd_text_rcvd) != NULL) { + if (strstr(USSD_TEXT_OWN_NUMBER, ussd_text_rcvd) != NULL) { DEBUGP(DMM, "USSD: Own number requested\n"); return send_own_number(msg); } else { @@ -60,9 +61,10 @@ int handle_rcv_ussd(struct msgb *msg) /* A network-specific handler function */ static int send_own_number(struct msgb *msg) { - char response_string[] = "Your extension is xxxxx\r"; /* Need trailing CR as EOT character */ + char *own_number = msg->lchan->subscr->extension; + /* Need trailing CR as EOT character */ + char response_string[] = "Your extension is xxxxx\r"; - char* own_number = msg->lchan->subscr->extension; memcpy(response_string + 18, own_number, 5); return gsm0480_send_ussd_response(msg, response_string); } -- cgit v1.2.3 From dc329a6cdb204d89c15599ca606e239dde368e7f Mon Sep 17 00:00:00 2001 From: Mike Haben Date: Thu, 22 Oct 2009 09:56:44 +0200 Subject: [USSD] eliminate static global variables This patch removes the need of static global variables and introduces a new, caller-allocated 'struct ussd_request' that needs to be passed to the various functions. --- openbsc/include/openbsc/gsm_04_80.h | 15 +++++-- openbsc/src/gsm_04_80.c | 90 +++++++++++++++++++------------------ openbsc/src/ussd.c | 19 ++++---- 3 files changed, 68 insertions(+), 56 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 11962d81d..9bdf2c200 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -125,8 +125,17 @@ #include -char* gsm0480_rcv_ussd(struct msgb *msg); -int gsm0480_send_ussd_response(struct msgb *msg, const char* response_text); -int gsm0480_send_ussd_reject(struct msgb *msg); +struct ussd_request { + char text[32]; + u_int8_t transaction_id; + u_int8_t invoke_id; +}; + +int gsm0480_decode_ussd_request(struct msgb *msg, + struct ussd_request *request); +int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text, + const struct ussd_request *req); +int gsm0480_send_ussd_reject(struct msgb *msg, + const struct ussd_request *request); #endif diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index 052b0a77a..5d85c8221 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -37,16 +37,16 @@ #include #include -static char ussd_string_buff[32]; -static u_int8_t last_transaction_id; -static u_int8_t last_invoke_id; - /* Forward declarations */ -static int parse_ussd(u_int8_t *ussd); -static int parse_ussd_information_elements(u_int8_t *ussd_ie); -static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length); -static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length); -static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length); +static int parse_ussd(u_int8_t *ussd, struct ussd_request *req); +static int parse_ussd_info_elements(u_int8_t *ussd_ie, + struct ussd_request *req); +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, + struct ussd_request *req); +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, + struct ussd_request *req); +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, + struct ussd_request *req); static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag) { @@ -69,26 +69,24 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, } -/* Receive a mobile-originated USSD message and return the decoded text */ -char *gsm0480_rcv_ussd(struct msgb *msg) +/* Decode a mobile-originated USSD-request message */ +int gsm0480_decode_ussd_request(struct msgb *msg, struct ussd_request *req) { int rc = 0; u_int8_t *parse_ptr = msgb_l3(msg); - memset(ussd_string_buff, 0, sizeof(ussd_string_buff)); - if ((*parse_ptr & 0x0F) == GSM48_PDISC_NC_SS) { - last_transaction_id = *parse_ptr & 0x70; - rc = parse_ussd(parse_ptr + 1); + req->transaction_id = *parse_ptr & 0x70; + rc = parse_ussd(parse_ptr+1, req); } if (!rc) DEBUGP(DMM, "Error occurred while parsing received USSD!\n"); - return ussd_string_buff; + return rc; } -static int parse_ussd(u_int8_t *ussd) +static int parse_ussd(u_int8_t *ussd, struct ussd_request *req) { int rc = 1; u_int8_t msg_type = ussd[0] & 0xBF; /* message-type - section 3.4 */ @@ -97,11 +95,11 @@ static int parse_ussd(u_int8_t *ussd) case GSM0480_MTYPE_RELEASE_COMPLETE: DEBUGP(DMM, "USS Release Complete\n"); /* could also parse out the optional Cause/Facility data */ - ussd_string_buff[0] = 0xFF; + req->text[0] = 0xFF; break; case GSM0480_MTYPE_REGISTER: case GSM0480_MTYPE_FACILITY: - rc &= parse_ussd_information_elements(ussd+1); + rc &= parse_ussd_info_elements(ussd+1, req); break; default: fprintf(stderr, "Unknown GSM 04.80 message-type field 0x%02x\n", @@ -113,7 +111,7 @@ static int parse_ussd(u_int8_t *ussd) return rc; } -static int parse_ussd_information_elements(u_int8_t *ussd_ie) +static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req) { int rc; /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ @@ -124,7 +122,7 @@ static int parse_ussd_information_elements(u_int8_t *ussd_ie) case GSM48_IE_CAUSE: break; case GSM0480_IE_FACILITY: - rc = parse_facility_ie(ussd_ie+2, iei_length); + rc = parse_facility_ie(ussd_ie+2, iei_length, req); break; case GSM0480_IE_SS_VERSION: break; @@ -138,7 +136,8 @@ static int parse_ussd_information_elements(u_int8_t *ussd_ie) return rc; } -static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, + struct ussd_request *req) { int rc = 1; u_int8_t offset = 0; @@ -150,7 +149,9 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) switch (component_type) { case GSM0480_CTYPE_INVOKE: - rc &= parse_ss_invoke(facility_ie+2, component_length); + rc &= parse_ss_invoke(facility_ie+2, + component_length, + req); break; case GSM0480_CTYPE_RETURN_RESULT: break; @@ -171,7 +172,8 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length) } /* Parse an Invoke component - see table 3.3 */ -static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, + struct ussd_request *req) { int rc = 1; u_int8_t offset; @@ -183,7 +185,7 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) } offset = invoke_data[1] + 2; - last_invoke_id = invoke_data[2]; + req->invoke_id = invoke_data[2]; /* optional part */ if (invoke_data[offset] == GSM0480_COMPIDTAG_LINKED_ID) @@ -195,7 +197,8 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) switch (operation_code) { case GSM0480_OP_CODE_PROCESS_USS_REQ: rc = parse_process_uss_req(invoke_data + offset + 3, - length - offset - 3); + length - offset - 3, + req); break; default: fprintf(stderr, "GSM 04.80 operation code 0x%02x " @@ -214,36 +217,33 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length) } /* Parse the parameters of a Process UnstructuredSS Request */ -static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length) +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, + struct ussd_request *req) { - int rc = 1; + int rc = 0; int num_chars; u_int8_t dcs; - /* FIXME: most phones send USSD text as a 7-bit encoded octet string; - * the following code also handles the case of plain ASCII text - * (IA5String), but other encodings might be used */ - if (uss_req_data[0] == GSM_0480_SEQUENCE_TAG) { if (uss_req_data[2] == ASN1_OCTET_STRING_TAG) { dcs = uss_req_data[4]; if ((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { num_chars = (uss_req_data[6] * 8) / 7; - gsm_7bit_decode(ussd_string_buff, + gsm_7bit_decode(req->text, &(uss_req_data[7]), num_chars); + /* append null-terminator */ + req->text[num_chars+1] = 0; + rc = 1; } } - } else if (uss_req_data[0] == ASN1_IA5_STRING_TAG) { - num_chars = uss_req_data[1]; - memcpy(ussd_string_buff, &(uss_req_data[2]), num_chars); - } - + } return rc; } /* Send response to a mobile-originated ProcessUnstructuredSS-Request */ -int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) +int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text, + const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -278,7 +278,7 @@ int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG); /* Pre-pend the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, last_invoke_id); + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); /* Wrap this up as a Return Result component */ msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT); @@ -288,13 +288,15 @@ int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text) /* And finally pre-pend the L3 header */ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS | last_transaction_id | (1<<7); /* TI direction = 1 */ + gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id + | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; return gsm48_sendmsg(msg, NULL); } -int gsm0480_send_ussd_reject(struct msgb *in_msg) +int gsm0480_send_ussd_reject(struct msgb *in_msg, + const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh; @@ -307,7 +309,7 @@ int gsm0480_send_ussd_reject(struct msgb *in_msg) GSM_0480_GEN_PROB_CODE_UNRECOGNISED); /* Before it insert the invoke ID */ - msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, last_invoke_id); + msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id); /* Wrap this up as a Reject component */ msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT); @@ -318,7 +320,7 @@ int gsm0480_send_ussd_reject(struct msgb *in_msg) /* And finally pre-pend the L3 header */ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_NC_SS; - gh->proto_discr |= last_transaction_id | (1<<7); /* TI direction = 1 */ + gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; return gsm48_sendmsg(msg, NULL); diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c index 9dc2205f1..e414b1cea 100644 --- a/openbsc/src/ussd.c +++ b/openbsc/src/ussd.c @@ -38,33 +38,34 @@ const char USSD_TEXT_OWN_NUMBER[] = "*#100#"; /* Forward declarations of network-specific handler functions */ -static int send_own_number(struct msgb *msg); +static int send_own_number(const struct msgb *msg, const struct ussd_request *req); /* Entrypoint - handler function common to all mobile-originated USSDs */ int handle_rcv_ussd(struct msgb *msg) { - char *ussd_text_rcvd = gsm0480_rcv_ussd(msg); + struct ussd_request req; - if (ussd_text_rcvd[0] == 0xFF) /* Release-Complete */ + gsm0480_decode_ussd_request(msg, &req); + if (req.text[0] == 0xFF) /* Release-Complete */ return 0; - if (strstr(USSD_TEXT_OWN_NUMBER, ussd_text_rcvd) != NULL) { + if (strstr(USSD_TEXT_OWN_NUMBER, req.text) != NULL) { DEBUGP(DMM, "USSD: Own number requested\n"); - return send_own_number(msg); + return send_own_number(msg, &req); } else { - DEBUGP(DMM, "Unhandled USSD %s\n", ussd_text_rcvd); - return gsm0480_send_ussd_reject(msg); + DEBUGP(DMM, "Unhandled USSD %s\n", req.text); + return gsm0480_send_ussd_reject(msg, &req); } } /* A network-specific handler function */ -static int send_own_number(struct msgb *msg) +static int send_own_number(const struct msgb *msg, const struct ussd_request *req) { char *own_number = msg->lchan->subscr->extension; /* Need trailing CR as EOT character */ char response_string[] = "Your extension is xxxxx\r"; memcpy(response_string + 18, own_number, 5); - return gsm0480_send_ussd_response(msg, response_string); + return gsm0480_send_ussd_response(msg, response_string, req); } -- cgit v1.2.3 From 2449b37dfe424248ea9fe2143efb78a3cd385d64 Mon Sep 17 00:00:00 2001 From: Mike Haben Date: Mon, 26 Oct 2009 20:36:34 +0100 Subject: [USSD] various USSD improvements - Improved handling of extension-number string (as per review) - Guard against a buffer-overflow if mobile sends a too-long USSD - declare some function-parameters const - fix gsm_ts_name function to display the right BTS number (bts->nr rather than bts->bts_nr) --- openbsc/include/openbsc/gsm_04_80.h | 10 ++++++---- openbsc/include/openbsc/gsm_subscriber.h | 7 ++++--- openbsc/src/gsm_04_80.c | 9 ++++++--- openbsc/src/gsm_data.c | 2 +- openbsc/src/ussd.c | 6 +++--- 5 files changed, 20 insertions(+), 14 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_80.h b/openbsc/include/openbsc/gsm_04_80.h index 9bdf2c200..c240bbe94 100644 --- a/openbsc/include/openbsc/gsm_04_80.h +++ b/openbsc/include/openbsc/gsm_04_80.h @@ -125,17 +125,19 @@ #include +#define MAX_LEN_USSD_STRING 31 + struct ussd_request { - char text[32]; + char text[MAX_LEN_USSD_STRING + 1]; u_int8_t transaction_id; u_int8_t invoke_id; }; -int gsm0480_decode_ussd_request(struct msgb *msg, +int gsm0480_decode_ussd_request(const struct msgb *msg, struct ussd_request *request); -int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text, +int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_text, const struct ussd_request *req); -int gsm0480_send_ussd_reject(struct msgb *msg, +int gsm0480_send_ussd_reject(const struct msgb *msg, const struct ussd_request *request); #endif diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index ea70c3aa2..d612ed566 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -8,13 +8,14 @@ #define GSM_IMEI_LENGTH 17 #define GSM_IMSI_LENGTH 17 #define GSM_NAME_LENGTH 128 -#define GSM_EXTENSION_LENGTH 128 + +#define GSM_EXTENSION_LENGTH 15 /* MSISDN can only be 15 digits length */ +#define GSM_MIN_EXTEN 20000 +#define GSM_MAX_EXTEN 49999 /* reserved according to GSM 03.03 § 2.4 */ #define GSM_RESERVED_TMSI 0xFFFFFFFF -#define GSM_MIN_EXTEN 20000 -#define GSM_MAX_EXTEN 49999 #define GSM_SUBSCRIBER_FIRST_CONTACT 0x00000001 #define tmsi_from_string(str) strtoul(str, NULL, 10) diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index 5d85c8221..7f5089de1 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -70,7 +70,7 @@ static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, u_int8_t tag, /* Decode a mobile-originated USSD-request message */ -int gsm0480_decode_ussd_request(struct msgb *msg, struct ussd_request *req) +int gsm0480_decode_ussd_request(const struct msgb *msg, struct ussd_request *req) { int rc = 0; u_int8_t *parse_ptr = msgb_l3(msg); @@ -230,6 +230,9 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, if ((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { num_chars = (uss_req_data[6] * 8) / 7; + /* Prevent a mobile-originated buffer-overrun! */ + if (num_chars > MAX_LEN_USSD_STRING) + num_chars = MAX_LEN_USSD_STRING; gsm_7bit_decode(req->text, &(uss_req_data[7]), num_chars); /* append null-terminator */ @@ -242,7 +245,7 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, } /* Send response to a mobile-originated ProcessUnstructuredSS-Request */ -int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text, +int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_text, const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); @@ -295,7 +298,7 @@ int gsm0480_send_ussd_response(struct msgb *in_msg, const char* response_text, return gsm48_sendmsg(msg, NULL); } -int gsm0480_send_ussd_reject(struct msgb *in_msg, +int gsm0480_send_ussd_reject(const struct msgb *in_msg, const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 34642900b..60205be13 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -232,7 +232,7 @@ static char ts2str[255]; char *gsm_ts_name(struct gsm_bts_trx_ts *ts) { snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)", - ts->trx->bts->bts_nr, ts->trx->nr, ts->nr); + ts->trx->bts->nr, ts->trx->nr, ts->nr); return ts2str; } diff --git a/openbsc/src/ussd.c b/openbsc/src/ussd.c index e414b1cea..a3d11f080 100644 --- a/openbsc/src/ussd.c +++ b/openbsc/src/ussd.c @@ -63,9 +63,9 @@ int handle_rcv_ussd(struct msgb *msg) static int send_own_number(const struct msgb *msg, const struct ussd_request *req) { char *own_number = msg->lchan->subscr->extension; - /* Need trailing CR as EOT character */ - char response_string[] = "Your extension is xxxxx\r"; + char response_string[GSM_EXTENSION_LENGTH + 20]; - memcpy(response_string + 18, own_number, 5); + /* Need trailing CR as EOT character */ + snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number); return gsm0480_send_ussd_response(msg, response_string, req); } -- cgit v1.2.3 From 17e5f9795860e1f61c43e27785db86f266a4db13 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Oct 2009 20:42:07 +0100 Subject: [USSD] whitespace fixes This is a purely cosmetic patch --- openbsc/src/gsm_04_80.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index 7f5089de1..b3817c779 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -39,13 +39,13 @@ /* Forward declarations */ static int parse_ussd(u_int8_t *ussd, struct ussd_request *req); -static int parse_ussd_info_elements(u_int8_t *ussd_ie, +static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req); -static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, struct ussd_request *req); -static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, struct ussd_request *req); -static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, struct ussd_request *req); static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, u_int8_t tag) @@ -81,7 +81,7 @@ int gsm0480_decode_ussd_request(const struct msgb *msg, struct ussd_request *req } if (!rc) - DEBUGP(DMM, "Error occurred while parsing received USSD!\n"); + DEBUGP(DMM, "Error occurred while parsing received USSD!\n"); return rc; } @@ -116,7 +116,7 @@ static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req) int rc; /* Information Element Identifier - table 3.2 & GSM 04.08 section 10.5 */ u_int8_t iei = ussd_ie[0]; - u_int8_t iei_length = ussd_ie[1]; + u_int8_t iei_length = ussd_ie[1]; switch (iei) { case GSM48_IE_CAUSE: @@ -136,7 +136,7 @@ static int parse_ussd_info_elements(u_int8_t *ussd_ie, struct ussd_request *req) return rc; } -static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, +static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, struct ussd_request *req) { int rc = 1; @@ -149,8 +149,8 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, switch (component_type) { case GSM0480_CTYPE_INVOKE: - rc &= parse_ss_invoke(facility_ie+2, - component_length, + rc &= parse_ss_invoke(facility_ie+2, + component_length, req); break; case GSM0480_CTYPE_RETURN_RESULT: @@ -172,7 +172,7 @@ static int parse_facility_ie(u_int8_t *facility_ie, u_int8_t length, } /* Parse an Invoke component - see table 3.3 */ -static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, +static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, struct ussd_request *req) { int rc = 1; @@ -217,7 +217,7 @@ static int parse_ss_invoke(u_int8_t *invoke_data, u_int8_t length, } /* Parse the parameters of a Process UnstructuredSS Request */ -static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, +static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, struct ussd_request *req) { int rc = 0; @@ -245,7 +245,7 @@ static int parse_process_uss_req(u_int8_t *uss_req_data, u_int8_t length, } /* Send response to a mobile-originated ProcessUnstructuredSS-Request */ -int gsm0480_send_ussd_response(const struct msgb *in_msg, const char* response_text, +int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_text, const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); -- cgit v1.2.3 From 8c8f791dbe4b14eea8733218b6d8283b538d4041 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 26 Oct 2009 20:42:55 +0100 Subject: [USSD] more whitespace fixes --- openbsc/src/gsm_04_80.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_80.c b/openbsc/src/gsm_04_80.c index b3817c779..d3b472f30 100644 --- a/openbsc/src/gsm_04_80.c +++ b/openbsc/src/gsm_04_80.c @@ -1,4 +1,4 @@ -/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface +/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ /* (C) 2008-2009 by Harald Welte @@ -291,14 +291,14 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_t /* And finally pre-pend the L3 header */ gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id + gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; return gsm48_sendmsg(msg, NULL); } -int gsm0480_send_ussd_reject(const struct msgb *in_msg, +int gsm0480_send_ussd_reject(const struct msgb *in_msg, const struct ussd_request *req) { struct msgb *msg = gsm48_msgb_alloc(); -- cgit v1.2.3 From 1f59ac4728906966d99f669b6157928d97064169 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 03:34:49 +0100 Subject: configure.in: Use kernel style silent rules starting with automake 1.11 Use the silent rules when they are available. Using make V=1 or a special configure option the silent rules can be disabled. --- openbsc/configure.in | 3 +++ 1 file changed, 3 insertions(+) (limited to 'openbsc') diff --git a/openbsc/configure.in b/openbsc/configure.in index 94fb15f4d..25c502972 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -3,6 +3,9 @@ AC_INIT AM_INIT_AUTOMAKE(openbsc, 0.0alpha1) +dnl kernel style compile messages +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + dnl checks for programs AC_PROG_MAKE_SET AC_PROG_CC -- cgit v1.2.3 From 55aac6e868d4f3b565bba310598104c53c53da0a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 03:41:09 +0100 Subject: ipaccess-config: Introduce stream-id/oml_tei to make it work again ipaccess-config stopped working after the introduction of multi-TRX/RSL stream id support in commit 8175e95222cf1c83. Set the oml_tei to 0xff by default and add an option to set a different stream id. --- openbsc/src/ipaccess-config.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 46043d571..add45f94b 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -281,13 +281,14 @@ static void print_help(void) printf(" -n flags/mask\tSet NVRAM attributes.\n"); printf(" -l --listen testnr \tPerform speciified test number\n"); printf(" -h --help this text\n"); + printf(" -s --stream-id ID\n"); } int main(int argc, char **argv) { struct gsm_bts *bts; struct sockaddr_in sin; - int rc, option_index = 0; + int rc, option_index = 0, stream_id = 0xff; printf("ipaccess-config (C) 2009 by Harald Welte\n"); printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n"); @@ -302,9 +303,10 @@ int main(int argc, char **argv) { "restart", 0, 0, 'r' }, { "help", 0, 0, 'h' }, { "listen", 1, 0, 'l' }, + { "stream-id", 1, 0, 's' }, }; - c = getopt_long(argc, argv, "u:o:rn:l:h", long_options, + c = getopt_long(argc, argv, "u:o:rn:l:hs:", long_options, &option_index); if (c == -1) @@ -332,6 +334,10 @@ int main(int argc, char **argv) case 'l': net_listen_testnr = atoi(optarg); break; + case 's': + stream_id = atoi(optarg); + printf("foo: %d\n", stream_id); + break; case 'h': print_usage(); print_help(); @@ -350,6 +356,7 @@ int main(int argc, char **argv) bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_NANOBTS, HARDCODED_TSC, HARDCODED_BSIC); + bts->oml_tei = stream_id; register_signal_handler(SS_NM, nm_sig_cb, NULL); printf("Trying to connect to ip.access BTS ...\n"); -- cgit v1.2.3 From e81a6109f9e94ec5dcceb44a7ef1ea8cc52e7cb1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 11:47:45 +0200 Subject: [gsm48] Add generation of ASSIGNMENT COMMAND to the 0408 utils Add code to generate an assignment command for a given lchan. It is expected that the lchan is modified already and the mode will be picked up from their. Currently only the mandantory items are supported. --- openbsc/include/openbsc/gsm_04_08.h | 10 ++++++++++ openbsc/src/abis_rsl.c | 1 + openbsc/src/gsm_04_08_utils.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 8c944e6ac..ae13581f2 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -59,6 +59,15 @@ enum gsm48_chan_mode { GSM48_CMODE_DATA_3k6 = 0x23, }; +/* Chapter 9.1.2 */ +struct gsm48_ass_cmd { + /* Semantic is from 10.5.2.5a */ + struct gsm48_chan_desc chan_desc; + u_int8_t power_command; + u_int8_t data[0]; +} __attribute__((packed)); + + /* Chapter 9.1.18 */ struct gsm48_imm_ass { u_int8_t l2_plen; @@ -727,6 +736,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); int bsc_upqueue(struct gsm_network *net); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 6b328bb28..a4764f5fb 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -239,6 +239,7 @@ struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr) return lchan; } +/* See Table 10.5.25 of GSM04.08 */ u_int8_t lchan2chan_nr(struct gsm_lchan *lchan) { struct gsm_bts_trx_ts *ts = lchan->ts; diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index ef9e59c77..358212f17 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -482,3 +482,35 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) return rsl_encryption_cmd(msg); } +/* Chapter 9.1.2: Assignment Command */ +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct gsm48_ass_cmd *ass = + (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass)); + u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; + + DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); + + msg->lchan = lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_ASS_CMD; + + /* + * fill the channel information element, this code + * should probably be shared with rsl_rx_chan_rqd(), + * gsm48_tx_chan_mode_modify. But beware that 10.5.2.5 + * 10.5.2.5.a have slightly different semantic for + * the chan_desc. But as long as multi-slot configurations + * are not used we seem to be fine. + */ + ass->chan_desc.chan_nr = lchan2chan_nr(lchan); + ass->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; + ass->chan_desc.h0.h = 0; + ass->chan_desc.h0.arfcn_high = arfcn >> 8; + ass->chan_desc.h0.arfcn_low = arfcn & 0xff; + ass->power_command = power_command; + + return gsm48_sendmsg(msg, NULL); +} -- cgit v1.2.3 From ff3f260e4fdc8445c7460cb8af1b23fb397467b2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:13:00 +0200 Subject: [gsm48] Move RR CHANNEL MODIFY to gsm_04_08_utils.c Be able to send RR CHANNEL MODIFY from the BSC/MSC code as well. Move the method that knows about the IPAccess RTP and issues the "bind" to the utils tool --- openbsc/include/openbsc/gsm_04_08.h | 2 ++ openbsc/src/gsm_04_08.c | 45 +++---------------------------------- openbsc/src/gsm_04_08_utils.c | 45 +++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 42 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index ae13581f2..2afc9c5fd 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -754,4 +754,6 @@ int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv); int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type); int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr); +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode); + #endif diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 23739657d..a29d0362b 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1087,34 +1087,6 @@ static int mm_rx_loc_upd_req(struct msgb *msg) return gsm0408_authorize(lchan, msg); } -/* 9.1.5 Channel mode modify: Modify the mode on the MS side */ -int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) -{ - struct msgb *msg = gsm48_msgb_alloc(); - struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - struct gsm48_chan_mode_modify *cmm = - (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm)); - u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; - - DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode); - - lchan->tch_mode = mode; - msg->lchan = lchan; - gh->proto_discr = GSM48_PDISC_RR; - gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; - - /* fill the channel information element, this code - * should probably be shared with rsl_rx_chan_rqd() */ - cmm->chan_desc.chan_nr = lchan2chan_nr(lchan); - cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; - cmm->chan_desc.h0.h = 0; - cmm->chan_desc.h0.arfcn_high = arfcn >> 8; - cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; - cmm->mode = mode; - - return gsm48_sendmsg(msg, NULL); -} - #if 0 static u_int8_t to_bcd8(u_int8_t val) { @@ -3167,22 +3139,11 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) return mncc_recvmsg(trans->subscr->net, trans, MNCC_USERINFO_IND, &user); } -static int gsm48_lchan_modify(struct gsm_trans *trans, void *arg) +static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; - int rc; - rc = gsm48_tx_chan_mode_modify(trans->lchan, mode->lchan_mode); - if (rc < 0) - return rc; - - /* FIXME: we not only need to do this after mode modify, but - * also after channel activation */ - if (is_ipaccess_bts(trans->lchan->ts->trx->bts) && - mode->lchan_mode != GSM48_CMODE_SIGN) - rc = rsl_ipacc_bind(trans->lchan); - - return rc; + return gsm48_lchan_modify(trans->lchan, mode->lchan_mode); } static struct downstate { @@ -3240,7 +3201,7 @@ static struct downstate { MNCC_REL_REQ, gsm48_cc_tx_release}, /* special */ {ALL_STATES, - MNCC_LCHAN_MODIFY, gsm48_lchan_modify}, + MNCC_LCHAN_MODIFY, _gsm48_lchan_modify}, }; #define DOWNSLLEN \ diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 358212f17..598775c03 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -514,3 +514,48 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) return gsm48_sendmsg(msg, NULL); } + +/* 9.1.5 Channel mode modify: Modify the mode on the MS side */ +int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) +{ + struct msgb *msg = gsm48_msgb_alloc(); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + struct gsm48_chan_mode_modify *cmm = + (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm)); + u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff; + + DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode); + + lchan->tch_mode = mode; + msg->lchan = lchan; + gh->proto_discr = GSM48_PDISC_RR; + gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; + + /* fill the channel information element, this code + * should probably be shared with rsl_rx_chan_rqd() */ + cmm->chan_desc.chan_nr = lchan2chan_nr(lchan); + cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc; + cmm->chan_desc.h0.h = 0; + cmm->chan_desc.h0.arfcn_high = arfcn >> 8; + cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; + cmm->mode = mode; + + return gsm48_sendmsg(msg, NULL); +} + +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode) +{ + int rc; + + rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode); + if (rc < 0) + return rc; + + /* FIXME: we not only need to do this after mode modify, but + * also after channel activation */ + if (is_ipaccess_bts(lchan->ts->trx->bts) && lchan_mode != GSM48_CMODE_SIGN) + rc = rsl_ipacc_bind(lchan); + + return rc; +} + -- cgit v1.2.3 From f520e6439a917777a4a456fea7eb0f214e027c67 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 22 Oct 2009 15:23:11 +0200 Subject: [gsm48] Handle the RR CHAN MODIFY ACK in the gsm04_08_utils Move the handling code to the gsm_04_08_utils.c and add a note that the method value needs to be checked. --- openbsc/include/openbsc/gsm_04_08.h | 7 ++++++- openbsc/src/gsm_04_08.c | 6 +----- openbsc/src/gsm_04_08_utils.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 2afc9c5fd..186a53f97 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -42,7 +42,11 @@ struct gsm48_req_ref { t3_low:3; } __attribute__ ((packed)); -/* Chapter 9.1.5 */ +/* + * Chapter 9.1.5/9.1.6 + * + * For 9.1.6 the chan_desc has the meaning of 10.5.2.5a + */ struct gsm48_chan_mode_modify { struct gsm48_chan_desc chan_desc; u_int8_t mode; @@ -755,5 +759,6 @@ int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr); int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode); +int gsm48_rx_rr_modif_ack(struct msgb *msg); #endif diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index a29d0362b..12cc36245 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1587,11 +1587,7 @@ static int gsm0408_rcv_rr(struct msgb *msg) rc = gsm48_rx_rr_pag_resp(msg); break; case GSM48_MT_RR_CHAN_MODE_MODIF_ACK: - DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); - /* We've successfully modified the MS side of the channel, - * now go on to modify the BTS side of the channel */ - msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; - rc = rsl_chan_mode_modify_req(msg->lchan); + rc = gsm48_rx_rr_modif_ack(msg); break; case GSM48_MT_RR_STATUS: rc = gsm48_rx_rr_status(msg); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 598775c03..2545f33a6 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -559,3 +559,39 @@ int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode) return rc; } +int gsm48_rx_rr_modif_ack(struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + struct gsm48_chan_mode_modify *mod = + (struct gsm48_chan_mode_modify *) gh->data; + + DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n"); + + if (mod->mode != msg->lchan->tch_mode) { + DEBUGP(DRR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n", + msg->lchan->tch_mode, mod->mode); + return -1; + } + + /* update the channel type */ + switch (mod->mode) { + case GSM48_CMODE_SIGN: + msg->lchan->rsl_cmode = RSL_CMOD_SPD_SIGN; + break; + case GSM48_CMODE_SPEECH_V1: + case GSM48_CMODE_SPEECH_EFR: + case GSM48_CMODE_SPEECH_AMR: + msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH; + break; + case GSM48_CMODE_DATA_14k5: + case GSM48_CMODE_DATA_12k0: + case GSM48_CMODE_DATA_6k0: + case GSM48_CMODE_DATA_3k6: + msg->lchan->rsl_cmode = RSL_CMOD_SPD_DATA; + break; + } + + /* We've successfully modified the MS side of the channel, + * now go on to modify the BTS side of the channel */ + return rsl_chan_mode_modify_req(msg->lchan); +} -- cgit v1.2.3 From 423bfe915c2e2eb116d21b4c390e0bc13bab39b0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 10:08:20 +0100 Subject: abis_nm.c: Remove duplicate entry from the table --- openbsc/src/abis_nm.c | 1 - 1 file changed, 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 03d9deff0..05dec2201 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -328,7 +328,6 @@ static const struct tlv_definition nm_att_tlvdef = { [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V }, [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V }, [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV }, - [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V }, [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V }, /* BS11 specifics */ [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV }, -- cgit v1.2.3 From 67b596199d5deb745842f26686bff96b40b63438 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 10:08:38 +0100 Subject: input/ipaccess.c: clang says ret might be uninitialized and it appears to be right that for the "default" case ret will not be assigned and we return ret. --- openbsc/src/input/ipaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 1265982d2..85018648a 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -304,7 +304,7 @@ static int handle_ts1_read(struct bsc_fd *bfd) struct e1inp_sign_link *link; struct msgb *msg; struct ipaccess_head *hh; - int ret, error; + int ret = 0, error; msg = ipaccess_read_msg(bfd, &error); if (!msg) { -- cgit v1.2.3 From 100fe569304a39fe02ce7744dc7478a6a7b5d2cc Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 10:14:04 +0100 Subject: misc: Fix make distcheck and welcome the two new header files to OpenBSC --- openbsc/include/openbsc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 8d454bb00..461f5a89e 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -3,4 +3,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \ subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ - bsc_rll.h mncc.h talloc.h transaction.h + bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h -- cgit v1.2.3 From 251aa918da9bea6fcf5ba916df8b616b130e8ada Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 10:42:28 +0100 Subject: misc: Make bitfields unsigned int... There is no use to have a signed bit in bitfields.. --- openbsc/include/openbsc/gsm_data.h | 4 ++-- openbsc/include/openbsc/timer.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 9a277aeee..927c32846 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -124,8 +124,8 @@ struct gsm_nm_state { */ struct gsm_loc_updating_operation { struct timer_list updating_timer; - int waiting_for_imsi : 1; - int waiting_for_imei : 1; + unsigned int waiting_for_imsi : 1; + unsigned int waiting_for_imei : 1; }; #define MAX_A5_KEY_LEN (128/8) diff --git a/openbsc/include/openbsc/timer.h b/openbsc/include/openbsc/timer.h index a1ad92cfc..fee888bfd 100644 --- a/openbsc/include/openbsc/timer.h +++ b/openbsc/include/openbsc/timer.h @@ -44,9 +44,9 @@ struct timer_list { struct llist_head entry; struct timeval timeout; - int active : 1; - int handled : 1; - int in_list : 1; + unsigned int active : 1; + unsigned int handled : 1; + unsigned int in_list : 1; void (*cb)(void*); void *data; -- cgit v1.2.3 From ba92587cd5789d74ffa8675179f680232682edf1 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 10:42:53 +0100 Subject: misc: Use NULL instead of integer value for a NULL pointer --- openbsc/src/chan_alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 48c728c09..541c6c35e 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -227,7 +227,7 @@ void lchan_free(struct gsm_lchan *lchan) lchan->type = GSM_LCHAN_NONE; if (lchan->subscr) { subscr_put(lchan->subscr); - lchan->subscr = 0; + lchan->subscr = NULL; } /* We might kill an active channel... */ @@ -304,5 +304,5 @@ struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr) return lchan; } - return 0; + return NULL; } -- cgit v1.2.3 From 5ea731338d9497e26b8bde1483de7c768f17c244 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 29 Oct 2009 02:29:45 +0100 Subject: [misc] Use talloc_zero instead of talloc and later memset --- openbsc/src/gsm_data.c | 9 +++------ openbsc/src/gsm_subscriber_base.c | 3 +-- openbsc/src/input/ipaccess.c | 9 +++------ 3 files changed, 7 insertions(+), 14 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 60205be13..59947fdb7 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -104,13 +104,12 @@ const char *gsm_chreq_name(enum gsm_chreq_reason_t c) struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) { - struct gsm_bts_trx *trx = talloc(bts, struct gsm_bts_trx); + struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx); int k; if (!trx) return NULL; - memset(trx, 0, sizeof(*trx)); trx->bts = bts; trx->nr = bts->num_trx++; @@ -140,13 +139,12 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts) struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type, u_int8_t tsc, u_int8_t bsic) { - struct gsm_bts *bts = talloc(net, struct gsm_bts); + struct gsm_bts *bts = talloc_zero(net, struct gsm_bts); int i; if (!bts) return NULL; - memset(bts, 0, sizeof(*bts)); bts->network = net; bts->nr = net->num_bts++; bts->type = type; @@ -179,10 +177,9 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c { struct gsm_network *net; - net = talloc(tall_bsc_ctx, struct gsm_network); + net = talloc_zero(tall_bsc_ctx, struct gsm_network); if (!net) return NULL; - memset(net, 0, sizeof(*net)); net->country_code = country_code; net->network_code = network_code; diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c index 868b35599..48374eae5 100644 --- a/openbsc/src/gsm_subscriber_base.c +++ b/openbsc/src/gsm_subscriber_base.c @@ -115,11 +115,10 @@ struct gsm_subscriber *subscr_alloc(void) { struct gsm_subscriber *s; - s = talloc(tall_subscr_ctx, struct gsm_subscriber); + s = talloc_zero(tall_subscr_ctx, struct gsm_subscriber); if (!s) return NULL; - memset(s, 0, sizeof(*s)); llist_add_tail(&s->entry, &active_subscribers); s->use_count = 1; s->tmsi = GSM_RESERVED_TMSI; diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 85018648a..3882ea677 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -494,12 +494,11 @@ static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) } DEBUGP(DINP, "accept()ed new OML link from %s\n", inet_ntoa(sa.sin_addr)); - line = talloc(tall_bsc_ctx, struct e1inp_line); + line = talloc_zero(tall_bsc_ctx, struct e1inp_line); if (!line) { close(ret); return -ENOMEM; } - memset(line, 0, sizeof(*line)); line->driver = &ipaccess_driver; //line->driver_data = e1h; /* create virrtual E1 timeslots for signalling */ @@ -538,10 +537,9 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) if (!(what & BSC_FD_READ)) return 0; - bfd = talloc(tall_bsc_ctx, struct bsc_fd); + bfd = talloc_zero(tall_bsc_ctx, struct bsc_fd); if (!bfd) return -ENOMEM; - memset(bfd, 0, sizeof(*bfd)); /* Some BTS has connected to us, but we don't know yet which line * (as created by the OML link) to associate it with. Thus, we @@ -652,10 +650,9 @@ int ipaccess_setup(struct gsm_network *gsmnet) if (ret) return ret; - e1h = talloc(tall_bsc_ctx, struct ia_e1_handle); + e1h = talloc_zero(tall_bsc_ctx, struct ia_e1_handle); if (!e1h) return -ENOMEM; - memset(e1h, 0, sizeof(*e1h)); e1h->gsmnet = gsmnet; -- cgit v1.2.3 From 5ba6f480926bee1eeeaf2997a5f18a4a533d5374 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 28 Oct 2009 14:23:39 +0100 Subject: [lchan] Keep track which SAPIs has been established with the BTS Keep track of which SAPIs have been established either by the BTS (from the MS) or by us. This can be used by the on-waves BSC code to figure out if a new request should be made. --- openbsc/include/openbsc/gsm_data.h | 8 ++++++++ openbsc/src/abis_rsl.c | 4 ++++ openbsc/src/chan_alloc.c | 3 +++ 3 files changed, 15 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 927c32846..94a70818a 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -131,6 +131,11 @@ struct gsm_loc_updating_operation { #define MAX_A5_KEY_LEN (128/8) #define RSL_ENC_ALG_A5(x) (x+1) +/* is the data link established? who established it? */ +#define LCHAN_SAPI_UNUSED 0 +#define LCHAN_SAPI_MS 1 +#define LCHAN_SAPI_NET 2 + struct gsm_lchan { /* The TS that we're part of */ struct gsm_bts_trx_ts *ts; @@ -160,6 +165,9 @@ struct gsm_lchan { struct timer_list T3101; + /* Established data link layer services */ + u_int8_t sapis[8]; + /* * Operations that have a state and might be pending */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index a4764f5fb..acd41dd63 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1294,6 +1294,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) case RSL_MT_EST_IND: DEBUGPC(DRLL, "ESTABLISH INDICATION\n"); /* lchan is established, stop T3101 */ + msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS; bsc_del_timer(&msg->lchan->T3101); if (msgb_l2len(msg) > sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) && @@ -1304,12 +1305,14 @@ static int abis_rsl_rx_rll(struct msgb *msg) break; case RSL_MT_EST_CONF: DEBUGPC(DRLL, "ESTABLISH CONFIRM\n"); + msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_NET; rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_EST_CONF); break; case RSL_MT_REL_IND: /* BTS informs us of having received DISC from MS */ DEBUGPC(DRLL, "RELEASE INDICATION\n"); + msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED; rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_REL_IND); /* we can now releae the channel on the BTS/Abis side */ @@ -1321,6 +1324,7 @@ static int abis_rsl_rx_rll(struct msgb *msg) /* BTS informs us of having received UA from MS, * in response to DISC that we've sent earlier */ DEBUGPC(DRLL, "RELEASE CONFIRMATION\n"); + msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED; /* we can now releae the channel on the BTS/Abis side */ /* FIXME: officially we need to start T3111 and wait for * some grace period */ diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 541c6c35e..7464aa96b 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -212,6 +212,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) lchan->type = type; lchan->use_count = 0; + /* clear sapis */ + memset(lchan->sapis, 0, sizeof(lchan->sapis)); + /* Configure the time and start it so it will be closed */ lchan->release_timer.cb = auto_release_channel; lchan->release_timer.data = lchan; -- cgit v1.2.3 From d7d1c99a5366b6d289990ef521fb5c19ea2d4b40 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Thu, 29 Oct 2009 16:33:59 +0100 Subject: ip.access: Header has a 16bit length in network byte order This is confirmed by looking at the source of their dissector. The length can go up to 273 bytes apparently (again, according to the source of their dissector). --- openbsc/include/openbsc/ipaccess.h | 3 +-- openbsc/src/input/ipaccess.c | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index eb17167b5..395687764 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -4,8 +4,7 @@ #include "e1_input.h" struct ipaccess_head { - u_int8_t zero; - u_int8_t len; + u_int16_t len; /* network byte order */ u_int8_t proto; u_int8_t data[0]; } __attribute__ ((packed)); diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 3882ea677..34d9462b9 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -259,7 +259,7 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) { struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "Abis/IP"); struct ipaccess_head *hh; - int ret = 0; + int len, ret = 0; if (!msg) { *error = -ENOMEM; @@ -284,8 +284,9 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error) /* then read te length as specified in header */ msg->l2h = msg->data + sizeof(*hh); - ret = recv(bfd->fd, msg->l2h, hh->len, 0); - if (ret < hh->len) { + len = ntohs(hh->len); + ret = recv(bfd->fd, msg->l2h, len, 0); + if (ret < len) { fprintf(stderr, "short read!\n"); msgb_free(msg); *error = -EIO; @@ -374,8 +375,7 @@ void ipaccess_prepend_header(struct msgb *msg, int proto) /* prepend the ip.access header */ hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh)); - hh->zero = 0; - hh->len = msg->len - sizeof(*hh); + hh->len = htons(msg->len - sizeof(*hh)); hh->proto = proto; } -- cgit v1.2.3 From e33966cec2a1b246114026b2c5eb19555a31d303 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 12:47:06 +0100 Subject: vty: Do not leak the gsm_subscriber --- openbsc/src/vty_interface_layer3.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 032e16fc4..87c1c85f1 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -1,5 +1,6 @@ /* OpenBSC interface to quagga VTY */ /* (C) 2009 by Harald Welte + * (C) 2009 by Holger Hans Peter Freyther * All Rights Reserved * * This program is free software; you can redistribute it and/or modify @@ -88,6 +89,7 @@ DEFUN(cfg_subscr, return CMD_WARNING; } + /* vty_go_parent should put this subscriber */ vty->index = subscr; vty->node = SUBSCR_NODE; @@ -112,6 +114,7 @@ DEFUN(show_subscr, return CMD_WARNING; } subscr_dump_vty(vty, subscr); + subscr_put(subscr); return CMD_SUCCESS; } @@ -218,6 +221,7 @@ DEFUN(sms_send_ext, b = argv_to_buffer(argc, argv, 1); rc = _send_sms_buffer(receiver, b); buffer_free(b); + subscr_put(receiver); return rc; } @@ -238,6 +242,7 @@ DEFUN(sms_send_imsi, b = argv_to_buffer(argc, argv, 1); rc = _send_sms_buffer(receiver, b); buffer_free(b); + subscr_put(receiver); return rc; } -- cgit v1.2.3 From ccf53c60c52399c4b19f6d37957fd42434e8d9f5 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 27 Oct 2009 14:21:14 +0100 Subject: [mncc] Fix possible transaction/subscriber and real life subscriber leak In the case a transaction has been already scheduled return 0 was called but the subscriber and transaction would leak. Fix it by calling subscr_put and trans_free. After claiming the channel also remove the reference on the subscr. --- openbsc/src/gsm_04_08.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 12cc36245..6a4abfc3a 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -3208,7 +3208,6 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) { int i, rc = 0; struct gsm_trans *trans = NULL, *transt; - struct gsm_subscriber *subscr; struct gsm_lchan *lchan = NULL; struct gsm_bts *bts = NULL; struct gsm_mncc *data = arg, rel; @@ -3233,6 +3232,8 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) /* Callref unknown */ if (!trans) { + struct gsm_subscriber *subscr; + if (msg_type != MNCC_SETUP_REQ) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Received '%s' from MNCC with " @@ -3308,6 +3309,8 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) "started.\n", bts->nr, data->called.number, get_mncc_name(msg_type)); + subscr_put(subscr); + trans_free(trans); return 0; } /* store setup informations until paging was successfull */ @@ -3315,11 +3318,13 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg) /* Trigger paging */ paging_request(net, subscr, RSL_CHANNEED_TCH_F, setup_trig_pag_evt, subscr); + subscr_put(subscr); return 0; } /* Assign lchan */ trans->lchan = lchan; use_lchan(lchan); + subscr_put(subscr); } lchan = trans->lchan; -- cgit v1.2.3 From d409be7faecb24640ee55b2be667340b9997775c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 7 Nov 2009 00:06:19 +0900 Subject: change some identifiers from u_int64_t to unsigned long long makes printf much easier on 64bit platforms... --- openbsc/include/openbsc/gsm_data.h | 2 +- openbsc/src/db.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 94a70818a..c3ea45dce 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -416,7 +416,7 @@ struct gsm_network { #define SMS_HDR_SIZE 128 #define SMS_TEXT_SIZE 256 struct gsm_sms { - u_int64_t id; + unsigned long long id; struct gsm_subscriber *sender; struct gsm_subscriber *receiver; diff --git a/openbsc/src/db.c b/openbsc/src/db.c index b86348c55..369505a2c 100644 --- a/openbsc/src/db.c +++ b/openbsc/src/db.c @@ -592,7 +592,7 @@ int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* toke } int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IMEI_LENGTH]) { - u_int64_t equipment_id, watch_id; + unsigned long long equipment_id, watch_id; dbi_result result; strncpy(subscriber->equipment.imei, imei, -- cgit v1.2.3 From 5727cf4ea78033b955fadd2525dbe12da486edf6 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Wed, 11 Nov 2009 23:02:07 +0900 Subject: [SMS] implement GSM340_TP_VPF_ABSOLUTE - Added function "gsm340_scts" to decode the service center time stamp into a UTC/GMT timestamp - in function gsm340_validity_period: can now decode validity period format absolute. --- openbsc/src/gsm_04_11.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 6e59eafe4..f941d90a2 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -216,10 +216,14 @@ static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans, return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA); } +static time_t gsm340_scts(u_int8_t *scts); + static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) { u_int8_t vp; unsigned long minutes; + time_t expires; + time_t now; switch (sms_vpf) { case GSM340_TP_VPF_RELATIVE: @@ -236,8 +240,12 @@ static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) break; case GSM340_TP_VPF_ABSOLUTE: /* Chapter 9.2.3.12.2 */ - /* FIXME: like service center time stamp */ - DEBUGP(DSMS, "VPI absolute not implemented yet\n"); + expires = gsm340_scts(sms_vp); + now = mktime(gmtime(NULL)); + if (expires <= now) + minutes = 0; + else + minutes = (expires-now)/60; break; case GSM340_TP_VPF_ENHANCED: /* Chapter 9.2.3.12.3 */ @@ -317,6 +325,7 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len, return len_in_bytes; } +/* Turn int into semi-octet representation: 98 => 0x89 */ static u_int8_t bcdify(u_int8_t value) { u_int8_t ret; @@ -327,6 +336,21 @@ static u_int8_t bcdify(u_int8_t value) return ret; } +/* Turn semi-octet representation into int: 0x89 => 98 */ +static u_int8_t unbcdify(u_int8_t value) +{ + u_int8_t ret; + + if ((value & 0x0F) > 9 || (value >> 4) > 9) + DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); + + ret = (value&0x0F)*10; + if (ret > 90) + ret += value>>4; + + return ret; +} + /* Generate 03.40 TP-SCTS */ static void gsm340_gen_scts(u_int8_t *scts, time_t time) { @@ -338,7 +362,30 @@ static void gsm340_gen_scts(u_int8_t *scts, time_t time) *scts++ = bcdify(tm->tm_hour); *scts++ = bcdify(tm->tm_min); *scts++ = bcdify(tm->tm_sec); - *scts++ = 0; /* FIXME: timezone */ + *scts++ = bcdify(tm->tm_gmtoff/(60*15)); +} + +/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ +static time_t gsm340_scts(u_int8_t *scts) +{ + struct tm tm; + + u_int8_t yr = unbcdify(*scts++); + + if (yr <= 80) + tm.tm_year = 100 + yr; + else + tm.tm_year = yr; + tm.tm_mon = unbcdify(*scts++) - 1; + tm.tm_mday = unbcdify(*scts++); + tm.tm_hour = unbcdify(*scts++); + tm.tm_min = unbcdify(*scts++); + tm.tm_sec = unbcdify(*scts++); + /* according to gsm 03.40 time zone is + "expressed in quarters of an hour" */ + tm.tm_gmtoff = unbcdify(*scts++) * 15*60; + + return mktime(&tm); } /* generate a msgb containing a TPDU derived from struct gsm_sms, -- cgit v1.2.3 From ccda96517c7f2f5aa10166eebe105f2f45342ad4 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 12 Nov 2009 22:28:18 +0900 Subject: move 'struct value_string' and 'get_value_string()' to gsm_data --- openbsc/include/openbsc/gsm_data.h | 7 +++++++ openbsc/src/gsm_04_11.c | 18 ------------------ openbsc/src/gsm_data.c | 13 +++++++++++++ 3 files changed, 20 insertions(+), 18 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c3ea45dce..3040525c2 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -3,6 +3,13 @@ #include +struct value_string { + unsigned int value; + const char *str; +}; + +const char *get_value_string(const struct value_string *vs, u_int32_t val); + enum gsm_band { GSM_BAND_400, GSM_BAND_850, diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index f941d90a2..75ddf9dd9 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -56,11 +56,6 @@ void *tall_gsms_ctx; static u_int32_t new_callref = 0x40000001; -struct value_string { - u_int32_t value; - const char *str; -}; - static const struct value_string cp_cause_strs[] = { { GSM411_CP_CAUSE_NET_FAIL, "Network Failure" }, { GSM411_CP_CAUSE_CONGESTION, "Congestion" }, @@ -104,19 +99,6 @@ static const struct value_string rp_cause_strs[] = { { 0, NULL } }; -const char *get_value_string(const struct value_string *vs, u_int32_t val) -{ - int i; - - for (i = 0;; i++) { - if (vs[i].value == 0 && vs[i].str == NULL) - break; - if (vs[i].value == val) - return vs[i].str; - } - return "unknown"; -} - struct gsm_sms *sms_alloc(void) { return talloc_zero(tall_gsms_ctx, struct gsm_sms); diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 59947fdb7..69a9096ca 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -30,6 +30,19 @@ void *tall_bsc_ctx; +const char *get_value_string(const struct value_string *vs, u_int32_t val) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (vs[i].value == val) + return vs[i].str; + } + return "unknown"; +} + void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr, u_int8_t e1_ts, u_int8_t e1_ts_ss) { -- cgit v1.2.3 From 0f255857d406223a85bae12d69c028274ecd66b2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 12 Nov 2009 14:48:42 +0100 Subject: ip.access: Introduce parser function for BCCH Info test result --- openbsc/include/openbsc/abis_nm.h | 45 +++++++++++++++++ openbsc/src/abis_nm.c | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 8765a7a00..a9bfceee0 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -660,6 +660,49 @@ enum abis_nm_ipacc_testres_ie { NM_IPACC_TR_IE_FREQ_ERR = 18, }; +enum ipac_eie { + NM_IPAC_EIE_ARFCN_WHITE = 0x01, + NM_IPAC_EIE_ARFCH_BLACK = 0x02, + NM_IPAC_EIE_FREQ_ERR_LIST = 0x03, + NM_IPAC_EIE_CHAN_USE_LIST = 0x04, + NM_IPAC_EIE_BCCH_INFO_TYPE = 0x05, + NM_IPAC_EIE_BCCH_INFO = 0x06, + /* FIXME */ +}; + +enum ipac_bcch_info_type { + IPAC_BINF_RXLEV = (1 << 8), + IPAC_BINF_RXQUAL = (1 << 9), + IPAC_BINF_FREQ_ERR_QUAL = (1 << 10), + IPAC_BINF_FRAME_OFFSET = (1 << 11), + IPAC_BINF_FRAME_NR_OFFSET = (1 << 12), + IPAC_BINF_BSIC = (1 << 13), + IPAC_BINF_CGI = (1 << 14), + IPAC_BINF_NEIGH_BA_SI2 = (1 << 15), + IPAC_BINF_NEIGH_BA_SI2bis = (1 << 0), + IPAC_BINF_NEIGH_BA_SI2ter = (1 << 1), + IPAC_BINF_CELL_ALLOC = (1 << 2), +}; + +/* The BCCH info from an ip.access test, in host byte order + * and already parsed... */ +struct ipac_bcch_info { + u_int16_t info_type; + u_int8_t freq_qual; + u_int16_t arfcn; + u_int8_t rx_lev; + u_int8_t rx_qual; + u_int16_t freq_err; + u_int16_t frame_offset; + u_int32_t frame_nr_offset; + u_int8_t bsic; + u_int8_t cgi[7]; + u_int8_t ba_list_si2[16]; + u_int8_t ba_list_si2bis[16]; + u_int8_t ba_list_si2ter[16]; + u_int8_t ca_list_si1[16]; +}; + /* PUBLIC */ struct msgb; @@ -754,6 +797,8 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t *attr, u_int8_t attr_len); int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, u_int32_t ip, u_int16_t port, u_int8_t stream); +int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf); +const char *ipacc_testres_name(u_int8_t res); /* Functions calling into other code parts */ enum nm_evt { diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 05dec2201..3f4fabb4a 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -572,6 +572,18 @@ const char *nm_avail_name(u_int8_t avail) return avail_names[avail]; } +static struct value_string test_names[] = { + /* FIXME: standard test names */ + { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" }, + { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" }, + { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" }, + { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" }, + { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" }, + { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" }, + { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" }, + { 0, NULL } +}; + const char *nm_adm_name(u_int8_t adm) { switch (adm) { @@ -2672,3 +2684,93 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, obj_class, bts_nr, trx_nr, ts_nr, attr, attr_len); } + +static const char *ipacc_testres_names[] = { + [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS", + [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT", + [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS", + [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL", + [NM_IPACC_TESTRES_STOPPED] = "STOPPED", +}; + +const char *ipacc_testres_name(u_int8_t res) +{ + if (res < ARRAY_SIZE(ipacc_testres_names) && + ipacc_testres_names[res]) + return ipacc_testres_names[res]; + + return "unknown"; +} + +/* parse BCCH information IEI from wire format to struct ipac_bcch_info */ +int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) +{ + u_int8_t *cur = buf; + u_int16_t len; + + memset(binf, 0, sizeof(binf)); + + if (cur[0] != NM_IPAC_EIE_BCCH_INFO) + return -EINVAL; + cur++; + + len = ntohs(*(u_int16_t *)cur); + cur += 2; + + binf->info_type = ntohs(*(u_int16_t *)cur); + cur += 2; + + if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL) + binf->freq_qual = *cur >> 2; + + binf->arfcn = *cur++ & 3 << 8; + binf->arfcn |= *cur++; + + if (binf->info_type & IPAC_BINF_RXLEV) + binf->rx_lev = *cur & 0x3f; + cur++; + + if (binf->info_type & IPAC_BINF_RXQUAL) + binf->rx_qual = *cur & 0x7; + cur++; + + if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL) + binf->freq_err = ntohs(*(u_int16_t *)cur); + cur += 2; + + if (binf->info_type & IPAC_BINF_FRAME_OFFSET) + binf->frame_offset = ntohs(*(u_int16_t *)cur); + cur += 2; + + if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET) + binf->frame_nr_offset = ntohl(*(u_int32_t *)cur); + cur += 4; + + if (binf->info_type & IPAC_BINF_BSIC) + binf->bsic = *cur++ & 0x3f; + cur++; + + memcpy(binf->cgi, cur, sizeof(binf->cgi)); + cur += sizeof(binf->cgi); + + if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) { + memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2)); + cur += sizeof(binf->ba_list_si2); + } + + if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) { + memcpy(binf->ba_list_si2bis, cur, + sizeof(binf->ba_list_si2bis)); + cur += sizeof(binf->ba_list_si2bis); + } + + if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) { + memcpy(binf->ba_list_si2ter, cur, + sizeof(binf->ba_list_si2ter)); + cur += sizeof(binf->ba_list_si2ter); + } + + return 0; +} + + -- cgit v1.2.3 From 5bde51b91ead6aee798f6194320ac9d1ec3b9a70 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 11:23:16 +0100 Subject: make ipaccess-config compile again (remove duplicate testres_name definition) --- openbsc/src/ipaccess-config.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index add45f94b..62be5ff95 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -79,23 +79,6 @@ struct ipacc_cusage_elem { rxlev:6; } __attribute__ ((packed)); -static const char *ipacc_testres_names[] = { - [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS", - [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT", - [NM_IPACC_TESTRES_NO_CHANS] = "NO CHANNELS", - [NM_IPACC_TESTRES_PARTIAL] = "PARTIAL", - [NM_IPACC_TESTRES_STOPPED] = "STOPPED", -}; - -const char *ipacc_testres_name(u_int8_t res) -{ - if (res < ARRAY_SIZE(ipacc_testres_names) && - ipacc_testres_names[res]) - return ipacc_testres_names[res]; - - return "unknown"; -} - static int test_rep(void *_msg) { struct msgb *msg = _msg; -- cgit v1.2.3 From b40a38ff46c1c6bfd8434ae346b892df3bd07efc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 11:56:05 +0100 Subject: [ip.access] Parse cell global ID as part of BCCH info --- openbsc/include/openbsc/abis_nm.h | 11 ++++++++++- openbsc/src/abis_nm.c | 23 +++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index a9bfceee0..56f8e525a 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -684,9 +684,18 @@ enum ipac_bcch_info_type { IPAC_BINF_CELL_ALLOC = (1 << 2), }; +struct cell_global_id { + u_int16_t mcc; + u_int16_t mnc; + u_int16_t lac; + u_int16_t ci; +}; + /* The BCCH info from an ip.access test, in host byte order * and already parsed... */ struct ipac_bcch_info { + struct llist_head list; + u_int16_t info_type; u_int8_t freq_qual; u_int16_t arfcn; @@ -696,7 +705,7 @@ struct ipac_bcch_info { u_int16_t frame_offset; u_int32_t frame_nr_offset; u_int8_t bsic; - u_int8_t cgi[7]; + struct cell_global_id cgi; u_int8_t ba_list_si2[16]; u_int8_t ba_list_si2bis[16]; u_int8_t ba_list_si2ter[16]; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 3f4fabb4a..63fda92e0 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2702,6 +2702,25 @@ const char *ipacc_testres_name(u_int8_t res) return "unknown"; } +void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf) +{ + cid->mcc = (buf[0] & 0xf) * 100; + cid->mcc += (buf[0] >> 4) * 10; + cid->mcc += (buf[1] & 0xf) * 1; + + if (buf[1] >> 4 == 0xf) { + cid->mnc = (buf[2] & 0xf) * 10; + cid->mnc += (buf[2] >> 4) * 1; + } else { + cid->mnc = (buf[2] & 0xf) * 100; + cid->mnc += (buf[2] >> 4) * 10; + cid->mnc += (buf[1] >> 4) * 1; + } + + cid->lac = ntohs(buf+3); + cid->ci = ntohs(buf+5); +} + /* parse BCCH information IEI from wire format to struct ipac_bcch_info */ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) { @@ -2750,8 +2769,8 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) binf->bsic = *cur++ & 0x3f; cur++; - memcpy(binf->cgi, cur, sizeof(binf->cgi)); - cur += sizeof(binf->cgi); + ipac_parse_cgi(&binf->cgi, cur); + cur += 7; if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) { memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2)); -- cgit v1.2.3 From 999549d9ae62a182d426b092042400e54abc23fd Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 12:10:18 +0100 Subject: [OML] more verbose error reporting in case object instance unknown --- openbsc/src/abis_nm.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 63fda92e0..757bb95f5 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -619,20 +619,26 @@ objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class, nm_state = &bts->nm_state; break; case NM_OC_RADIO_CARRIER: - if (obj_inst->trx_nr >= bts->num_trx) + if (obj_inst->trx_nr >= bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); nm_state = &trx->nm_state; break; case NM_OC_BASEB_TRANSC: - if (obj_inst->trx_nr >= bts->num_trx) + if (obj_inst->trx_nr >= bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); nm_state = &trx->bb_transc.nm_state; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) + if (obj_inst->trx_nr > bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); if (obj_inst->ts_nr >= TRX_NR_TS) return NULL; @@ -697,20 +703,26 @@ objclass2obj(struct gsm_bts *bts, u_int8_t obj_class, obj = bts; break; case NM_OC_RADIO_CARRIER: - if (obj_inst->trx_nr >= bts->num_trx) + if (obj_inst->trx_nr >= bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); obj = trx; break; case NM_OC_BASEB_TRANSC: - if (obj_inst->trx_nr >= bts->num_trx) + if (obj_inst->trx_nr >= bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); obj = &trx->bb_transc; break; case NM_OC_CHANNEL: - if (obj_inst->trx_nr > bts->num_trx) + if (obj_inst->trx_nr > bts->num_trx) { + DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr); return NULL; + } trx = gsm_bts_trx_num(bts, obj_inst->trx_nr); if (obj_inst->ts_nr >= TRX_NR_TS) return NULL; @@ -744,6 +756,8 @@ static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class, int rc; obj = objclass2obj(bts, obj_class, obj_inst); + if (!obj) + return -EINVAL; nm_state = objclass2nmstate(bts, obj_class, obj_inst); if (!nm_state) return -1; @@ -773,7 +787,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb) nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst); if (!nm_state) { - DEBUGPC(DNM, "\n"); + DEBUGPC(DNM, "unknown object class\n"); return -EINVAL; } -- cgit v1.2.3 From aff237d7393b7d492edbc67ddc91a1b02ab4bebf Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 14:41:52 +0100 Subject: [OML] fix bugs in BCCH info parser for ip.access --- openbsc/include/openbsc/abis_nm.h | 2 +- openbsc/src/abis_nm.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h index 56f8e525a..00697a384 100644 --- a/openbsc/include/openbsc/abis_nm.h +++ b/openbsc/include/openbsc/abis_nm.h @@ -701,7 +701,7 @@ struct ipac_bcch_info { u_int16_t arfcn; u_int8_t rx_lev; u_int8_t rx_qual; - u_int16_t freq_err; + int16_t freq_err; u_int16_t frame_offset; u_int32_t frame_nr_offset; u_int8_t bsic; diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 757bb95f5..c64582a92 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2731,8 +2731,8 @@ void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf) cid->mnc += (buf[1] >> 4) * 1; } - cid->lac = ntohs(buf+3); - cid->ci = ntohs(buf+5); + cid->lac = ntohs(*((u_int16_t *)&buf[3])); + cid->ci = ntohs(*((u_int16_t *)&buf[5])); } /* parse BCCH information IEI from wire format to struct ipac_bcch_info */ @@ -2750,6 +2750,8 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) len = ntohs(*(u_int16_t *)cur); cur += 2; + DEBUGP(DNM, "bcch info: %s\n", hexdump(cur, len)); + binf->info_type = ntohs(*(u_int16_t *)cur); cur += 2; @@ -2780,7 +2782,7 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) cur += 4; if (binf->info_type & IPAC_BINF_BSIC) - binf->bsic = *cur++ & 0x3f; + binf->bsic = *cur & 0x3f; cur++; ipac_parse_cgi(&binf->cgi, cur); -- cgit v1.2.3 From 654c9df3c83b00e1331f85df36835962adfa7782 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 14:42:52 +0100 Subject: [OML] don't hexdump bcch info --- openbsc/src/abis_nm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index c64582a92..1bd38de17 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2750,8 +2750,6 @@ int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf) len = ntohs(*(u_int16_t *)cur); cur += 2; - DEBUGP(DNM, "bcch info: %s\n", hexdump(cur, len)); - binf->info_type = ntohs(*(u_int16_t *)cur); cur += 2; -- cgit v1.2.3 From cf01b8ff56d12a6fef4960ae5e9dc3af9b94f5ec Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 13 Nov 2009 14:43:15 +0100 Subject: ipaccess-config: Print BCCH info test reports This will print test rep[orts that look like: <0020> ipaccess-config.c:91 TEST REPORT: test_no=0x43 test_res=PARTIAL <0020> ipaccess-config.c:140 ==> ARFCN 37, RxLev 24, RxQual 0: 262-1, LAC 13830 CI 10759 --- openbsc/src/ipaccess-config.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 62be5ff95..49c0ea31f 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -85,7 +85,8 @@ static int test_rep(void *_msg) struct abis_om_fom_hdr *foh = msgb_l3(msg); u_int16_t test_rep_len, ferr_list_len; struct ipacc_ferr_elem *ife; - int i; + struct ipac_bcch_info binfo; + int i, rc; DEBUGP(DNM, "TEST REPORT: "); @@ -102,7 +103,7 @@ static int test_rep(void *_msg) /* data[6]: ip.access nested IE. 3 == freq_err_list */ switch (foh->data[6]) { - case 3: + case NM_IPAC_EIE_FREQ_ERR_LIST: /* data[7..8]: length of ferr_list */ ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]); @@ -113,7 +114,7 @@ static int test_rep(void *_msg) ife->arfcn, ntohs(ife->freq_err)); } break; - case 4: + case NM_IPAC_EIE_CHAN_USE_LIST: /* data[7..8]: length of ferr_list */ ferr_list_len = ntohs(*(u_int16_t *) &foh->data[7]); @@ -125,6 +126,19 @@ static int test_rep(void *_msg) cu & 0x3ff, cu >> 10); } break; + case NM_IPAC_EIE_BCCH_INFO_TYPE: + break; + case NM_IPAC_EIE_BCCH_INFO: + rc = ipac_parse_bcch_info(&binfo, foh->data+6); + if (rc < 0) { + DEBUGP(DNM, "BCCH Info parsing failed\n"); + break; + } + DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d\n", + binfo.arfcn, binfo.rx_lev, binfo.rx_qual, + binfo.cgi.mcc, binfo.cgi.mnc, + binfo.cgi.lac, binfo.cgi.ci); + break; default: break; } -- cgit v1.2.3 From 793a1355d6cded7c3b332fd2235b9002b4b80979 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 5 Nov 2009 15:51:17 +0900 Subject: [VTY] Add feature to send silent SMS from console "Silent SMS" is a SMS that is delivered (and confirmed) but not shown on the display of the phone. You can now send such SMS by using sms send silent extension 12345 text or sms send silent imsi 123451234512345 text --- openbsc/src/vty_interface_layer3.c | 50 +++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 87c1c85f1..6fe209e2e 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -194,12 +194,12 @@ struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, const char *text) } static int _send_sms_buffer(struct gsm_subscriber *receiver, - struct buffer *b) + struct buffer *b, u_int8_t tp_pid) { struct gsm_sms *sms; sms = sms_from_text(receiver, buffer_getstr(b)); - + sms->protocol_id = tp_pid; gsm411_send_sms_subscr(receiver, sms); return CMD_SUCCESS; @@ -219,7 +219,27 @@ DEFUN(sms_send_ext, return CMD_WARNING; b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b); + rc = _send_sms_buffer(receiver, b, 0); + buffer_free(b); + + return rc; +} + +DEFUN(sms_send_silent_ext, + sms_send_silent_ext_cmd, + "sms send silent extension EXTEN .LINE", + "Send a silent message to a subscriber identified by EXTEN") +{ + struct gsm_subscriber *receiver; + struct buffer *b; + int rc; + + receiver = subscr_get_by_extension(gsmnet, argv[0]); + if (!receiver) + return CMD_WARNING; + + b = argv_to_buffer(argc, argv, 1); + rc = _send_sms_buffer(receiver, b, 64); buffer_free(b); subscr_put(receiver); @@ -240,7 +260,27 @@ DEFUN(sms_send_imsi, return CMD_WARNING; b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b); + rc = _send_sms_buffer(receiver, b, 0); + buffer_free(b); + + return rc; +} + +DEFUN(sms_send_silent_imsi, + sms_send_silent_imsi_cmd, + "sms send silent imsi IMSI .LINE", + "Send a silent message to a subscriber identified by IMSI") +{ + struct gsm_subscriber *receiver; + struct buffer *b; + int rc; + + receiver = subscr_get_by_imsi(gsmnet, argv[0]); + if (!receiver) + return CMD_WARNING; + + b = argv_to_buffer(argc, argv, 1); + rc = _send_sms_buffer(receiver, b, 64); buffer_free(b); subscr_put(receiver); @@ -307,6 +347,8 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &sms_send_pend_cmd); install_element(VIEW_NODE, &sms_send_ext_cmd); install_element(VIEW_NODE, &sms_send_imsi_cmd); + install_element(VIEW_NODE, &sms_send_silent_ext_cmd); + install_element(VIEW_NODE, &sms_send_silent_imsi_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); -- cgit v1.2.3 From 98f9c75094fcb54f7e7318a4cbfca04a8db8112f Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 14 Nov 2009 08:00:53 +0100 Subject: [VTY] restructure sms and silent sms commands --- openbsc/src/vty_interface_layer3.c | 95 +++++++++++++------------------------- 1 file changed, 32 insertions(+), 63 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 6fe209e2e..53b596098 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -205,89 +205,60 @@ static int _send_sms_buffer(struct gsm_subscriber *receiver, return CMD_SUCCESS; } -DEFUN(sms_send_ext, - sms_send_ext_cmd, - "sms send extension EXTEN .LINE", - "Send a message to a subscriber identified by EXTEN") +static struct gsm_subscriber *get_subscr_by_argv(const char *type, + const char *id) { - struct gsm_subscriber *receiver; - struct buffer *b; - int rc; - - receiver = subscr_get_by_extension(gsmnet, argv[0]); - if (!receiver) - return CMD_WARNING; - - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b, 0); - buffer_free(b); - - return rc; -} - -DEFUN(sms_send_silent_ext, - sms_send_silent_ext_cmd, - "sms send silent extension EXTEN .LINE", - "Send a silent message to a subscriber identified by EXTEN") -{ - struct gsm_subscriber *receiver; - struct buffer *b; - int rc; - - receiver = subscr_get_by_extension(gsmnet, argv[0]); - if (!receiver) - return CMD_WARNING; - - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b, 64); - buffer_free(b); - subscr_put(receiver); - - return rc; + if (!strcmp(type, "extension")) + return subscr_get_by_extension(gsmnet, id); + else if (!strcmp(type, "imsi")) + return subscr_get_by_imsi(gsmnet, id); + else if (!strcmp(type, "tmsi")) + return subscr_get_by_tmsi(gsmnet, atoi(id)); + else if (!strcmp(type, "id")) + return subscr_get_by_id(gsmnet, atoi(id)); + + return NULL; } +#define SUBSCR_TYPES "(extension|imsi|tmsi|id)" -DEFUN(sms_send_imsi, - sms_send_imsi_cmd, - "sms send imsi IMSI .LINE", - "Send a message to a subscriber identified by IMSI") +DEFUN(subscriber_send_sms, + subscriber_send_sms_cmd, + "subscriber " SUBSCR_TYPES " EXTEN sms send .LINE", + "Select subscriber based on extension") { - struct gsm_subscriber *receiver; + struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); struct buffer *b; int rc; - receiver = subscr_get_by_imsi(gsmnet, argv[0]); - if (!receiver) + if (!subscr) return CMD_WARNING; - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b, 0); + b = argv_to_buffer(argc, argv, 2); + rc = _send_sms_buffer(subscr, b, 0); buffer_free(b); return rc; } -DEFUN(sms_send_silent_imsi, - sms_send_silent_imsi_cmd, - "sms send silent imsi IMSI .LINE", - "Send a silent message to a subscriber identified by IMSI") +DEFUN(subscriber_silent_sms, + subscriber_silent_sms_cmd, + "subscriber " SUBSCR_TYPES " EXTEN silent sms send .LINE", + "Select subscriber based on extension") { - struct gsm_subscriber *receiver; + struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); struct buffer *b; int rc; - receiver = subscr_get_by_imsi(gsmnet, argv[0]); - if (!receiver) + if (!subscr) return CMD_WARNING; - b = argv_to_buffer(argc, argv, 1); - rc = _send_sms_buffer(receiver, b, 64); + b = argv_to_buffer(argc, argv, 2); + rc = _send_sms_buffer(subscr, b, 0); buffer_free(b); - subscr_put(receiver); return rc; } - DEFUN(cfg_subscr_name, cfg_subscr_name_cmd, "name NAME", @@ -336,7 +307,6 @@ DEFUN(cfg_subscr_authorized, return CMD_SUCCESS; } - int bsc_vty_init_extra(struct gsm_network *net) { gsmnet = net; @@ -345,10 +315,9 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &show_subscr_cache_cmd); install_element(VIEW_NODE, &sms_send_pend_cmd); - install_element(VIEW_NODE, &sms_send_ext_cmd); - install_element(VIEW_NODE, &sms_send_imsi_cmd); - install_element(VIEW_NODE, &sms_send_silent_ext_cmd); - install_element(VIEW_NODE, &sms_send_silent_imsi_cmd); + + install_element(VIEW_NODE, &subscriber_send_sms_cmd); + install_element(VIEW_NODE, &subscriber_silent_sms_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); -- cgit v1.2.3 From a148233b5e03935584b842250b2b511eee782839 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 14 Nov 2009 10:08:40 +0100 Subject: Add "silent call" feature to OpenBSC This allows the administrator to use the vty interface to issue a silent call to a given subscriber by using "subscriber extension XXXX silent call start" and stopping that silent call with "subscriber extension XXXX silent call stop" --- openbsc/include/openbsc/signal.h | 14 ++++++ openbsc/src/Makefile.am | 2 +- openbsc/src/silent_call.c | 92 ++++++++++++++++++++++++++++++++++++++ openbsc/src/vty_interface_layer3.c | 56 ++++++++++++++++++++++- 4 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 openbsc/src/silent_call.c (limited to 'openbsc') diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 1af849684..9e5511f6f 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -39,6 +39,7 @@ enum signal_subsystems { SS_NM, SS_LCHAN, SS_SUBSCR, + SS_SCALL, }; /* SS_PAGING signals */ @@ -85,6 +86,13 @@ enum signal_subscr { S_SUBSCR_DETACHED, }; +/* SS_SCALL signals */ +enum signal_scall { + S_SCALL_SUCCESS, + S_SCALL_EXPIRED, + S_SCALL_DETACHED, +}; + typedef int signal_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data); @@ -96,6 +104,12 @@ struct paging_signal_data { struct gsm_lchan *lchan; }; +struct scall_signal_data { + struct gsm_subscriber *subscr; + struct gsm_lchan *lchan; + void *data; +}; + /* Management */ int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data); diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 2f715bbaf..891a112aa 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -14,7 +14,7 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \ - token_auth.c rrlp.c gsm_04_80.c ussd.c + token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c new file mode 100644 index 000000000..3161834c2 --- /dev/null +++ b/openbsc/src/silent_call.c @@ -0,0 +1,92 @@ +/* GSM silent call feature */ + +/* + * (C) 2009 by Harald Welte + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int paging_cb_silent(unsigned int hooknum, unsigned int event, + struct msgb *msg, void *_lchan, void *_data) +{ + struct gsm_lchan *lchan = _lchan; + struct scall_signal_data sigdata; + int rc; + + if (hooknum != GSM_HOOK_RR_PAGING) + return -EINVAL; + + DEBUGP(DSMS, "paging_cb_silent: "); + + sigdata.lchan = lchan; + sigdata.data = _data; + + switch (event) { + case GSM_PAGING_SUCCEEDED: + DEBUGPC(DSMS, "success, using Timeslot %u on ARFCN %u\n", + lchan->ts->nr, lchan->ts->trx->arfcn); + /* increment lchan reference count */ + dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata); + use_lchan(lchan); + break; + case GSM_PAGING_EXPIRED: + DEBUGP(DSMS, "expired\n"); + dispatch_signal(SS_SCALL, S_SCALL_EXPIRED, &sigdata); + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data) +{ + int rc; + + rc = paging_request(subscr->net, subscr, RSL_CHANNEED_TCH_F, + paging_cb_silent, data); + return rc; +} + +int gsm_silent_call_stop(struct gsm_subscriber *subscr) +{ + struct gsm_lchan *lchan; + + lchan = lchan_for_subscr(subscr); + if (!lchan) + return -EINVAL; + + /* FIXME: did we actually establish a silent call for this guy? */ + put_lchan(lchan); + + return 0; +} diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 53b596098..124a368f4 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -38,6 +38,7 @@ #include #include #include +#include /* forward declarations */ void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr); @@ -55,7 +56,6 @@ static int dummy_config_write(struct vty *v) return CMD_SUCCESS; } - static struct buffer *argv_to_buffer(int argc, const char *argv[], int base) { struct buffer *b = buffer_new(1024); @@ -259,6 +259,38 @@ DEFUN(subscriber_silent_sms, return rc; } +DEFUN(subscriber_silent_call, + subscriber_silent_call_cmd, + "subscriber " SUBSCR_TYPES " EXTEN silent call (start|stop)", + "Send a silent call to a subscriber") +{ + struct gsm_subscriber *subscr = get_subscr_by_argv(argv[0], argv[1]); + int rc; + + if (!subscr) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1]); + return CMD_WARNING; + } + + if (!strcmp(argv[2], "start")) { + rc = gsm_silent_call_start(subscr, vty); + if (rc <= 0) { + vty_out(vty, "%% Subscriber not attached%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } else { + rc = gsm_silent_call_stop(subscr); + if (rc < 0) + return CMD_WARNING; + } + + subscr_put(subscr); + + return CMD_SUCCESS; +} + DEFUN(cfg_subscr_name, cfg_subscr_name_cmd, "name NAME", @@ -307,10 +339,31 @@ DEFUN(cfg_subscr_authorized, return CMD_SUCCESS; } +static int scall_cbfn(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data) +{ + struct scall_signal_data *sigdata = signal_data; + struct vty *vty = sigdata->data; + + switch (signal) { + case S_SCALL_SUCCESS: + vty_out(vty, "%% silent call on ARFCN %u timeslot %u%s", + sigdata->lchan->ts->trx->arfcn, sigdata->lchan->ts->nr, + VTY_NEWLINE); + break; + case S_SCALL_EXPIRED: + vty_out(vty, "%% silent call expired paging%s", VTY_NEWLINE); + break; + } + return 0; +} + int bsc_vty_init_extra(struct gsm_network *net) { gsmnet = net; + register_signal_handler(SS_SCALL, scall_cbfn, NULL); + install_element(VIEW_NODE, &show_subscr_cmd); install_element(VIEW_NODE, &show_subscr_cache_cmd); @@ -318,6 +371,7 @@ int bsc_vty_init_extra(struct gsm_network *net) install_element(VIEW_NODE, &subscriber_send_sms_cmd); install_element(VIEW_NODE, &subscriber_silent_sms_cmd); + install_element(VIEW_NODE, &subscriber_silent_call_cmd); install_element(CONFIG_NODE, &cfg_subscr_cmd); install_node(&subscr_node, dummy_config_write); -- cgit v1.2.3 From af8c7b497ea37c9030133de01029f2e20bb54da8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 14 Nov 2009 10:10:54 +0100 Subject: silent sms: make it silent again (type 64), fix subscriber refcount leak --- openbsc/src/vty_interface_layer3.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index 124a368f4..fe5b667f0 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -237,6 +237,8 @@ DEFUN(subscriber_send_sms, rc = _send_sms_buffer(subscr, b, 0); buffer_free(b); + subscr_put(subscr); + return rc; } @@ -253,9 +255,11 @@ DEFUN(subscriber_silent_sms, return CMD_WARNING; b = argv_to_buffer(argc, argv, 2); - rc = _send_sms_buffer(subscr, b, 0); + rc = _send_sms_buffer(subscr, b, 64); buffer_free(b); + subscr_put(subscr); + return rc; } -- cgit v1.2.3 From 20f9831168b59ee881414d29baba56ef68f850da Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 14 Nov 2009 10:11:45 +0100 Subject: VTY (silent sms / sms): better error reporting --- openbsc/src/vty_interface_layer3.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index fe5b667f0..fe107030e 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -230,9 +230,11 @@ DEFUN(subscriber_send_sms, struct buffer *b; int rc; - if (!subscr) + if (!subscr) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); return CMD_WARNING; - + } b = argv_to_buffer(argc, argv, 2); rc = _send_sms_buffer(subscr, b, 0); buffer_free(b); @@ -251,8 +253,11 @@ DEFUN(subscriber_silent_sms, struct buffer *b; int rc; - if (!subscr) + if (!subscr) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); return CMD_WARNING; + } b = argv_to_buffer(argc, argv, 2); rc = _send_sms_buffer(subscr, b, 64); @@ -273,7 +278,7 @@ DEFUN(subscriber_silent_call, if (!subscr) { vty_out(vty, "%% No subscriber found for %s %s%s", - argv[0], argv[1]); + argv[0], argv[1], VTY_NEWLINE); return CMD_WARNING; } -- cgit v1.2.3 From b54d950ac17ec1836a845abda92cf3061cd8ee59 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Nov 2009 06:00:23 +0100 Subject: silent call: add header file for function prototypes --- openbsc/include/openbsc/silent_call.h | 7 +++++++ openbsc/src/vty_interface_layer3.c | 1 + 2 files changed, 8 insertions(+) create mode 100644 openbsc/include/openbsc/silent_call.h (limited to 'openbsc') diff --git a/openbsc/include/openbsc/silent_call.h b/openbsc/include/openbsc/silent_call.h new file mode 100644 index 000000000..53ed4e248 --- /dev/null +++ b/openbsc/include/openbsc/silent_call.h @@ -0,0 +1,7 @@ +#ifndef _SILENT_CALL_H +#define _SILENT_CALL_H + +extern int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data); +extern int gsm_silent_call_stop(struct gsm_subscriber *subscr); + +#endif /* _SILENT_CALL_H */ diff --git a/openbsc/src/vty_interface_layer3.c b/openbsc/src/vty_interface_layer3.c index fe107030e..4cc08c2da 100644 --- a/openbsc/src/vty_interface_layer3.c +++ b/openbsc/src/vty_interface_layer3.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From d8cfc90e22e0645bda0c5f581c68181c3be9079b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Nov 2009 06:09:56 +0100 Subject: [abis_nm] avoid integer-to-pointer casting and associated gcc warnings --- openbsc/src/abis_nm.c | 4 ++-- openbsc/src/bsc_init.c | 7 +++++-- openbsc/src/ipaccess-config.c | 7 +++++-- 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 1bd38de17..4d4cec0a3 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -1036,7 +1036,7 @@ static int abis_nm_rcvmsg_fom(struct msgb *mb) else DEBUGPC(DNM, "\n"); - dispatch_signal(SS_NM, S_NM_NACK, (void*) ((long)mt)); + dispatch_signal(SS_NM, S_NM_NACK, (void*) &mt); return 0; } #if 0 @@ -2601,7 +2601,7 @@ static int abis_nm_rx_ipacc(struct msgb *msg) case NM_MT_IPACC_RSL_CONNECT_NACK: case NM_MT_IPACC_SET_NVATTR_NACK: case NM_MT_IPACC_GET_NVATTR_NACK: - dispatch_signal(SS_NM, S_NM_IPACC_NACK, (void*) ((long)foh->msg_type)); + dispatch_signal(SS_NM, S_NM_IPACC_NACK, &foh->msg_type); break; default: break; diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 815fe2b6e..bb1e382f0 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -443,7 +443,7 @@ static int sw_activ_rep(struct msgb *mb) } /* Callback function for NACK on the OML NM */ -static int oml_msg_nack(int mt) +static int oml_msg_nack(u_int8_t mt) { if (mt == NM_MT_SET_BTS_ATTR_NACK) { fprintf(stderr, "Failed to set BTS attributes. That is fatal. " @@ -458,11 +458,14 @@ static int oml_msg_nack(int mt) static int nm_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { + u_int8_t *msg_type; + switch (signal) { case S_NM_SW_ACTIV_REP: return sw_activ_rep(signal_data); case S_NM_NACK: - return oml_msg_nack((int)signal_data); + msg_type = signal_data; + return oml_msg_nack(*msg_type); default: break; } diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 49c0ea31f..1b2aa5e34 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -61,7 +61,7 @@ static u_int8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', * result. The nanoBTS will send us a NACK when we did something the * BTS didn't like. */ -static int ipacc_msg_nack(int mt) +static int ipacc_msg_nack(u_int8_t mt) { fprintf(stderr, "Failure to set attribute. This seems fatal\n"); exit(-1); @@ -149,9 +149,12 @@ static int test_rep(void *_msg) static int nm_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { + u_int8_t *msg_type; + switch (signal) { case S_NM_IPACC_NACK: - return ipacc_msg_nack((int)signal_data); + msg_type = signal_data; + return ipacc_msg_nack(*msg_type); case S_NM_TEST_REP: return test_rep(signal_data); default: -- cgit v1.2.3 From 986c3d76db7795e565d0a7be5402d4bfe5e1ba93 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Nov 2009 06:12:16 +0100 Subject: fix some more compiler warnings --- openbsc/src/input/misdn.c | 2 +- openbsc/src/silent_call.c | 1 + openbsc/src/vty_interface.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/input/misdn.c b/openbsc/src/input/misdn.c index 82268e811..135cfad48 100644 --- a/openbsc/src/input/misdn.c +++ b/openbsc/src/input/misdn.c @@ -262,7 +262,7 @@ static int handle_tsX_write(struct bsc_fd *bfd) ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0); if (ret < sizeof(*hh) + BCHAN_TX_GRAN) - DEBUGP(DMIB, "send returns %d instead of %u\n", ret, + DEBUGP(DMIB, "send returns %d instead of %lu\n", ret, sizeof(*hh) + BCHAN_TX_GRAN); return ret; diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c index 3161834c2..82b656327 100644 --- a/openbsc/src/silent_call.c +++ b/openbsc/src/silent_call.c @@ -32,6 +32,7 @@ #include #include #include +#include static int paging_cb_silent(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_lchan, void *_data) diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 9aa970696..894146b6f 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -620,7 +620,7 @@ DEFUN(show_e1ts, "show e1_timeslot [line_nr] [ts_nr]", SHOW_STR "Display information about a E1 timeslot\n") { - struct e1inp_line *line; + struct e1inp_line *line = NULL; struct e1inp_ts *ts; int ts_nr; -- cgit v1.2.3 From e723eac5a35d61829d9471b97a029c921c04a258 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 15 Nov 2009 12:56:12 +0100 Subject: [telnet] Remove unused variables from the telnet interface These became unused when the interface was switched to use the vty module. It is about time to remove these. --- openbsc/include/openbsc/telnet_interface.h | 7 ------- openbsc/src/telnet_interface.c | 1 - 2 files changed, 8 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/telnet_interface.h b/openbsc/include/openbsc/telnet_interface.h index 97357d794..d3381e0a4 100644 --- a/openbsc/include/openbsc/telnet_interface.h +++ b/openbsc/include/openbsc/telnet_interface.h @@ -35,13 +35,6 @@ struct telnet_connection { struct gsm_network *network; struct bsc_fd fd; struct vty *vty; - - int bts; - - int command; - char *imsi; - char commands[1024]; - int read; }; diff --git a/openbsc/src/telnet_interface.c b/openbsc/src/telnet_interface.c index d7c905518..128c34e94 100644 --- a/openbsc/src/telnet_interface.c +++ b/openbsc/src/telnet_interface.c @@ -165,7 +165,6 @@ static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) { connection->fd.fd = new_connection; connection->fd.when = BSC_FD_READ; connection->fd.cb = client_data; - connection->bts = 0; bsc_register_fd(&connection->fd); llist_add_tail(&connection->entry, &active_connections); -- cgit v1.2.3 From c7df7c6e42f6c952c2db1a634eb3530c8d33149d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 15 Nov 2009 13:50:39 +0100 Subject: [ipaccess] Fix spelling in the comment --- openbsc/src/input/ipaccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/input/ipaccess.c b/openbsc/src/input/ipaccess.c index 34d9462b9..2d9f51ef9 100644 --- a/openbsc/src/input/ipaccess.c +++ b/openbsc/src/input/ipaccess.c @@ -543,7 +543,7 @@ static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what) /* Some BTS has connected to us, but we don't know yet which line * (as created by the OML link) to associate it with. Thus, we - * aloocate a temporary bfd until we have received ID from BTS */ + * allocate a temporary bfd until we have received ID from BTS */ bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len); if (bfd->fd < 0) { -- cgit v1.2.3 From 057fec5336312cf737885be24fb959b8fcb03ef2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 16 Nov 2009 19:53:08 +0100 Subject: ipaccess-config.c: Spelling fix in the config mode --- openbsc/src/ipaccess-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/ipaccess-config.c b/openbsc/src/ipaccess-config.c index 1b2aa5e34..c50a46581 100644 --- a/openbsc/src/ipaccess-config.c +++ b/openbsc/src/ipaccess-config.c @@ -279,7 +279,7 @@ static void print_help(void) printf(" -o --oml-ip ip\n"); printf(" -r --restart\n"); printf(" -n flags/mask\tSet NVRAM attributes.\n"); - printf(" -l --listen testnr \tPerform speciified test number\n"); + printf(" -l --listen testnr \tPerform specified test number\n"); printf(" -h --help this text\n"); printf(" -s --stream-id ID\n"); } -- cgit v1.2.3 From 0fef39a8ac17484f42840a898e06923c4989db38 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 16 Nov 2009 15:37:05 +0100 Subject: [rsl] Improve error message when the lchan allocation is failing --- openbsc/src/abis_rsl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index acd41dd63..de0f4845b 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1139,7 +1139,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); if (!lchan) { - fprintf(stderr, "CHAN RQD: no resources\n"); + DEBUGP(DRSL, "CHAN RQD: no resources for %u 0x%x\n", + lctype, rqd_ref->ra); /* FIXME: send some kind of reject ?!? */ return -ENOMEM; } -- cgit v1.2.3 From f7d752f7acc0ccee32959ad0586cbbb54b1efaf8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 16 Nov 2009 17:12:38 +0100 Subject: [si] Make it possible to set the NECI value... Allow to configure the NECI value... and change code that is relying on the NECI value. --- openbsc/include/openbsc/gsm_04_08.h | 4 ++-- openbsc/include/openbsc/gsm_data.h | 1 + openbsc/src/abis_rsl.c | 4 ++-- openbsc/src/bsc_init.c | 4 ++++ openbsc/src/gsm_04_08_utils.c | 8 ++++---- openbsc/src/vty_interface.c | 12 ++++++++++++ 6 files changed, 25 insertions(+), 8 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 186a53f97..4a3bdc187 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -724,8 +724,8 @@ void gsm0408_set_reject_cause(int cause); int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id); void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc, u_int16_t mnc, u_int16_t lac); -enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra); -enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra); +enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci); +enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci); int gsm48_tx_mm_info(struct gsm_lchan *lchan); int gsm48_tx_mm_auth_req(struct gsm_lchan *lchan, u_int8_t *rand); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 3040525c2..c1b7b05ac 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -410,6 +410,7 @@ struct gsm_network { char *name_short; enum gsm_auth_policy auth_policy; int a5_encryption; + int neci; /* layer 4 */ int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index de0f4845b..2d006030f 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1133,8 +1133,8 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* determine channel type (SDCCH/TCH_F/TCH_H) based on * request reference RA */ - lctype = get_ctype_by_chreq(bts, rqd_ref->ra); - chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra); + lctype = get_ctype_by_chreq(bts, rqd_ref->ra, bts->network->neci); + chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra, bts->network->neci); /* check availability / allocate channel */ lchan = lchan_alloc(bts, lctype); diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index bb1e382f0..d11cde578 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -956,6 +956,10 @@ static void patch_si_tables(struct gsm_bts *bts) type_4->cell_sel_par.ms_txpwr_max_ccch = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); + /* Set NECI to influence channel request */ + type_3->cell_sel_par.neci = bts->network->neci; + type_4->cell_sel_par.neci = bts->network->neci; + if (bts->cell_barred) { type_1->rach_control.cell_bar = 1; type_2->rach_control.cell_bar = 1; diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 2545f33a6..0e242b778 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -302,13 +302,13 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, }; -enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra) +enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) { int i; /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = &chreq_type_neci0[i]; + const struct chreq *chr = neci ? &chreq_type_neci1[i] : &chreq_type_neci0[i]; if ((ra & chr->mask) == chr->val) return ctype_by_chreq[chr->type]; } @@ -316,13 +316,13 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra) return GSM_LCHAN_SDCCH; } -enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra) +enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) { int i; /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = &chreq_type_neci0[i]; + const struct chreq *chr = neci ? &chreq_type_neci1[i] : &chreq_type_neci0[i]; if ((ra & chr->mask) == chr->val) return reason_by_chreq[chr->type]; } diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 894146b6f..54c9d5c68 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -87,6 +87,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE); vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption, VTY_NEWLINE); + vty_out(vty, " NECI (TCH/H): %u%s", net->neci, + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -789,6 +791,15 @@ DEFUN(cfg_net_encryption, return CMD_SUCCESS; } +DEFUN(cfg_net_neci, + cfg_net_neci_cmd, + "neci (0|1)", + "Set if NECI of cell selection is to be set") +{ + gsmnet->neci = atoi(argv[0]); + return CMD_SUCCESS; +} + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -1228,6 +1239,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_name_long_cmd); install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); + install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); -- cgit v1.2.3 From 1059deb7829e93bbe5baf156d6cfbd1eea36ece0 Mon Sep 17 00:00:00 2001 From: "Andreas.Eversberg" Date: Tue, 17 Nov 2009 09:55:26 +0100 Subject: Fix configuration file generation Assign the encryption status to the right variable. Signed-off-by: Holger Freyther --- openbsc/src/vty_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 54c9d5c68..a7188a414 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -786,7 +786,7 @@ DEFUN(cfg_net_encryption, "encryption a5 (0|1|2)", "Enable or disable encryption (A5) for this network\n") { - gsmnet->auth_policy = atoi(argv[0]); + gsmnet->a5_encryption= atoi(argv[0]); return CMD_SUCCESS; } -- cgit v1.2.3 From fe9da827fd29b8e153a43d44865a37ff36ae446d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 17 Nov 2009 10:16:46 +0100 Subject: [paging] In expiration handling remove the request before doing the callback Not doing this could lead to a double deletion due the paging request being removed during the callback and afterwards as well. Change the code to save the callback data, remove the request, do the callback. A patch was proposed by Andreas Eversberg and this one is based on it. --- openbsc/src/paging.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 87c7e7d38..69902e8b1 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -197,6 +197,8 @@ static void paging_T3113_expired(void *data) { struct gsm_paging_request *req = (struct gsm_paging_request *)data; struct paging_signal_data sig_data; + void *cbfn_param; + gsm_cbfn *cbfn; DEBUGP(DPAG, "T3113 expired for request %p (%s)\n", req, req->subscr->imsi); @@ -205,11 +207,15 @@ static void paging_T3113_expired(void *data) sig_data.bts = req->bts; sig_data.lchan = NULL; - dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); - if (req->cbfn) - req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, - req->cbfn_param); + /* must be destroyed before calling cbfn, to prevent double free */ + cbfn_param = req->cbfn_param; + cbfn = req->cbfn; paging_remove_request(&req->bts->paging, req); + + dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data); + if (cbfn) + cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL, + cbfn_param); } static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, -- cgit v1.2.3 From 843b44d261c5d1087face85cc95a68fcf2efad24 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 17 Nov 2009 16:38:25 +0100 Subject: [neci] Use the correct length when going over the array Use the correct length when going over the array instead of using the neci0 values. Remove the fixme from the method as well as the issue has been addressed by adding a parameter to the method. --- openbsc/src/gsm_04_08_utils.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 0e242b778..e95de79fa 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -305,10 +305,20 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) { int i; - /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ + int length; + const struct chreq *chreq; - for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = neci ? &chreq_type_neci1[i] : &chreq_type_neci0[i]; + if (neci) { + chreq = chreq_type_neci1; + length = ARRAY_SIZE(chreq_type_neci1); + } else { + chreq = chreq_type_neci0; + length = ARRAY_SIZE(chreq_type_neci0); + } + + + for (i = 0; i < length; i++) { + const struct chreq *chr = &chreq[i]; if ((ra & chr->mask) == chr->val) return ctype_by_chreq[chr->type]; } @@ -319,10 +329,19 @@ enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) { int i; - /* FIXME: determine if we set NECI = 0 in the BTS SI4 */ + int length; + const struct chreq *chreq; + + if (neci) { + chreq = chreq_type_neci1; + length = ARRAY_SIZE(chreq_type_neci1); + } else { + chreq = chreq_type_neci0; + length = ARRAY_SIZE(chreq_type_neci0); + } - for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) { - const struct chreq *chr = neci ? &chreq_type_neci1[i] : &chreq_type_neci0[i]; + for (i = 0; i < length; i++) { + const struct chreq *chr = &chreq[i]; if ((ra & chr->mask) == chr->val) return reason_by_chreq[chr->type]; } -- cgit v1.2.3 From 135a7c65cd3bf127d0e9a2613da5699b74f9be0f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 17 Nov 2009 16:46:46 +0100 Subject: [neci] Separate handling of chan requested for paging any Allow to handle the channel requested differently based on the NECI value for the "paging any" case. This will allow to open a TCH/H, TCH/F depending on the neci mode. --- openbsc/include/openbsc/gsm_04_08.h | 3 ++- openbsc/src/gsm_04_08_utils.c | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 4a3bdc187..3e9557b1d 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -634,7 +634,8 @@ enum chreq_type { CHREQ_T_VOICE_CALL_TCH_H, CHREQ_T_DATA_CALL_TCH_H, CHREQ_T_LOCATION_UPD, - CHREQ_T_PAG_R_ANY, + CHREQ_T_PAG_R_ANY_NECI0, + CHREQ_T_PAG_R_ANY_NECI1, CHREQ_T_PAG_R_TCH_F, CHREQ_T_PAG_R_TCH_FH, }; diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index e95de79fa..08aadf99d 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -255,7 +255,7 @@ static const struct chreq chreq_type_neci1[] = { { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, { 0x00, 0xf0, CHREQ_T_LOCATION_UPD }, { 0x10, 0xf0, CHREQ_T_SDCCH }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, }; @@ -267,7 +267,7 @@ static const struct chreq chreq_type_neci0[] = { { 0xe0, 0xe0, CHREQ_T_TCH_F }, { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H }, { 0x00, 0xe0, CHREQ_T_LOCATION_UPD }, - { 0x80, 0xe0, CHREQ_T_PAG_R_ANY }, + { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, }; @@ -282,7 +282,8 @@ static const enum gsm_chan_t ctype_by_chreq[] = { [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H, [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H, [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH, - [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_SDCCH, + [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH, [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, }; @@ -297,7 +298,8 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER, [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD, - [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, }; -- cgit v1.2.3 From a6bcc7471642f4076b0aa31ae04647f1499e9bb4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 16 Nov 2009 22:49:24 +0100 Subject: [gsm48] When picking AMR we need to supply the multirate config On channel mode modify and assignment command when using the a multirate code the multirate configuration must be present in the packet. Add a parameter and add a warning when using it in a broken way. --- openbsc/include/openbsc/gsm_04_08.h | 22 ++++++++++++++++++++-- openbsc/src/gsm_04_08.c | 2 +- openbsc/src/gsm_04_08_utils.c | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 52 insertions(+), 7 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 3e9557b1d..5bd860be9 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -33,6 +33,23 @@ struct gsm48_chan_desc { }; } __attribute__ ((packed)); +/* Chapter 10.5.2.21aa */ +struct gsm48_multi_rate_conf { + u_int8_t smod : 2, + spare: 1, + icmi : 1, + nscb : 1, + ver : 3; + u_int8_t m4_75 : 1, + m5_15 : 1, + m5_90 : 1, + m6_70 : 1, + m7_40 : 1, + m7_95 : 1, + m10_2 : 1, + m12_2 : 1; +} __attribute__((packed)); + /* Chapter 10.5.2.30 */ struct gsm48_req_ref { u_int8_t ra; @@ -411,6 +428,7 @@ struct gsm48_imsi_detach_ind { #define GSM_MI_TYPE_TMSI 0x04 #define GSM_MI_ODD 0x08 +#define GSM48_IE_MUL_RATE_CFG 0x03 /* 10.5.2.21aa */ #define GSM48_IE_MOBILE_ID 0x17 #define GSM48_IE_NAME_LONG 0x43 /* 10.5.3.5a */ #define GSM48_IE_NAME_SHORT 0x45 /* 10.5.3.5a */ @@ -741,7 +759,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class, struct gsm48_multi_rate_conf *conf); int bsc_upqueue(struct gsm_network *net); @@ -759,7 +777,7 @@ int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv); int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type); int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr); -int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode); +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, struct gsm48_multi_rate_conf *conf); int gsm48_rx_rr_modif_ack(struct msgb *msg); #endif diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 6a4abfc3a..7a8bcbdea 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -3139,7 +3139,7 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; - return gsm48_lchan_modify(trans->lchan, mode->lchan_mode); + return gsm48_lchan_modify(trans->lchan, mode->lchan_mode, NULL); } static struct downstate { diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 08aadf99d..053e999b7 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -504,7 +504,8 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) } /* Chapter 9.1.2: Assignment Command */ -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command, + struct gsm48_multi_rate_conf *conf) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -533,11 +534,24 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) ass->chan_desc.h0.arfcn_low = arfcn & 0xff; ass->power_command = power_command; + /* in case of multi rate we need to attach a config */ + if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { + if (!conf) { + DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); + } else { + u_int8_t *data = msgb_put(msg, 4); + data[0] = GSM48_IE_MUL_RATE_CFG; + data[1] = 0x2; + memcpy(&data[2], conf, 2); + } + } + return gsm48_sendmsg(msg, NULL); } /* 9.1.5 Channel mode modify: Modify the mode on the MS side */ -int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) +int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode, + struct gsm48_multi_rate_conf *conf) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -561,14 +575,27 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) cmm->chan_desc.h0.arfcn_low = arfcn & 0xff; cmm->mode = mode; + /* in case of multi rate we need to attach a config */ + if (mode == GSM48_CMODE_SPEECH_AMR) { + if (!conf) { + DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); + } else { + u_int8_t *data = msgb_put(msg, 4); + data[0] = GSM48_IE_MUL_RATE_CFG; + data[1] = 0x2; + memcpy(&data[2], conf, 2); + } + } + return gsm48_sendmsg(msg, NULL); } -int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode) +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, + struct gsm48_multi_rate_conf *conf) { int rc; - rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode); + rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode, conf); if (rc < 0) return rc; -- cgit v1.2.3 From 61a83b2aec48648921472360a2e58c1b7e6310e2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 18 Nov 2009 09:20:22 +0100 Subject: max_power_limit: the limit is 24 dB ! --- openbsc/src/vty_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 894146b6f..f1e35e882 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1101,7 +1101,7 @@ DEFUN(cfg_trx_max_power_red, { int maxpwr_r = atoi(argv[0]); struct gsm_bts_trx *trx = vty->index; - int upper_limit = 12; /* default 12.21 max power red. */ + int upper_limit = 24; /* default 12.21 max power red. */ /* FIXME: check if our BTS type supports more than 12 */ if (maxpwr_r < 0 || maxpwr_r > upper_limit) { -- cgit v1.2.3 From 25f30ba00ae7a5be50724a77bdf7484886726b9b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 28 Oct 2009 09:12:43 +0100 Subject: misc: Add routine to generate backtrace from within the application E.g. to analyze the subscr_get/subscr_put behavior one can place the generate_backtrace into the functions, recompile and then filter the output with contrib/bt.py to get the function name, file and line. --- openbsc/contrib/bt.py | 33 +++++++++++++++++++++++++++++++++ openbsc/include/openbsc/gsm_utils.h | 2 ++ openbsc/src/gsm_utils.c | 19 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100755 openbsc/contrib/bt.py (limited to 'openbsc') diff --git a/openbsc/contrib/bt.py b/openbsc/contrib/bt.py new file mode 100755 index 000000000..1b111efc8 --- /dev/null +++ b/openbsc/contrib/bt.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +import os + +f = open("unbalanced") +lines = [] +for line in f: + lines.append(line) + +filenames = {} + +output = [] +for line in lines: + if "[0x" in line: + start = line.find("[") + end = line.find("]") + addr = line[start+1:end] + try: + file = filenames[addr] + except KeyError: + r = os.popen("addr2line -fs -e ./bsc_hack %s" % addr) + all = r.read().replace("\n", ",") + file = all + filenames[addr] = file + + line = line.replace(addr, file) + output.append(line) + +g = open("unbalanced.2", "w") +g.write("".join(output)) + + + diff --git a/openbsc/include/openbsc/gsm_utils.h b/openbsc/include/openbsc/gsm_utils.h index 7cd0578ad..1bd1bc55a 100644 --- a/openbsc/include/openbsc/gsm_utils.h +++ b/openbsc/include/openbsc/gsm_utils.h @@ -32,4 +32,6 @@ int gsm_7bit_encode(u_int8_t *result, const char *data); int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm); int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl); + +void generate_backtrace(); #endif diff --git a/openbsc/src/gsm_utils.c b/openbsc/src/gsm_utils.c index de18dba26..ddfd7f3de 100644 --- a/openbsc/src/gsm_utils.c +++ b/openbsc/src/gsm_utils.c @@ -23,8 +23,10 @@ #include #include +#include #include #include +#include #include /* GSM 03.38 6.2.1 Charachter packing */ @@ -148,4 +150,21 @@ int ms_pwr_dbm(enum gsm_band band, u_int8_t lvl) return -EINVAL; } +void generate_backtrace() +{ + int i, nptrs; + void *buffer[100]; + char **strings; + + nptrs = backtrace(buffer, ARRAY_SIZE(buffer)); + printf("backtrace() returned %d addresses\n", nptrs); + + strings = backtrace_symbols(buffer, nptrs); + if (!strings) + return; + for (i = 1; i < nptrs; i++) + printf("%s\n", strings[i]); + + free(strings); +} -- cgit v1.2.3 From 231163d3658d0c48d3e3dec786735244e66b8b7e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 21:06:12 +0100 Subject: [ipa] Change names of RTP methods to follow MGCP naming IPA is naming these functions CRCX, MDCX, DLCX to follow the naming of the MediaGatewayControlProtocol. Change the code to go from BIND to CRCX (create connection) and from CONNECT to MDCX (modify connection). Connect indicates that it is only possible to call it once while it is possible to call it more than once to modify the audio parmaters and such. So the IPA terminology is making a bit more sense here (now that we know it). --- openbsc/include/openbsc/abis_rsl.h | 28 ++++++++++++------------- openbsc/include/openbsc/signal.h | 4 ++-- openbsc/src/abis_rsl.c | 42 +++++++++++++++++++------------------- openbsc/src/gsm_04_08.c | 10 ++++----- openbsc/src/gsm_04_08_utils.c | 2 +- 5 files changed, 43 insertions(+), 43 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 1ffea3f14..a911be355 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -142,16 +142,16 @@ enum abis_rsl_msgtype { RSL_MT_IPAC_DISC_MUX = 0x56, RSL_MT_IPAC_DISC_MUX_ACK, RSL_MT_IPAC_DISC_MUX_NACK, - RSL_MT_IPAC_BIND = 0x70, /* Bind to local BTS RTP port */ - RSL_MT_IPAC_BIND_ACK, - RSL_MT_IPAC_BIND_NACK, - RSL_MT_IPAC_CONNECT = 0x73, - RSL_MT_IPAC_CONNECT_ACK, - RSL_MT_IPAC_CONNECT_NACK, - RSL_MT_IPAC_DISCONNECT_IND = 0x76, - RSL_MT_IPAC_DISCONNECT = 0x77, - RSL_MT_IPAC_DISCONNECT_ACK, - RSL_MT_IPAC_DISCONNECT_NACK, + RSL_MT_IPAC_CRCX = 0x70, /* Bind to local BTS RTP port */ + RSL_MT_IPAC_CRCX_ACK, + RSL_MT_IPAC_CRCX_NACK, + RSL_MT_IPAC_MDCX = 0x73, + RSL_MT_IPAC_MDCX_ACK, + RSL_MT_IPAC_MDCX_NACK, + RSL_MT_IPAC_DLCX_IND = 0x76, + RSL_MT_IPAC_DLCX = 0x77, + RSL_MT_IPAC_DLCX_ACK, + RSL_MT_IPAC_DLCX_NACK, }; /* Siemens vendor-specific */ @@ -535,10 +535,10 @@ enum rsl_mrpci_phase { int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci); /* ip.access specfic RSL extensions */ -int rsl_ipacc_bind(struct gsm_lchan *lchan); -int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, - u_int16_t port, u_int16_t conn_id, - u_int8_t rtp_payload2); +int rsl_ipacc_crcx(struct gsm_lchan *lchan); +int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, + u_int16_t port, u_int16_t conn_id, + u_int8_t rtp_payload2); int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan); int abis_rsl_rcvmsg(struct msgb *msg); diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index 9e5511f6f..fee9d5bfd 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -57,8 +57,8 @@ enum signal_sms { /* SS_ABISIP signals */ enum signal_abisip { - S_ABISIP_BIND_ACK, - S_ABISIP_DISC_IND, + S_ABISIP_CRCX_ACK, + S_ABISIP_DLCX_IND, }; /* SS_NM signals */ diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 2d006030f..f6e0b87a7 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1362,14 +1362,14 @@ static u_int8_t ipa_smod_s_for_tch_mode(u_int8_t tch_mode) } /* ip.access specific RSL extensions */ -int rsl_ipacc_bind(struct gsm_lchan *lchan) +int rsl_ipacc_crcx(struct gsm_lchan *lchan) { struct msgb *msg = rsl_msgb_alloc(); struct abis_rsl_dchan_hdr *dh; u_int8_t speech_mode; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IPAC_BIND); + init_dchan_hdr(dh, RSL_MT_IPAC_CRCX); dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); @@ -1386,7 +1386,7 @@ int rsl_ipacc_bind(struct gsm_lchan *lchan) return abis_rsl_sendmsg(msg); } -int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, +int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, u_int16_t conn_id, u_int8_t rtp_payload2) { struct msgb *msg = rsl_msgb_alloc(); @@ -1396,7 +1396,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, struct in_addr ia; dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); - init_dchan_hdr(dh, RSL_MT_IPAC_CONNECT); + init_dchan_hdr(dh, RSL_MT_IPAC_MDCX); dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS; dh->chan_nr = lchan2chan_nr(lchan); @@ -1404,7 +1404,7 @@ int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, speech_mode = 0x00 | ipa_smod_s_for_tch_mode(lchan->tch_mode); ia.s_addr = htonl(ip); - DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_CONNECT " + DEBUGP(DRSL, "channel=%s chan_nr=0x%02x IPAC_MDCX " "IP=%s PORT=%d RTP_PAYLOAD2=%d CONN_ID=%d speech_mode=0x%02x\n", gsm_ts_name(lchan->ts), dh->chan_nr, inet_ntoa(ia), port, rtp_payload2, conn_id, speech_mode); @@ -1454,7 +1454,7 @@ int rsl_ipacc_pdch_activate(struct gsm_lchan *lchan) return abis_rsl_sendmsg(msg); } -static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) +static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; @@ -1492,12 +1492,12 @@ static int abis_rsl_rx_ipacc_bindack(struct msgb *msg) ts->abis_ip.bound_port = ntohs(port); ts->abis_ip.conn_id = ntohs(attr_f8); - dispatch_signal(SS_ABISIP, S_ABISIP_BIND_ACK, msg->lchan); + dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan); return 0; } -static int abis_rsl_rx_ipacc_disc_ind(struct msgb *msg) +static int abis_rsl_rx_ipacc_dlcx_ind(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); struct tlv_parsed tv; @@ -1508,7 +1508,7 @@ static int abis_rsl_rx_ipacc_disc_ind(struct msgb *msg) print_rsl_cause(TLVP_VAL(&tv, RSL_IE_CAUSE), TLVP_LEN(&tv, RSL_IE_CAUSE)); - dispatch_signal(SS_ABISIP, S_ABISIP_DISC_IND, msg->lchan); + dispatch_signal(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan); return 0; } @@ -1523,27 +1523,27 @@ static int abis_rsl_rx_ipacc(struct msgb *msg) gsm_ts_name(msg->lchan->ts), rllh->chan_nr); switch (rllh->c.msg_type) { - case RSL_MT_IPAC_BIND_ACK: - DEBUGPC(DRSL, "IPAC_BIND_ACK "); - rc = abis_rsl_rx_ipacc_bindack(msg); + case RSL_MT_IPAC_CRCX_ACK: + DEBUGPC(DRSL, "IPAC_CRCX_ACK "); + rc = abis_rsl_rx_ipacc_crcx_ack(msg); break; - case RSL_MT_IPAC_BIND_NACK: + case RSL_MT_IPAC_CRCX_NACK: /* somehow the BTS was unable to bind the lchan to its local * port?!? */ - DEBUGPC(DRSL, "IPAC_BIND_NACK "); + DEBUGPC(DRSL, "IPAC_CRCX_NACK "); break; - case RSL_MT_IPAC_CONNECT_ACK: + case RSL_MT_IPAC_MDCX_ACK: /* the BTS tells us that a connect operation was successful */ - DEBUGPC(DRSL, "IPAC_CONNECT_ACK "); + DEBUGPC(DRSL, "IPAC_MDCX_ACK "); break; - case RSL_MT_IPAC_CONNECT_NACK: + case RSL_MT_IPAC_MDCX_NACK: /* somehow the BTS was unable to connect the lchan to a remote * port */ - DEBUGPC(DRSL, "IPAC_CONNECT_NACK "); + DEBUGPC(DRSL, "IPAC_MDCX_NACK "); break; - case RSL_MT_IPAC_DISCONNECT_IND: - DEBUGPC(DRSL, "IPAC_DISCONNECT_IND "); - rc = abis_rsl_rx_ipacc_disc_ind(msg); + case RSL_MT_IPAC_DLCX_IND: + DEBUGPC(DRSL, "IPAC_DLCX_IND "); + rc = abis_rsl_rx_ipacc_dlcx_ind(msg); break; default: DEBUGPC(DRSL, "Unknown ip.access msg_type 0x%02x", rllh->c.msg_type); diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 7a8bcbdea..4d352bc1f 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -1830,7 +1830,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, ts = lchan->ts; switch (signal) { - case S_ABISIP_BIND_ACK: + case S_ABISIP_CRCX_ACK: /* the BTS has successfully bound a TCH to a local ip/port, * which means we can connect our UDP socket to it */ if (ts->abis_ip.rtp_socket) { @@ -1848,7 +1848,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal, if (rc < 0) goto out_err; break; - case S_ABISIP_DISC_IND: + case S_ABISIP_DLCX_IND: /* the BTS tells us a RTP stream has been disconnected */ if (ts->abis_ip.rtp_socket) { rtp_socket_free(ts->abis_ip.rtp_socket); @@ -1870,7 +1870,7 @@ static int ipacc_connect_proxy_bind(struct gsm_lchan *lchan) struct rtp_socket *rs = ts->abis_ip.rtp_socket; int rc; - rc = rsl_ipacc_connect(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), + rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr), ntohs(rs->rtp.sin_local.sin_port), ts->abis_ip.conn_id, /* FIXME: use RTP payload of bound socket, not BTS*/ @@ -1911,14 +1911,14 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) } else { /* directly connect TCH RTP streams to each other */ ts = remote_lchan->ts; - rc = rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip, + rc = rsl_ipacc_mdcx(lchan, ts->abis_ip.bound_ip, ts->abis_ip.bound_port, lchan->ts->abis_ip.conn_id, ts->abis_ip.rtp_payload2); if (rc < 0) return rc; ts = lchan->ts; - rc = rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip, + rc = rsl_ipacc_mdcx(remote_lchan, ts->abis_ip.bound_ip, ts->abis_ip.bound_port, remote_lchan->ts->abis_ip.conn_id, ts->abis_ip.rtp_payload2); diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 053e999b7..b8fe43069 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -602,7 +602,7 @@ int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, /* FIXME: we not only need to do this after mode modify, but * also after channel activation */ if (is_ipaccess_bts(lchan->ts->trx->bts) && lchan_mode != GSM48_CMODE_SIGN) - rc = rsl_ipacc_bind(lchan); + rc = rsl_ipacc_crcx(lchan); return rc; } -- cgit v1.2.3 From 25b1e25dd400dda565c59a05c9abcbf08c162080 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 19:30:24 +0100 Subject: [gsm48] Send the IPA CRCX after the chan modify ack Change the CRCX after the channel has been modified. --- openbsc/src/gsm_04_08_utils.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index b8fe43069..1a0af3735 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -599,16 +599,12 @@ int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, if (rc < 0) return rc; - /* FIXME: we not only need to do this after mode modify, but - * also after channel activation */ - if (is_ipaccess_bts(lchan->ts->trx->bts) && lchan_mode != GSM48_CMODE_SIGN) - rc = rsl_ipacc_crcx(lchan); - return rc; } int gsm48_rx_rr_modif_ack(struct msgb *msg) { + int rc; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_chan_mode_modify *mod = (struct gsm48_chan_mode_modify *) gh->data; @@ -641,5 +637,11 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg) /* We've successfully modified the MS side of the channel, * now go on to modify the BTS side of the channel */ - return rsl_chan_mode_modify_req(msg->lchan); + rc = rsl_chan_mode_modify_req(msg->lchan); + + /* FIXME: we not only need to do this after mode modify, but + * also after channel activation */ + if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN) + rsl_ipacc_crcx(msg->lchan); + return rc; } -- cgit v1.2.3 From 45b0243a41582a8059a9541114865eade1e476e5 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 22:59:51 +0100 Subject: [lchan] Fix the SAPI reset in the chan allocation... Reset the whole array instead of just the first element. --- openbsc/src/chan_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index 7464aa96b..bd3ec85b2 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -213,7 +213,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) lchan->use_count = 0; /* clear sapis */ - memset(lchan->sapis, 0, sizeof(lchan->sapis)); + memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis)); /* Configure the time and start it so it will be closed */ lchan->release_timer.cb = auto_release_channel; -- cgit v1.2.3 From ea52802762b7e485d5d9aa4aa6f30b4c88425a53 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 22:57:02 +0100 Subject: [lchan] RSL and RR need the multirate config, place it in the lchan Both GSM 04.08 RR and GSM 08.58 RSL need the multirate config in the channel modify. Place the config in the lchan, change the gsm48 methods to not take the argument, change the RSL implementation to make use of it with the right IE. The other code should use the t(l)v_put routines as well but were left untouched for now. --- openbsc/include/openbsc/gsm_04_08.h | 4 ++-- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/abis_rsl.c | 5 +++++ openbsc/src/chan_alloc.c | 3 +++ openbsc/src/gsm_04_08.c | 2 +- openbsc/src/gsm_04_08_utils.c | 21 +++++++++------------ 6 files changed, 23 insertions(+), 15 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 5bd860be9..40a76549e 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -759,7 +759,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, u_int8_t apdu_len, const u_int8_t *apdu); -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class, struct gsm48_multi_rate_conf *conf); +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); int bsc_upqueue(struct gsm_network *net); @@ -777,7 +777,7 @@ int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv); int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type); int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr); -int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, struct gsm48_multi_rate_conf *conf); +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode); int gsm48_rx_rr_modif_ack(struct msgb *msg); #endif diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index c1b7b05ac..0ac8674fd 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -163,6 +163,9 @@ struct gsm_lchan { u_int8_t key_len; u_int8_t key[MAX_A5_KEY_LEN]; } encr; + + /* AMR bits */ + struct gsm48_multi_rate_conf mr_conf; /* To whom we are allocated at the moment */ struct gsm_subscriber *subscr; diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index f6e0b87a7..0dee79b17 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -648,6 +648,11 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); } + if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { + msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf), + (u_int8_t *) &lchan->mr_conf); + } + msg->trx = lchan->ts->trx; return abis_rsl_sendmsg(msg); diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c index bd3ec85b2..7ba679c87 100644 --- a/openbsc/src/chan_alloc.c +++ b/openbsc/src/chan_alloc.c @@ -215,6 +215,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type) /* clear sapis */ memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis)); + /* clear multi rate config */ + memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf)); + /* Configure the time and start it so it will be closed */ lchan->release_timer.cb = auto_release_channel; lchan->release_timer.data = lchan; diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c index 4d352bc1f..1f8235411 100644 --- a/openbsc/src/gsm_04_08.c +++ b/openbsc/src/gsm_04_08.c @@ -3139,7 +3139,7 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { struct gsm_mncc *mode = arg; - return gsm48_lchan_modify(trans->lchan, mode->lchan_mode, NULL); + return gsm48_lchan_modify(trans->lchan, mode->lchan_mode); } static struct downstate { diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index 1a0af3735..b2fbdc2c3 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -504,8 +504,7 @@ int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv) } /* Chapter 9.1.2: Assignment Command */ -int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command, - struct gsm48_multi_rate_conf *conf) +int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -536,13 +535,13 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command, /* in case of multi rate we need to attach a config */ if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { - if (!conf) { + if (lchan->mr_conf.ver == 0) { DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); } else { u_int8_t *data = msgb_put(msg, 4); data[0] = GSM48_IE_MUL_RATE_CFG; data[1] = 0x2; - memcpy(&data[2], conf, 2); + memcpy(&data[2], &lchan->mr_conf, 2); } } @@ -550,8 +549,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command, } /* 9.1.5 Channel mode modify: Modify the mode on the MS side */ -int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode, - struct gsm48_multi_rate_conf *conf) +int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) { struct msgb *msg = gsm48_msgb_alloc(); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); @@ -576,26 +574,25 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode, cmm->mode = mode; /* in case of multi rate we need to attach a config */ - if (mode == GSM48_CMODE_SPEECH_AMR) { - if (!conf) { + if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { + if (lchan->mr_conf.ver == 0) { DEBUGP(DRR, "BUG: Using multirate codec without multirate config.\n"); } else { u_int8_t *data = msgb_put(msg, 4); data[0] = GSM48_IE_MUL_RATE_CFG; data[1] = 0x2; - memcpy(&data[2], conf, 2); + memcpy(&data[2], &lchan->mr_conf, 2); } } return gsm48_sendmsg(msg, NULL); } -int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode, - struct gsm48_multi_rate_conf *conf) +int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode) { int rc; - rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode, conf); + rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode); if (rc < 0) return rc; -- cgit v1.2.3 From d54c337a831319271f453a8a2e2c50d54b51a404 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:37:48 +0100 Subject: [vty] Write out the neci configuration --- openbsc/src/vty_interface.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 7ac0216c6..09575d06b 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -274,6 +274,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); + vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); return CMD_SUCCESS; } -- cgit v1.2.3 From f926ed6b6f84c3465b602b291596287609e6f897 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:38:49 +0100 Subject: [vty] Remove tab to make the cell_identity nicely indent --- openbsc/src/vty_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 09575d06b..5712ca1c7 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -228,7 +228,7 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE); vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE); vty_out(vty, " band %s%s", gsm_band_name(bts->band), VTY_NEWLINE); - vty_out(vty, " cell_identity %u%s", bts->cell_identity, VTY_NEWLINE); + vty_out(vty, " cell_identity %u%s", bts->cell_identity, VTY_NEWLINE); vty_out(vty, " location_area_code %u%s", bts->location_area_code, VTY_NEWLINE); vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE); -- cgit v1.2.3 From ed0a47b9c5569a8b13566d2dd77da223d456277f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 1 Aug 2009 16:54:45 +0200 Subject: [debug] Add a debug area for SCCP --- openbsc/include/openbsc/debug.h | 2 ++ openbsc/src/debug.c | 1 + 2 files changed, 3 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 6ac3a5409..24f45add7 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -20,6 +20,8 @@ #define DMUX 0x4000 #define DINP 0x8000 +#define DSCCP 0x10000 + #ifdef DEBUG #define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args) #define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index fa903af98..14d6b603e 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -57,6 +57,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DMIB, "DMIB", "", "") DEBUG_CATEGORY(DMUX, "DMUX", "", "") DEBUG_CATEGORY(DMEAS, "DMEAS", "", "") + DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") }; static int use_color = 1; -- cgit v1.2.3 From 32201c50a53aa7981628bef14388067bc3706bf0 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 18 Aug 2009 12:54:50 +0200 Subject: [debug] Add a debug area for MSC --- openbsc/include/openbsc/debug.h | 1 + openbsc/src/debug.c | 1 + 2 files changed, 2 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 24f45add7..c8c0013d9 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -21,6 +21,7 @@ #define DINP 0x8000 #define DSCCP 0x10000 +#define DMSC 0x20000 #ifdef DEBUG #define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index 14d6b603e..f88a90475 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -58,6 +58,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DMUX, "DMUX", "", "") DEBUG_CATEGORY(DMEAS, "DMEAS", "", "") DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") + DEBUG_CATEGORY(DMSC, "DMSC", "", "") }; static int use_color = 1; -- cgit v1.2.3 From ff5fa4e45595671cbaf5b319eb6b6b3451b39874 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 13:05:48 +0100 Subject: [debug] Add a debug area for the MGCP code of On Waves --- openbsc/include/openbsc/debug.h | 2 ++ openbsc/src/debug.c | 1 + 2 files changed, 3 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index c8c0013d9..447c3584f 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -23,6 +23,8 @@ #define DSCCP 0x10000 #define DMSC 0x20000 +#define DMGCP 0x40000 + #ifdef DEBUG #define DEBUGP(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 0, fmt, ## args) #define DEBUGPC(ss, fmt, args...) debugp(ss, __FILE__, __LINE__, 1, fmt, ## args) diff --git a/openbsc/src/debug.c b/openbsc/src/debug.c index f88a90475..5dc2e0ff7 100644 --- a/openbsc/src/debug.c +++ b/openbsc/src/debug.c @@ -59,6 +59,7 @@ static const struct debug_info debug_info[] = { DEBUG_CATEGORY(DMEAS, "DMEAS", "", "") DEBUG_CATEGORY(DSCCP, "DSCCP", "", "") DEBUG_CATEGORY(DMSC, "DMSC", "", "") + DEBUG_CATEGORY(DMGCP, "DMGCP", "", "") }; static int use_color = 1; -- cgit v1.2.3 From ac96770ad7160323e2445859e128175d28f49295 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 29 Jul 2009 07:37:48 +0200 Subject: [sccp] Implement parts of ITU SCCP for use in the A-Interface include/sccp/sccp_types.h contain Q.713 and GSM definitions include/sccp/sccp.h is the application interface resembling the esentials of the UNIX socket interface. src/sccp.c is the actual implementation of SCCP featuring connection and UDT1 support. tests/sccp/sccp.c is testing connection creation and formating of the SCCP messages used by the A-interface. And it contains a simple fuzzing test to test the robustnes of the implementation. --- openbsc/configure.in | 2 + openbsc/include/Makefile.am | 2 +- openbsc/include/sccp/Makefile.am | 1 + openbsc/include/sccp/sccp.h | 145 +++++ openbsc/include/sccp/sccp_types.h | 383 +++++++++++++ openbsc/src/Makefile.am | 4 +- openbsc/src/sccp/sccp.c | 1129 +++++++++++++++++++++++++++++++++++++ openbsc/tests/Makefile.am | 2 +- openbsc/tests/sccp/Makefile.am | 8 + openbsc/tests/sccp/sccp_test.c | 723 ++++++++++++++++++++++++ 10 files changed, 2396 insertions(+), 3 deletions(-) create mode 100644 openbsc/include/sccp/Makefile.am create mode 100644 openbsc/include/sccp/sccp.h create mode 100644 openbsc/include/sccp/sccp_types.h create mode 100644 openbsc/src/sccp/sccp.c create mode 100644 openbsc/tests/sccp/Makefile.am create mode 100644 openbsc/tests/sccp/sccp_test.c (limited to 'openbsc') diff --git a/openbsc/configure.in b/openbsc/configure.in index 25c502972..cba6c6cd9 100644 --- a/openbsc/configure.in +++ b/openbsc/configure.in @@ -40,6 +40,7 @@ AC_OUTPUT( openbsc.pc include/openbsc/Makefile include/vty/Makefile + include/sccp/Makefile include/Makefile src/Makefile tests/Makefile @@ -49,4 +50,5 @@ AC_OUTPUT( tests/gsm0408/Makefile tests/db/Makefile tests/channel/Makefile + tests/sccp/Makefile Makefile) diff --git a/openbsc/include/Makefile.am b/openbsc/include/Makefile.am index a95129fa9..56b2a338a 100644 --- a/openbsc/include/Makefile.am +++ b/openbsc/include/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = openbsc vty +SUBDIRS = openbsc vty sccp noinst_HEADERS = mISDNif.h compat_af_isdn.h diff --git a/openbsc/include/sccp/Makefile.am b/openbsc/include/sccp/Makefile.am new file mode 100644 index 000000000..42fd31047 --- /dev/null +++ b/openbsc/include/sccp/Makefile.am @@ -0,0 +1 @@ +noinst_HEADERS = sccp_types.h sccp.h diff --git a/openbsc/include/sccp/sccp.h b/openbsc/include/sccp/sccp.h new file mode 100644 index 000000000..8ee4b680b --- /dev/null +++ b/openbsc/include/sccp/sccp.h @@ -0,0 +1,145 @@ +/* + * SCCP management code + * + * (C) 2009 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef SCCP_H +#define SCCP_H + +#include + +#include + +#include + +#include "sccp_types.h" + +struct sccp_system; + +enum { + SCCP_CONNECTION_STATE_NONE, + SCCP_CONNECTION_STATE_REQUEST, + SCCP_CONNECTION_STATE_CONFIRM, + SCCP_CONNECTION_STATE_ESTABLISHED, + SCCP_CONNECTION_STATE_RELEASE, + SCCP_CONNECTION_STATE_RELEASE_COMPLETE, + SCCP_CONNECTION_STATE_REFUSED, + SCCP_CONNECTION_STATE_SETUP_ERROR, +}; + +struct sockaddr_sccp { + sa_family_t sccp_family; /* AF_SCCP in the future??? */ + u_int8_t sccp_ssn; /* subssystem number for routing */ + + /* TODO fill in address indicator... if that is ever needed */ + + /* not sure about these */ + /* u_int8_t sccp_class; */ +}; + +/* + * parsed structure of an address + */ +struct sccp_address { + struct sccp_called_party_address address; + u_int8_t ssn; + u_int8_t poi[2]; +}; + +struct sccp_optional_data { + u_int8_t data_len; + u_int8_t data_start; +}; + +struct sccp_connection { + /* public */ + void *data_ctx; + void (*data_cb)(struct sccp_connection *conn, struct msgb *msg, unsigned int len); + + void *state_ctx; + void (*state_cb)(struct sccp_connection *, int old_state); + + struct sccp_source_reference source_local_reference; + struct sccp_source_reference destination_local_reference; + + int connection_state; + + /* private */ + /* list of active connections */ + struct llist_head list; + struct sccp_system *system; + int incoming; +}; + +/** + * system functionality to implement on top of any other transport layer: + * call sccp_system_incoming for incoming data (from the network) + * sccp will call outgoing whenever outgoing data exists + */ +int sccp_system_init(int (*outgoing)(struct msgb *data, void *ctx), void *context); +int sccp_system_incoming(struct msgb *data); + +/** + * Send data on an existing connection + */ +int sccp_connection_write(struct sccp_connection *connection, struct msgb *data); +int sccp_connection_close(struct sccp_connection *connection, int cause); +int sccp_connection_free(struct sccp_connection *connection); + +/** + * Create a new socket. Set your callbacks and then call bind to open + * the connection. + */ +struct sccp_connection *sccp_connection_socket(void); + +/** + * Open the connection and send additional data + */ +int sccp_connection_connect(struct sccp_connection *conn, + const struct sockaddr_sccp *sccp_called, + struct msgb *data); + +/** + * mostly for testing purposes only. Set the accept callback. + * TODO: add true routing information... in analogy to socket, bind, accept + */ +int sccp_connection_set_incoming(const struct sockaddr_sccp *sock, + int (*accept_cb)(struct sccp_connection *connection, void *data), + void *user_data); + +/** + * Send data in terms of unit data. A fixed address indicator will be used. + */ +int sccp_write(struct msgb *data, + const struct sockaddr_sccp *sock_sender, + const struct sockaddr_sccp *sock_target, int class); +int sccp_set_read(const struct sockaddr_sccp *sock, + int (*read_cb)(struct msgb *msgb, unsigned int, void *user_data), + void *user_data); + +/* generic sock addresses */ +extern const struct sockaddr_sccp sccp_ssn_bssap; + +/* helpers */ +u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref); +struct sccp_source_reference sccp_src_ref_from_int(u_int32_t); + +#endif diff --git a/openbsc/include/sccp/sccp_types.h b/openbsc/include/sccp/sccp_types.h new file mode 100644 index 000000000..c6b11820c --- /dev/null +++ b/openbsc/include/sccp/sccp_types.h @@ -0,0 +1,383 @@ +/* + * ITU Q.713 defined types for SCCP + * + * (C) 2009 by Holger Hans Peter Freyther + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef SCCP_TYPES_H +#define SCCP_TYPES_H + +/* Table 1/Q.713 - SCCP message types */ +enum sccp_message_types { + SCCP_MSG_TYPE_CR = 1, + SCCP_MSG_TYPE_CC = 2, + SCCP_MSG_TYPE_CREF = 3, + SCCP_MSG_TYPE_RLSD = 4, + SCCP_MSG_TYPE_RLC = 5, + SCCP_MSG_TYPE_DT1 = 6, + SCCP_MSG_TYPE_DT2 = 7, + SCCP_MSG_TYPE_AK = 8, + SCCP_MSG_TYPE_UDT = 9, + SCCP_MSG_TYPE_UDTS = 10, + SCCP_MSG_TYPE_ED = 11, + SCCP_MSG_TYPE_EA = 12, + SCCP_MSG_TYPE_RSR = 13, + SCCP_MSG_TYPE_RSC = 14, + SCCP_MSG_TYPE_ERR = 15, + SCCP_MSG_TYPE_IT = 16, + SCCP_MSG_TYPE_XUDT = 17, + SCCP_MSG_TYPE_XUDTS = 18, + SCCP_MSG_TYPE_LUDT = 19, + SCCP_MSG_TYPE_LUDTS = 20 +}; + +/* Table 2/Q.713 - SCCP parameter name codes */ +enum sccp_parameter_name_codes { + SCCP_PNC_END_OF_OPTIONAL = 0, + SCCP_PNC_DESTINATION_LOCAL_REFERENCE = 1, + SCCP_PNC_SOURCE_LOCAL_REFERENCE = 2, + SCCP_PNC_CALLED_PARTY_ADDRESS = 3, + SCCP_PNC_CALLING_PARTY_ADDRESS = 4, + SCCP_PNC_PROTOCOL_CLASS = 5, + SCCP_PNC_SEGMENTING = 6, + SCCP_PNC_RECEIVE_SEQ_NUMBER = 7, + SCCP_PNC_SEQUENCING = 8, + SCCP_PNC_CREDIT = 9, + SCCP_PNC_RELEASE_CAUSE = 10, + SCCP_PNC_RETURN_CAUSE = 11, + SCCP_PNC_RESET_CAUSE = 12, + SCCP_PNC_ERROR_CAUSE = 13, + SCCP_PNC_REFUSAL_CAUSE = 14, + SCCP_PNC_DATA = 15, + SCCP_PNC_SEGMENTATION = 16, + SCCP_PNC_HOP_COUNTER = 17, + SCCP_PNC_IMPORTANCE = 18, + SCCP_PNC_LONG_DATA = 19, +}; + +/* Figure 3/Q.713 Called/calling party address */ +enum { + SCCP_TITLE_IND_NONE = 0, + SCCP_TITLE_IND_NATURE_ONLY = 1, + SCCP_TITLE_IND_TRANSLATION_ONLY = 2, + SCCP_TITLE_IND_TRANS_NUM_ENC = 3, + SCCP_TITLE_IND_TRANS_NUM_ENC_NATURE = 4, +}; + +enum { + SCCP_CALL_ROUTE_ON_SSN = 1, + SCCP_CALL_ROUTE_ON_GT = 0, +}; + +struct sccp_called_party_address { + u_int8_t point_code_indicator : 1, + ssn_indicator : 1, + global_title_indicator : 4, + routing_indicator : 1, + reserved : 1; + u_int8_t data[0]; +} __attribute__((packed)); + +/* indicator indicates presence in the above order */ + +/* Figure 6/Q.713 */ +struct sccp_signalling_point_code { + u_int8_t lsb; + u_int8_t msb : 6, + reserved : 2; +} __attribute__((packed)); + +/* SSN == subsystem number */ +enum sccp_subsystem_number { + SCCP_SSN_NOT_KNOWN_OR_USED = 0, + SCCP_SSN_MANAGEMENT = 1, + SCCP_SSN_RESERVED_ITU = 2, + SCCP_SSN_ISDN_USER_PART = 3, + SCCP_SSN_OMAP = 4, /* operation, maint and administration part */ + SCCP_SSN_MAP = 5, /* mobile application part */ + SCCP_SSN_HLR = 6, + SCCP_SSN_VLR = 7, + SCCP_SSN_MSC = 8, + SCCP_SSN_EIC = 9, /* equipent identifier centre */ + SCCP_SSN_AUC = 10, /* authentication centre */ + SCCP_SSN_ISDN_SUPPL_SERVICES = 11, + SCCP_SSN_RESERVED_INTL = 12, + SCCP_SSN_ISDN_EDGE_TO_EDGE = 13, + SCCP_SSN_TC_TEST_RESPONDER = 14, + + /* From GSM 03.03 8.2 */ + SCCP_SSN_BSSAP = 254, + SCCP_SSN_BSSOM = 253, +}; + +/* Q.713, 3.4.2.3 */ +enum { + SCCP_NAI_UNKNOWN = 0, + SCCP_NAI_SUBSCRIBER_NUMBER = 1, + SCCP_NAI_RESERVED_NATIONAL = 2, + SCCP_NAI_NATIONAL_SIGNIFICANT = 3, + SCCP_NAI_INTERNATIONAL = 4, +}; + +struct sccp_global_title { + u_int8_t nature_of_addr_ind : 7, + odd_even : 1; + u_int8_t data[0]; +} __attribute__((packed)); + +/* Q.713, 3.3 */ +struct sccp_source_reference { + u_int8_t octet1; + u_int8_t octet2; + u_int8_t octet3; +} __attribute__((packed)); + +/* Q.714, 3.6 */ +enum sccp_protocol_class { + SCCP_PROTOCOL_CLASS_0 = 0, + SCCP_PROTOCOL_CLASS_1 = 1, + SCCP_PROTOCOL_CLASS_2 = 2, + SCCP_PROTOCOL_CLASS_3 = 3, +}; + +/* bits 5-8 when class0, class1 is used */ +enum sccp_protocol_options { + SCCP_PROTOCOL_NO_SPECIAL = 0, + SCCP_PROTOCOL_RETURN_MESSAGE = 8, +}; + +enum sccp_release_cause { + SCCP_RELEASE_CAUSE_END_USER_ORIGINATED = 0, + SCCP_RELEASE_CAUSE_END_USER_CONGESTION = 1, + SCCP_RELEASE_CAUSE_END_USER_FAILURE = 2, + SCCP_RELEASE_CAUSE_SCCP_USER_ORIGINATED = 3, + SCCP_RELEASE_CAUSE_REMOTE_PROCEDURE_ERROR = 4, + SCCP_RELEASE_CAUSE_INCONSISTENT_CONN_DATA = 5, + SCCP_RELEASE_CAUSE_ACCESS_FAILURE = 6, + SCCP_RELEASE_CAUSE_ACCESS_CONGESTION = 7, + SCCP_RELEASE_CAUSE_SUBSYSTEM_FAILURE = 8, + SCCP_RELEASE_CAUSE_SUBSYSTEM_CONGESTION = 9, + SCCP_RELEASE_CAUSE_MTP_FAILURE = 10, + SCCP_RELEASE_CAUSE_NETWORK_CONGESTION = 11, + SCCP_RELEASE_CAUSE_EXPIRATION_RESET = 12, + SCCP_RELEASE_CAUSE_EXPIRATION_INACTIVE = 13, + SCCP_RELEASE_CAUSE_RESERVED = 14, + SCCP_RELEASE_CAUSE_UNQUALIFIED = 15, + SCCP_RELEASE_CAUSE_SCCP_FAILURE = 16, +}; + +enum sccp_return_cause { + SCCP_RETURN_CAUSE_NO_TRANSLATION_NATURE = 0, + SCCP_RETURN_CAUSE_NO_TRANSLATION = 1, + SCCP_RETURN_CAUSE_SUBSYSTEM_CONGESTION = 2, + SCCP_RETURN_CAUSE_SUBSYSTEM_FAILURE = 3, + SCCP_RETURN_CAUSE_UNEQUIPPED_USER = 4, + SCCP_RETURN_CAUSE_MTP_FAILURE = 5, + SCCP_RETURN_CAUSE_NETWORK_CONGESTION = 6, + SCCP_RETURN_CAUSE_UNQUALIFIED = 7, + SCCP_RETURN_CAUSE_ERROR_IN_MSG_TRANSPORT = 8, + SCCP_RETURN_CAUSE_ERROR_IN_LOCAL_PROCESSING = 9, + SCCP_RETURN_CAUSE_DEST_CANNOT_PERFORM_REASSEMBLY = 10, + SCCP_RETURN_CAUSE_SCCP_FAILURE = 11, + SCCP_RETURN_CAUSE_HOP_COUNTER_VIOLATION = 12, + SCCP_RETURN_CAUSE_SEGMENTATION_NOT_SUPPORTED= 13, + SCCP_RETURN_CAUSE_SEGMENTATION_FAOLURE = 14 +}; + +enum sccp_reset_cause { + SCCP_RESET_CAUSE_END_USER_ORIGINATED = 0, + SCCP_RESET_CAUSE_SCCP_USER_ORIGINATED = 1, + SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PS = 2, + SCCP_RESET_CAUSE_MSG_OUT_OF_ORDER_PR = 3, + SCCP_RESET_CAUSE_RPC_OUT_OF_WINDOW = 4, + SCCP_RESET_CAUSE_RPC_INCORRECT_PS = 5, + SCCP_RESET_CAUSE_RPC_GENERAL = 6, + SCCP_RESET_CAUSE_REMOTE_END_USER_OPERATIONAL= 7, + SCCP_RESET_CAUSE_NETWORK_OPERATIONAL = 8, + SCCP_RESET_CAUSE_ACCESS_OPERATIONAL = 9, + SCCP_RESET_CAUSE_NETWORK_CONGESTION = 10, + SCCP_RESET_CAUSE_RESERVED = 11, +}; + +enum sccp_error_cause { + SCCP_ERROR_LRN_MISMATCH_UNASSIGNED = 0, /* local reference number */ + SCCP_ERROR_LRN_MISMATCH_INCONSISTENT = 1, + SCCP_ERROR_POINT_CODE_MISMATCH = 2, + SCCP_ERROR_SERVICE_CLASS_MISMATCH = 3, + SCCP_ERROR_UNQUALIFIED = 4, +}; + +enum sccp_refusal_cause { + SCCP_REFUSAL_END_USER_ORIGINATED = 0, + SCCP_REFUSAL_END_USER_CONGESTION = 1, + SCCP_REFUSAL_END_USER_FAILURE = 2, + SCCP_REFUSAL_SCCP_USER_ORIGINATED = 3, + SCCP_REFUSAL_DESTINATION_ADDRESS_UKNOWN = 4, + SCCP_REFUSAL_DESTINATION_INACCESSIBLE = 5, + SCCP_REFUSAL_NET_QOS_NON_TRANSIENT = 6, + SCCP_REFUSAL_NET_QOS_TRANSIENT = 7, + SCCP_REFUSAL_ACCESS_FAILURE = 8, + SCCP_REFUSAL_ACCESS_CONGESTION = 9, + SCCP_REFUSAL_SUBSYSTEM_FAILURE = 10, + SCCP_REFUSAL_SUBSYTEM_CONGESTION = 11, + SCCP_REFUSAL_EXPIRATION = 12, + SCCP_REFUSAL_INCOMPATIBLE_USER_DATA = 13, + SCCP_REFUSAL_RESERVED = 14, + SCCP_REFUSAL_UNQUALIFIED = 15, + SCCP_REFUSAL_HOP_COUNTER_VIOLATION = 16, + SCCP_REFUSAL_SCCP_FAILURE = 17, + SCCP_REFUSAL_UNEQUIPPED_USER = 18, +}; + +/* + * messages... as of Q.713 Chapter 4 + */ +struct sccp_connection_request { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference source_local_reference; + u_int8_t proto_class; + + + /* variable */ + u_int8_t variable_called; +#if VARIABLE + called_party_address +#endif + + /* optional */ + u_int8_t optional_start; + +#if OPTIONAL + credit 3 + callingparty var 4-n + data 3-130 + hop_counter 3 + importance 3 + end_of_optional 1 +#endif + + u_int8_t data[0]; +} __attribute__((packed)); + +struct sccp_connection_confirm { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference destination_local_reference; + struct sccp_source_reference source_local_reference; + u_int8_t proto_class; + + /* optional */ + u_int8_t optional_start; + + /* optional */ +#if OPTIONAL + credit 3 + called party 4 + data 3-130 + importance 3 + end_of_optional 1 +#endif + + u_int8_t data[0]; +} __attribute__((packed)); + +struct sccp_connection_refused { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference destination_local_reference; + u_int8_t cause; + + /* optional */ + u_int8_t optional_start; + + /* optional */ +#if OPTIONAL + called party 4 + data 3-130 + importance 3 + end_of_optional 1 +#endif + + u_int8_t data[0]; +} __attribute__((packed)); + +struct sccp_connection_released { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference destination_local_reference; + struct sccp_source_reference source_local_reference; + u_int8_t release_cause; + + + /* optional */ + u_int8_t optional_start; + +#if OPTIONAL + data 3-130 + importance 3 + end_of_optional 1 +#endif + u_int8_t data[0]; +} __attribute__((packed)); + +struct sccp_connection_release_complete { + u_int8_t type; + struct sccp_source_reference destination_local_reference; + struct sccp_source_reference source_local_reference; +} __attribute__((packed)); + +struct sccp_data_form1 { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference destination_local_reference; + u_int8_t segmenting; + + /* variable */ + u_int8_t variable_start; + +#if VARIABLE + data 2-256; +#endif + + u_int8_t data[0]; +} __attribute__((packed)); + + +struct sccp_data_unitdata { + /* mandantory */ + u_int8_t type; + u_int8_t proto_class; + + + /* variable */ + u_int8_t variable_called; + u_int8_t variable_calling; + u_int8_t variable_data; + +#if VARIABLE + called party address + calling party address +#endif + + u_int8_t data[0]; +} __attribute__((packed)); + +#endif diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 891a112aa..79120081d 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync -noinst_LIBRARIES = libbsc.a libmsc.a libvty.a +noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ @@ -18,6 +18,8 @@ libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c +libsccp_a_SOURCES = sccp/sccp.c + bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c new file mode 100644 index 000000000..8b111b2f5 --- /dev/null +++ b/openbsc/src/sccp/sccp.c @@ -0,0 +1,1129 @@ +/* + * SCCP management code + * + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include + +#include +#include +#include + +static void *tall_sccp_ctx; +static LLIST_HEAD(sccp_connections); + +#define SCCP_MSG_SIZE 4096 +#define SCCP_MSG_HEADROOM 128 + +/* global data */ +const struct sockaddr_sccp sccp_ssn_bssap = { + .sccp_family = 0, + .sccp_ssn = SCCP_SSN_BSSAP, +}; + +struct sccp_system { + /* layer3 -> layer2 */ + int (*write_data)(struct msgb *data, void *context); + void *write_context; +}; + + +static struct sccp_system sccp_system = { + .write_data = NULL, +}; + +struct sccp_data_callback { + /* connection based */ + int (*accept_cb)(struct sccp_connection *, void *); + void *accept_context; + + /* connection less */ + int (*read_cb)(struct msgb *, unsigned int, void *); + void *read_context; + + u_int8_t ssn; + struct llist_head callback; +}; + +static LLIST_HEAD(sccp_callbacks); + +static struct sccp_data_callback *_find_ssn(u_int8_t ssn) +{ + struct sccp_data_callback *cb; + + llist_for_each_entry(cb, &sccp_callbacks, callback) { + if (cb->ssn == ssn) + return cb; + } + + /* need to add one */ + cb = talloc_zero(tall_sccp_ctx, struct sccp_data_callback); + if (!cb) { + DEBUGP(DSCCP, "Failed to allocate sccp callback.\n"); + return NULL; + } + + cb->ssn = ssn; + llist_add_tail(&cb->callback, &sccp_callbacks); + return cb; +} + + +static int _send_msg(struct msgb *msg) +{ + return sccp_system.write_data(msg, sccp_system.write_context); +} + +/* + * parsing routines + */ +static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb *msgb) +{ + struct sccp_called_party_address *party; + + int room = msgb_l2len(msgb) - offset; + u_int8_t read = 0; + u_int8_t length; + + if (room <= 0) { + DEBUGP(DSCCP, "Not enough room for an address: %u\n", room); + return -1; + } + + length = msgb->l2h[offset]; + if (room <= length) { + DEBUGP(DSCCP, "Not enough room for optional data %u %u\n", room, length); + return -1; + } + + + party = (struct sccp_called_party_address *)(msgb->l2h + offset + 1); + if (party->point_code_indicator) { + if (length <= read + 2) { + DEBUGP(DSCCP, "POI does not fit %u\n", length); + return -1; + } + + + memcpy(&addr->poi, &party->data[read], 2); + read += 2; + } + + if (party->ssn_indicator) { + if (length <= read + 1) { + DEBUGP(DSCCP, "SSN does not fit %u\n", length); + return -1; + } + + addr->ssn = party->data[read]; + read += 1; + } + + if (party->global_title_indicator) { + DEBUGP(DSCCP, "GTI not supported %u\n", *(u_int8_t *)party); + return -1; + } + + addr->address = *party; + return 0; +} + +static int check_address(struct sccp_address *addr) +{ + /* ignore point_code_indicator... it should be zero... but */ + if (addr->address.ssn_indicator != 1 + || addr->address.global_title_indicator == 1 + || addr->address.routing_indicator != 1) { + DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + *(u_int8_t *)&addr->address, addr->ssn); + return -1; + } + + return 0; +} + +static int _sccp_parse_optional_data(const int offset, + struct msgb *msgb, struct sccp_optional_data *data) +{ + u_int16_t room = msgb_l2len(msgb) - offset; + u_int16_t read = 0; + + while (room > read) { + u_int8_t type = msgb->l2h[offset + read]; + if (type == SCCP_PNC_END_OF_OPTIONAL) + return 0; + + if (read + 1 >= room) { + DEBUGP(DSCCP, "no place for length\n"); + return 0; + } + + u_int8_t length = msgb->l2h[offset + read + 1]; + read += 2 + length; + + + if (room <= read) { + DEBUGP(DSCCP, "no space for the data: type: %d read: %d room: %d l2: %d\n", + type, read, room, msgb_l2len(msgb)); + return 0; + } + + if (type == SCCP_PNC_DATA) { + data->data_len = length; + data->data_start = offset + read - length; + } + + } + + return -1; +} + +/* + * Send UDT. Currently we have a fixed address... + */ +static int _sccp_send_data(int class, const struct sockaddr_sccp *in, + const struct sockaddr_sccp *out, struct msgb *payload) +{ + struct sccp_data_unitdata *udt; + u_int8_t *data; + int ret; + + if (msgb_l3len(payload) > 256) { + DEBUGP(DSCCP, "The payload is too big for one udt\n"); + return -1; + } + + struct msgb *msg = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp: udt"); + msg->l2h = &msg->data[0]; + udt = (struct sccp_data_unitdata *)msgb_put(msg, sizeof(*udt)); + + udt->type = SCCP_MSG_TYPE_UDT; + udt->proto_class = class; + udt->variable_called = 3; + udt->variable_calling = 5; + udt->variable_data = 7; + + /* for variable data we start with a size and the data */ + data = msgb_put(msg, 1 + 2); + data[0] = 2; + data[1] = 0x42; + data[2] = out->sccp_ssn; + + data = msgb_put(msg, 1 + 2); + data[0] = 2; + data[1] = 0x42; + data[2] = in->sccp_ssn; + + /* copy the payload */ + data = msgb_put(msg, 1 + msgb_l3len(payload)); + data[0] = msgb_l3len(payload); + memcpy(&data[1], payload->l3h, msgb_l3len(payload)); + + ret = _send_msg(msg); + msgb_free(msg); + + return ret; +} + +static int _sccp_handle_read(struct msgb *msgb) +{ + static const u_int32_t header_size = sizeof(struct sccp_data_unitdata); + static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called); + static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling); + static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data); + + struct sccp_data_callback *cb; + struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; + struct sccp_address called, calling; + + /* we don't have enough size for the struct */ + if (msgb_l2len(msgb) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + /* copy out the calling and called address. Add the off */ + if (copy_address(&called, called_offset + udt->variable_called, msgb) != 0) + return -1; + + if (check_address(&called) != 0) { + DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + *(u_int8_t *)&called.address, called.ssn); + return -1; + } + + cb = _find_ssn(called.ssn); + if (!cb || !cb->read_cb) { + DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", called.ssn); + return -1; + } + + if (copy_address(&calling, calling_offset + udt->variable_calling, msgb) != 0) + return -1; + + if (check_address(&calling) != 0) { + DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + *(u_int8_t *)&called.address, called.ssn); + } + + /* we don't have enough size for the data */ + if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) { + DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n", + msgb_l2len(msgb), header_size, udt->variable_data); + return -1; + } + + + msgb->l3h = &udt->data[udt->variable_data]; + + if (msgb_l3len(msgb) != msgb->l3h[-1]) { + DEBUGP(DSCCP, "msgb is truncated %u %u\n", + msgb_l3len(msgb), msgb->l3h[-1]); + return -1; + } + + /* sanity check */ + return cb->read_cb(msgb, msgb_l3len(msgb), cb->read_context); +} + +/* + * handle connection orientated methods + */ +static int source_local_reference_is_free(struct sccp_source_reference *reference) +{ + struct sccp_connection *connection; + + llist_for_each_entry(connection, &sccp_connections, list) { + if (memcmp(reference, &connection->source_local_reference, sizeof(*reference)) == 0) + return -1; + } + + return 0; +} + +static int destination_local_reference_is_free(struct sccp_source_reference *reference) +{ + struct sccp_connection *connection; + + llist_for_each_entry(connection, &sccp_connections, list) { + if (memcmp(reference, &connection->destination_local_reference, sizeof(*reference)) == 0) + return -1; + } + + return 0; +} + +static int assign_source_local_reference(struct sccp_connection *connection) +{ + static u_int32_t last_ref = 0x30000; + int wrapped = 0; + + do { + struct sccp_source_reference reference; + reference.octet1 = (last_ref >> 0) & 0xff; + reference.octet2 = (last_ref >> 8) & 0xff; + reference.octet3 = (last_ref >> 16) & 0xff; + + ++last_ref; + /* do not use the reversed word and wrap around */ + if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) { + DEBUGP(DSCCP, "Wrapped searching for a free code\n"); + last_ref = 0; + ++wrapped; + } + + if (source_local_reference_is_free(&reference) == 0) { + connection->source_local_reference = reference; + return 0; + } + } while (wrapped != 2); + + DEBUGP(DSCCP, "Finding a free reference failed\n"); + return -1; +} + +static void _sccp_set_connection_state(struct sccp_connection *connection, int new_state) +{ + int old_state = connection->connection_state; + + connection->connection_state = new_state; + if (connection->state_cb) + connection->state_cb(connection, old_state); +} + +static int _sccp_send_refuse(struct sccp_connection_request *req, int cause) +{ + struct msgb *msgb; + struct sccp_connection_refused *ref; + u_int8_t *data; + int ret; + + msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp ref"); + msgb->l2h = &msgb->data[0]; + + ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref)); + ref->type = SCCP_MSG_TYPE_CREF; + memcpy(&ref->destination_local_reference, &req->source_local_reference, + sizeof(struct sccp_source_reference)); + ref->cause = cause; + ref->optional_start = 1; + + data = msgb_put(msgb, 1); + data[0] = SCCP_PNC_END_OF_OPTIONAL; + + ret = _send_msg(msgb); + msgb_free(msgb); + return ret; +} + +static int _sccp_send_connection_confirm(struct sccp_connection *connection) +{ + struct msgb *response; + struct sccp_connection_confirm *confirm; + u_int8_t *optional_data; + int ret; + + if (assign_source_local_reference(connection) != 0) + return -1; + + response = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp confirm"); + response->l2h = &response->data[0]; + + confirm = (struct sccp_connection_confirm *) msgb_put(response, sizeof(*confirm)); + + confirm->type = SCCP_MSG_TYPE_CC; + memcpy(&confirm->destination_local_reference, + &connection->destination_local_reference, + sizeof(connection->destination_local_reference)); + memcpy(&confirm->source_local_reference, + &connection->source_local_reference, + sizeof(connection->source_local_reference)); + confirm->proto_class = 2; + confirm->optional_start = 1; + + optional_data = (u_int8_t *) msgb_put(response, 1); + optional_data[0] = SCCP_PNC_END_OF_OPTIONAL; + + ret = _send_msg(response); + msgb_free(response); + + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_ESTABLISHED); + return ret; +} + +static int _sccp_send_connection_request(struct sccp_connection *connection, + const struct sockaddr_sccp *called, struct msgb *msg) +{ + struct msgb *request; + struct sccp_connection_request *req; + u_int8_t *data; + u_int8_t extra_size = 3 + 1; + int ret; + + + if (msg && (msgb_l3len(msg) < 3 || msgb_l3len(msg) > 130)) { + DEBUGP(DSCCP, "Invalid amount of data... %d\n", msgb_l3len(msg)); + return -1; + } + + /* try to find a id */ + if (assign_source_local_reference(connection) != 0) { + DEBUGP(DSCCP, "Assigning a local reference failed.\n"); + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_SETUP_ERROR); + return -1; + } + + + if (msg) + extra_size += 2 + msgb_l3len(msg); + request = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp connection request"); + request->l2h = &request->data[0]; + req = (struct sccp_connection_request *) msgb_put(request, sizeof(*req)); + + req->type = SCCP_MSG_TYPE_CR; + memcpy(&req->source_local_reference, &connection->source_local_reference, + sizeof(connection->source_local_reference)); + req->proto_class = 2; + req->variable_called = 2; + req->optional_start = 4; + + /* write the called party address */ + data = msgb_put(request, 1 + 2); + data[0] = 2; + data[1] = 0x42; + data[2] = called->sccp_ssn; + + /* write the payload */ + if (msg) { + data = msgb_put(request, 2 + msgb_l3len(msg)); + data[0] = SCCP_PNC_DATA; + data[1] = msgb_l3len(msg); + memcpy(&data[2], msg->l3h, msgb_l3len(msg)); + } + + data = msgb_put(request, 1); + data[0] = SCCP_PNC_END_OF_OPTIONAL; + + llist_add_tail(&connection->list, &sccp_connections); + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REQUEST); + + ret = _send_msg(request); + msgb_free(request); + + return ret; +} + +static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data) +{ + struct msgb *msgb; + struct sccp_data_form1 *dt1; + u_int8_t *data; + int extra_size; + int ret; + + if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) { + DEBUGP(DSCCP, "data size too big, segmenting unimplemented.\n"); + return -1; + } + + extra_size = 1 + msgb_l3len(_data); + msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp dt1"); + msgb->l2h = &msgb->data[0]; + + dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1)); + dt1->type = SCCP_MSG_TYPE_DT1; + memcpy(&dt1->destination_local_reference, &conn->destination_local_reference, + sizeof(struct sccp_source_reference)); + dt1->segmenting = 0; + + /* copy the data */ + dt1->variable_start = 1; + data = msgb_put(msgb, extra_size); + data[0] = extra_size - 1; + memcpy(&data[1], _data->l3h, extra_size - 1); + + ret = _send_msg(msgb); + msgb_free(msgb); + + return ret; +} + +static int _sccp_send_connection_released(struct sccp_connection *conn, int cause) +{ + struct msgb *msg; + struct sccp_connection_released *rel; + u_int8_t *data; + int ret; + + msg = msgb_alloc_headroom(SCCP_MSG_SIZE, SCCP_MSG_HEADROOM, + "sccp: connection released"); + msg->l2h = &msg->data[0]; + rel = (struct sccp_connection_released *) msgb_put(msg, sizeof(*rel)); + rel->type = SCCP_MSG_TYPE_RLSD; + rel->release_cause = cause; + + /* copy the source references */ + memcpy(&rel->destination_local_reference, &conn->destination_local_reference, + sizeof(struct sccp_source_reference)); + memcpy(&rel->source_local_reference, &conn->source_local_reference, + sizeof(struct sccp_source_reference)); + + data = msgb_put(msg, 1); + data[0] = SCCP_PNC_END_OF_OPTIONAL; + + _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE); + ret = _send_msg(msg); + msgb_free(msg); + + return ret; +} + +/* + * Open a connection. The following is going to happen: + * + * - Verify the packet, e.g. that we have no other connection + * that id. + * - Ask the user if he wants to accept the connection + * - Try to open the connection by assigning a source local reference + * and sending the packet + */ +static int _sccp_handle_connection_request(struct msgb *msgb) +{ + static const u_int32_t header_size = + sizeof(struct sccp_connection_request); + static const u_int32_t optional_offset = + offsetof(struct sccp_connection_request, optional_start); + static const u_int32_t called_offset = + offsetof(struct sccp_connection_request, variable_called); + + struct sccp_data_callback *cb; + struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data; + struct sccp_address called; + struct sccp_connection *connection; + struct sccp_optional_data optional_data; + + /* header check */ + if (msgb_l2len(msgb) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + /* copy out the calling and called address. Add the offset */ + if (copy_address(&called, called_offset + req->variable_called, msgb) != 0) + return -1; + + if (check_address(&called) != 0) { + DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n", + *(u_int8_t *)&called.address, called.ssn); + return -1; + } + + cb = _find_ssn(called.ssn); + if (!cb || !cb->accept_cb) { + DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", called.ssn); + return -1; + } + + /* check if the system wants this connection */ + connection = talloc_zero(tall_sccp_ctx, struct sccp_connection); + if (!connection) { + DEBUGP(DSCCP, "Allocation failed\n"); + return -1; + } + + /* + * sanity checks: + * - Is the source_local_reference in any other connection? + * then will call accept, assign a "destination" local reference + * and send a connection confirm, otherwise we will send a refuseed + * one.... + */ + if (destination_local_reference_is_free(&req->source_local_reference) != 0) { + DEBUGP(DSCCP, "Need to reject connection with existing reference\n"); + _sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); + talloc_free(connection); + return -1; + } + + connection->incoming = 1; + connection->destination_local_reference = req->source_local_reference; + + /* + * parse optional data. + */ + memset(&optional_data, 0, sizeof(optional_data)); + if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) { + DEBUGP(DSCCP, "parsing of optional data failed.\n"); + talloc_free(connection); + return -1; + } + + if (cb->accept_cb(connection, cb->accept_context) != 0) { + _sccp_send_refuse(req, SCCP_REFUSAL_END_USER_ORIGINATED); + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); + talloc_free(connection); + return 0; + } + + + llist_add_tail(&connection->list, &sccp_connections); + + if (_sccp_send_connection_confirm(connection) != 0) { + DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n"); + + _sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); + llist_del(&connection->list); + talloc_free(connection); + + return -1; + } + + /* + * If we have data let us forward things. + */ + if (optional_data.data_len != 0 && connection->data_cb) { + msgb->l3h = &msgb->l2h[optional_data.data_start]; + connection->data_cb(connection, msgb, optional_data.data_len); + } + + return 0; +} + +/* Handle the release confirmed */ +static int _sccp_handle_connection_release_complete(struct msgb *data) +{ + static int header_size = sizeof(struct sccp_connection_release_complete); + + struct sccp_connection_release_complete *cmpl; + struct sccp_connection *conn; + + /* header check */ + if (msgb_l2len(data) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(data), header_size); + return -1; + } + + cmpl = (struct sccp_connection_release_complete *) data->l2h; + + /* find the connection */ + llist_for_each_entry(conn, &sccp_connections, list) { + if (conn->data_cb + && memcmp(&conn->source_local_reference, + &cmpl->destination_local_reference, + sizeof(conn->source_local_reference)) == 0 + && memcmp(&conn->destination_local_reference, + &cmpl->source_local_reference, + sizeof(conn->destination_local_reference)) == 0) { + goto found; + } + } + + + DEBUGP(DSCCP, "Release complete of unknown connection\n"); + return -1; + +found: + llist_del(&conn->list); + _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE_COMPLETE); + return 0; +} + +/* Handle the Data Form 1 message */ +static int _sccp_handle_connection_dt1(struct msgb *data) +{ + static int variable_offset = offsetof(struct sccp_data_form1, variable_start); + static int header_size = sizeof(struct sccp_data_form1); + + struct sccp_data_form1 *dt1 = (struct sccp_data_form1 *)data->l2h; + struct sccp_connection *conn; + int size; + + /* we don't have enough size for the struct */ + if (msgb_l2len(data) < header_size) { + DEBUGP(DSCCP, "msgb > header_size %u %u\n", + msgb_l2len(data), header_size); + return -1; + } + + if (dt1->segmenting != 0) { + DEBUGP(DSCCP, "This packet has segmenting, not supported: %d\n", dt1->segmenting); + return -1; + } + + /* lookup if we have a connection with the given reference */ + llist_for_each_entry(conn, &sccp_connections, list) { + if (conn->data_cb + && memcmp(&conn->source_local_reference, + &dt1->destination_local_reference, + sizeof(conn->source_local_reference)) == 0) { + + /* some more size checks in here */ + if (msgb_l2len(data) < variable_offset + dt1->variable_start + 1) { + DEBUGP(DSCCP, "Not enough space for variable start: %u %u\n", + msgb_l2len(data), dt1->variable_start); + return -1; + } + + size = data->l2h[variable_offset + dt1->variable_start]; + data->l3h = &data->l2h[dt1->variable_start + variable_offset + 1]; + + if (msgb_l3len(data) < size) { + DEBUGP(DSCCP, "Not enough room for the payload: %u %u\n", + msgb_l3len(data), size); + return -1; + } + + conn->data_cb(conn, data, size); + return 0; + } + } + + DEBUGP(DSCCP, "No connection found for dt1 data\n"); + return -1; +} + +/* confirm a connection release */ +static int _sccp_send_connection_release_complete(struct sccp_connection *connection) +{ + struct msgb *msgb; + struct sccp_connection_release_complete *rlc; + int ret; + + msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp rlc"); + msgb->l2h = &msgb->data[0]; + + rlc = (struct sccp_connection_release_complete *) msgb_put(msgb, sizeof(*rlc)); + rlc->type = SCCP_MSG_TYPE_RLC; + memcpy(&rlc->destination_local_reference, + &connection->destination_local_reference, sizeof(struct sccp_source_reference)); + memcpy(&rlc->source_local_reference, + &connection->source_local_reference, sizeof(struct sccp_source_reference)); + + ret = _send_msg(msgb); + msgb_free(msgb); + + /* + * Remove from the list of active connections and set the state. User code + * should now free the entry. + */ + llist_del(&connection->list); + _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_RELEASE_COMPLETE); + + return ret; +} + +/* connection released, send a released confirm */ +static int _sccp_handle_connection_released(struct msgb *data) +{ + static int header_size = sizeof(struct sccp_connection_released); + static int optional_offset = offsetof(struct sccp_connection_released, optional_start); + + struct sccp_optional_data optional_data; + struct sccp_connection_released *rls = (struct sccp_connection_released *)data->l2h; + struct sccp_connection *conn; + + /* we don't have enough size for the struct */ + if (msgb_l2len(data) < header_size) { + DEBUGP(DSCCP, "msgb > header_size %u %u\n", + msgb_l2len(data), header_size); + return -1; + } + + /* lookup if we have a connection with the given reference */ + llist_for_each_entry(conn, &sccp_connections, list) { + if (conn->data_cb + && memcmp(&conn->source_local_reference, + &rls->destination_local_reference, + sizeof(conn->source_local_reference)) == 0 + && memcmp(&conn->destination_local_reference, + &rls->source_local_reference, + sizeof(conn->destination_local_reference)) == 0) { + goto found; + } + } + + + DEBUGP(DSCCP, "Unknown connection was released.\n"); + return -1; + + /* we have found a connection */ +found: + memset(&optional_data, 0, sizeof(optional_data)); + if (_sccp_parse_optional_data(optional_offset + rls->optional_start, data, &optional_data) != 0) { + DEBUGP(DSCCP, "parsing of optional data failed.\n"); + return -1; + } + + /* optional data */ + if (optional_data.data_len != 0 && conn->data_cb) { + data->l3h = &data->l2h[optional_data.data_start]; + conn->data_cb(conn, data, optional_data.data_len); + } + + /* generate a response */ + if (_sccp_send_connection_release_complete(conn) != 0) { + DEBUGP(DSCCP, "Sending release confirmed failed\n"); + return -1; + } + + return 0; +} + +static int _sccp_handle_connection_refused(struct msgb *msgb) +{ + static const u_int32_t header_size = + sizeof(struct sccp_connection_refused); + static int optional_offset = offsetof(struct sccp_connection_refused, optional_start); + + struct sccp_optional_data optional_data; + struct sccp_connection *conn; + struct sccp_connection_refused *ref; + + /* header check */ + if (msgb_l2len(msgb) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + ref = (struct sccp_connection_refused *) msgb->l2h; + + /* lookup if we have a connection with the given reference */ + llist_for_each_entry(conn, &sccp_connections, list) { + if (conn->incoming == 0 && conn->data_cb + && memcmp(&conn->source_local_reference, + &ref->destination_local_reference, + sizeof(conn->source_local_reference)) == 0) { + goto found; + } + } + + DEBUGP(DSCCP, "Refused but no connection found\n"); + return -1; + +found: + memset(&optional_data, 0, sizeof(optional_data)); + if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) { + DEBUGP(DSCCP, "parsing of optional data failed.\n"); + return -1; + } + + /* optional data */ + if (optional_data.data_len != 0 && conn->data_cb) { + msgb->l3h = &msgb->l2h[optional_data.data_start]; + conn->data_cb(conn, msgb, optional_data.data_len); + } + + + llist_del(&conn->list); + _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_REFUSED); + return 0; +} + +static int _sccp_handle_connection_confirm(struct msgb *msgb) +{ + static u_int32_t header_size = + sizeof(struct sccp_connection_confirm); + static const u_int32_t optional_offset = + offsetof(struct sccp_connection_confirm, optional_start); + + struct sccp_optional_data optional_data; + struct sccp_connection *conn; + struct sccp_connection_confirm *con; + + /* header check */ + if (msgb_l2len(msgb) < header_size) { + DEBUGP(DSCCP, "msgb < header_size %u %u\n", + msgb_l2len(msgb), header_size); + return -1; + } + + con = (struct sccp_connection_confirm *) msgb->l2h; + + /* lookup if we have a connection with the given reference */ + llist_for_each_entry(conn, &sccp_connections, list) { + if (conn->incoming == 0 && conn->data_cb + && memcmp(&conn->source_local_reference, + &con->destination_local_reference, + sizeof(conn->source_local_reference)) == 0) { + goto found; + } + } + + DEBUGP(DSCCP, "Confirmed but no connection found\n"); + return -1; + +found: + /* copy the addresses of the connection */ + conn->destination_local_reference = con->source_local_reference; + _sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_ESTABLISHED); + + memset(&optional_data, 0, sizeof(optional_data)); + if (_sccp_parse_optional_data(optional_offset + con->optional_start, msgb, &optional_data) != 0) { + DEBUGP(DSCCP, "parsing of optional data failed.\n"); + return -1; + } + + /* optional data */ + if (optional_data.data_len != 0 && conn->data_cb) { + msgb->l3h = &msgb->l2h[optional_data.data_start]; + conn->data_cb(conn, msgb, optional_data.data_len); + } + + return 0; +} + + +int sccp_system_init(int (*outgoing)(struct msgb *data, void *ctx), void *ctx) +{ + sccp_system.write_data = outgoing; + sccp_system.write_context = ctx; + + return 0; +} + +/* oh my god a real SCCP packet. need to dispatch it now */ +int sccp_system_incoming(struct msgb *msgb) +{ + if (msgb_l2len(msgb) < 1 ) { + DEBUGP(DSCCP, "Too short packet\n"); + return -1; + } + + int type = msgb->l2h[0]; + + switch(type) { + case SCCP_MSG_TYPE_CR: + return _sccp_handle_connection_request(msgb); + break; + case SCCP_MSG_TYPE_RLSD: + return _sccp_handle_connection_released(msgb); + break; + case SCCP_MSG_TYPE_CREF: + return _sccp_handle_connection_refused(msgb); + break; + case SCCP_MSG_TYPE_CC: + return _sccp_handle_connection_confirm(msgb); + break; + case SCCP_MSG_TYPE_RLC: + return _sccp_handle_connection_release_complete(msgb); + break; + case SCCP_MSG_TYPE_DT1: + return _sccp_handle_connection_dt1(msgb); + break; + case SCCP_MSG_TYPE_UDT: + return _sccp_handle_read(msgb); + break; + default: + DEBUGP(DSCCP, "unimplemented msg type: %d\n", type); + }; + + return -1; +} + +/* create a packet from the data */ +int sccp_connection_write(struct sccp_connection *connection, struct msgb *data) +{ + if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM + || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { + DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n", + connection, connection->connection_state); + return -1; + } + + return _sccp_send_connection_data(connection, data); +} + +/* send a connection release and wait for the connection released */ +int sccp_connection_close(struct sccp_connection *connection, int cause) +{ + if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM + || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { + DEBUGPC(DSCCP, "Can not close the connection. It was never opened: %p %d\n", + connection, connection->connection_state); + return -1; + } + + return _sccp_send_connection_released(connection, cause); +} + +int sccp_connection_free(struct sccp_connection *connection) +{ + if (connection->connection_state > SCCP_CONNECTION_STATE_NONE + && connection->connection_state < SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { + DEBUGP(DSCCP, "The connection needs to be released before it is freed"); + return -1; + } + + talloc_free(connection); + return 0; +} + +struct sccp_connection *sccp_connection_socket(void) +{ + return talloc_zero(tall_sccp_ctx, struct sccp_connection); +} + +int sccp_connection_connect(struct sccp_connection *conn, + const struct sockaddr_sccp *local, + struct msgb *data) +{ + return _sccp_send_connection_request(conn, local, data); +} + +int sccp_connection_set_incoming(const struct sockaddr_sccp *sock, + int (*accept_cb)(struct sccp_connection *, void *), void *context) +{ + struct sccp_data_callback *cb; + + if (!sock) + return -2; + + cb = _find_ssn(sock->sccp_ssn); + if (!cb) + return -1; + + cb->accept_cb = accept_cb; + cb->accept_context = context; + return 0; +} + +int sccp_write(struct msgb *data, const struct sockaddr_sccp *in, + const struct sockaddr_sccp *out, int class) +{ + return _sccp_send_data(class, in, out, data); +} + +int sccp_set_read(const struct sockaddr_sccp *sock, + int (*read_cb)(struct msgb *, unsigned int, void *), void *context) +{ + struct sccp_data_callback *cb; + + if (!sock) + return -2; + + cb = _find_ssn(sock->sccp_ssn); + if (!cb) + return -1; + + cb->read_cb = read_cb; + cb->read_context = context; + return 0; +} + +static_assert(sizeof(struct sccp_source_reference) <= sizeof(u_int32_t), enough_space); + +u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref) +{ + u_int32_t src_ref = 0; + memcpy(&src_ref, ref, sizeof(*ref)); + return src_ref; +} + +struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_ref) +{ + struct sccp_source_reference ref; + memcpy(&ref, &int_ref, sizeof(ref)); + return ref; +} + +static __attribute__((constructor)) void on_dso_load(void) +{ + tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp"); +} + +static __attribute__((destructor)) void on_dso_unload(void) +{ + talloc_report_full(tall_sccp_ctx, stderr); +} diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 2d4e81c75..f40105fbf 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -1 +1 @@ -SUBDIRS = debug timer sms gsm0408 db channel +SUBDIRS = debug timer sms gsm0408 db channel sccp diff --git a/openbsc/tests/sccp/Makefile.am b/openbsc/tests/sccp/Makefile.am new file mode 100644 index 000000000..5a275fc2b --- /dev/null +++ b/openbsc/tests/sccp/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS=-Wall -ggdb3 + +noinst_PROGRAMS = sccp_test + +sccp_test_SOURCES = sccp_test.c +sccp_test_LDADD = $(top_builddir)/src/libsccp.a $(top_builddir)/src/libbsc.a + diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c new file mode 100644 index 000000000..d3b334f3b --- /dev/null +++ b/openbsc/tests/sccp/sccp_test.c @@ -0,0 +1,723 @@ +/* + * SCCP testing code + * + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include + +#include + +#include +#include +#include + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +/* BSC -> MSC */ +static const u_int8_t bssmap_reset[] = { + 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, + 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, + 0x01, 0x20, +}; + +/* MSC -> BSC reset ack */ +static const u_int8_t bssmap_reset_ack[] = { + 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, + 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, + 0x00, 0x01, 0x31, +}; + +/* MSC -> BSC paging, connection less */ +static const u_int8_t bssmap_paging[] = { + 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, + 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10, + 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, + 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06, +}; + +/* MSC -> BSC paging, UDT without PC */ +static const u_int8_t bssmap_udt[] = { + 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, + 0x02, 0x42, 0xfe, 0x10, 0x00, 0x0e, 0x52, 0x08, + 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, 0x31, 0x97, + 0x61, 0x1a, 0x01, 0x06, +}; + +/* BSC -> MSC connection open */ +static const u_int8_t bssmap_cr[] = { + 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02, + 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, + 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3, + 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33, + 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, + 0x31, 0x97, 0x61, 0x00 +}; + +/* MSC -> BSC connection confirm */ +static const u_int8_t bssmap_cc[] = { + 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, +}; + +/* MSC -> BSC DTAP + * + * we fake a bit and make it BSC -> MSC... so the + * payload does not make any sense.. + */ +static const u_int8_t bssmap_dtap[] = { + 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x0f, 0x01, 0x00, 0x0c, + 0x03, 0x05, 0x5c, 0x08, 0x11, 0x81, 0x33, 0x66, 0x02, 0x13, + 0x45, 0xf4, +}; + +/* MSC -> BSC clear command */ +static const u_int8_t bssmap_clear[] = { + 0x06, 0x00, 0x00, 0x03, 0x00, 0x01, 0x06, 0x00, 0x04, 0x20, + 0x04, 0x01, 0x09, +}; + +/* MSC -> BSC released */ +static const u_int8_t bssmap_released[] = { + 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f, + 0x02, 0x23, 0x42, 0x00, +}; + +/* BSC -> MSC released */ +static const u_int8_t bssmap_release_complete[] = { + 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03 +}; + +struct test_data { + int length; + const u_int8_t *data; + int payload_start; + int payload_length; + u_int8_t first_byte; + + /* in case it should trigger a sccp response */ + int write; + const u_int8_t *response; + int response_length; +}; + +static const struct test_data test_data[] = { + { + .length = ARRAY_SIZE(bssmap_reset), + .data = &bssmap_reset[0], + .payload_start = 12, + .payload_length = ARRAY_SIZE(bssmap_reset) - 12, + .first_byte = 0x0, + }, + { + .length = ARRAY_SIZE(bssmap_reset_ack), + .data = &bssmap_reset_ack[0], + .payload_start = 16, + .payload_length = ARRAY_SIZE(bssmap_reset_ack) - 16, + .first_byte = 0x0, + }, + { + .length = ARRAY_SIZE(bssmap_paging), + .data = &bssmap_paging[0], + .payload_start = 16, + .payload_length = ARRAY_SIZE(bssmap_paging) - 16, + .first_byte = 0x0, + }, + { + .length = ARRAY_SIZE(bssmap_cr), + .data = &bssmap_cr[0], + .payload_start = 12, + /* 0x00 is end of optional data, subtract this byte */ + .payload_length = 31, + .first_byte = 0x0, + + /* the connection request should trigger a connection confirm */ + .write = 1, + .response = &bssmap_cc[0], + .response_length= ARRAY_SIZE(bssmap_cc), + }, + { + .length = ARRAY_SIZE(bssmap_dtap), + .data = &bssmap_dtap[0], + .payload_start = 7, + .payload_length = 15, + .first_byte = 0x01, + }, + { + .length = ARRAY_SIZE(bssmap_clear), + .data = &bssmap_clear[0], + .payload_start = 7, + .payload_length = 6, + .first_byte = 0x00, + }, + { + .length = ARRAY_SIZE(bssmap_released), + .data = &bssmap_released[0], + .payload_length = 2, + .payload_start = 11, + .first_byte = 0x23, + + .write = 1, + .response = &bssmap_release_complete[0], + .response_length= ARRAY_SIZE(bssmap_release_complete), + }, +}; + +/* we will send UDTs and verify they look like this */ +static const struct test_data send_data[] = { + { + .length = ARRAY_SIZE(bssmap_udt), + .data = &bssmap_udt[0], + .payload_start = 12, + .payload_length = ARRAY_SIZE(bssmap_udt) - 12, + .first_byte = 0x0, + }, + { + .length = ARRAY_SIZE(bssmap_reset), + .data = &bssmap_reset[0], + .payload_start = 12, + .payload_length = ARRAY_SIZE(bssmap_reset) - 12, + .first_byte = 0x0, + }, +}; + +struct connection_test { + /* should the connection be refused? */ + int refuse; + + int with_data; + + /* on which side to close the connection? */ + int close_side; + int close_cause; +}; + +/* sccp connection handling we want to test */ +static const struct connection_test connection_tests[] = { + { + .refuse = 1, + }, + { + .refuse = 1, + .with_data = 1, + }, + { + .refuse = 0, + .close_side = 0, + .close_cause = 5, + }, + { + .refuse = 0, + .close_side = 0, + .close_cause = 5, + .with_data = 1, + }, + { + .refuse = 0, + .close_side = 1, + .close_cause = 5, + }, + { + .refuse = 0, + .close_side = 1, + .close_cause = 5, + .with_data = 1, + }, +}; + +/* testing procedure: + * - we will use sccp_write and see what will be set in the + * outgoing callback + * - we will call sccp_system_incoming and see which calls + * are made. And then compare it to the ones we expect. We + * want the payload to arrive, or callbacks to be called. + * - we will use sccp_connection_socket and sccp_connection_write + * and verify state handling of connections + */ + +static int current_test; + +/* + * test state... + */ +static int called = 0; +static int matched = 0; +static int write_called = 0; + +#define FAIL(x, args...) printf("FAILURE in %s:%d: " x, __FILE__, __LINE__, ## args) + +/* + * writing these packets and expecting a result + */ +int sccp_read_cb(struct msgb *data, unsigned len, void *context) +{ + u_int16_t payload_length = test_data[current_test].payload_length; + const u_int8_t *got, *wanted; + int i; + + called = 1; + + if (msgb_l3len(data) < len) { + /* this should never be reached */ + FAIL("Something horrible happened.. invalid packet..\n"); + exit(-1); + } + + if (len == 0 || len != payload_length) { + FAIL("length mismatch: got: %d wanted: %d\n", msgb_l3len(data), payload_length); + return -1; + } + + if (data->l3h[0] != test_data[current_test].first_byte) { + FAIL("The first bytes of l3 do not match: 0x%x 0x%x\n", + data->l3h[0], test_data[current_test].first_byte); + return -1; + } + + got = &data->l3h[0]; + wanted = test_data[current_test].data + test_data[current_test].payload_start; + + for (i = 0; i < len; ++i) { + if (got[i] != wanted[i]) { + FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", + got[i], wanted[i], i); + return -1; + } + } + + matched = 1; + return 0; +} + +int sccp_write_cb(struct msgb *data, void *ctx) +{ + int i = 0; + const u_int8_t *got, *wanted; + + if (test_data[current_test].response == NULL) { + FAIL("Didn't expect write callback\n"); + return -1; + } else if (test_data[current_test].response_length != msgb_l2len(data)) { + FAIL("Size does not match. Got: %d Wanted: %d\n", + msgb_l2len(data), test_data[current_test].response_length); + } + + got = &data->l2h[0]; + wanted = test_data[current_test].response; + + for (i = 0; i < msgb_l2len(data); ++i) { + if (got[i] != wanted[i]) { + FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", + got[i], wanted[i], i); + return -1; + } + } + + write_called = 1; + return 0; +} + +void sccp_c_read(struct sccp_connection *connection, struct msgb *msgb, unsigned int len) +{ + sccp_read_cb(msgb, len, connection->data_ctx); +} + +void sccp_c_state(struct sccp_connection *connection, int old_state) +{ + if (connection->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) + sccp_connection_free(connection); +} + +int sccp_accept_cb(struct sccp_connection *connection, void *user_data) +{ + called = 1; + unsigned int ref = 0; + ref |= connection->destination_local_reference.octet1 << 24; + ref |= connection->destination_local_reference.octet2 << 16; + ref |= connection->destination_local_reference.octet3 << 8; + ref = ntohl(ref); + + connection->data_cb = sccp_c_read; + connection->state_cb = sccp_c_state; + + /* accept this */ + return 0; +} + +static int sccp_udt_write_cb(struct msgb *data, void *context) +{ + const u_int8_t *got, *wanted; + int i; + + write_called = 1; + + if (send_data[current_test].length != msgb_l2len(data)) { + FAIL("Size does not match. Got: %d Wanted: %d\n", + msgb_l2len(data), send_data[current_test].length); + return -1; + } + + got = &data->l2h[0]; + wanted = send_data[current_test].data; + + for (i = 0; i < msgb_l2len(data); ++i) { + if (got[i] != wanted[i]) { + FAIL("Failed to compare byte. Got: 0x%x Wanted: 0x%x at %d\n", + got[i], wanted[i], i); + return -1; + } + } + + matched = 1; + return 0; +} + +static void test_sccp_system(void) +{ + sccp_system_init(sccp_write_cb, NULL); + sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); + sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); + + for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { + unsigned int length = test_data[current_test].length; + struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); + msg->l2h = msgb_put(msg, length); + memcpy(msg->l2h, test_data[current_test].data, length); + + called = matched = write_called = 0; + printf("Testing packet: %d\n", current_test); + sccp_system_incoming(msg); + + if (!called || !matched || (test_data[current_test].write != write_called)) + FAIL("current test: %d called: %d matched: %d write: %d\n", + current_test, called, matched, write_called); + + msgb_free(msg); + } +} + +/* test sending of udt */ +static void test_sccp_send_udt(void) +{ + sccp_system_init(sccp_udt_write_cb, NULL); + sccp_set_read(NULL, NULL, NULL); + sccp_connection_set_incoming(NULL, NULL, NULL); + + for (current_test = 0; current_test < ARRAY_SIZE(send_data); ++current_test) { + const struct test_data *test = &send_data[current_test]; + + struct msgb *msg = msgb_alloc(test->payload_length, __func__); + msg->l3h = msgb_put(msg, test->payload_length); + memcpy(msg->l3h, test->data + test->payload_start, test->payload_length); + + matched = write_called = 0; + printf("Testing packet: %d\n", current_test); + sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); + + if (!matched || !write_called) + FAIL("current test: %d matched: %d write: %d\n", + current_test, matched, write_called); + + msgb_free(msg); + } +} + +/* send udt from one end to another */ +static unsigned int test_value = 0x2442; +static int sccp_udt_read(struct msgb *data, unsigned int len, void *context) +{ + unsigned int *val; + + if (len != 4) { + FAIL("Wrong size: %d\n", msgb_l3len(data)); + return -1; + } + + val = (unsigned int*)data->l3h; + matched = test_value == *val; + + return 0; +} + +static int sccp_write_loop(struct msgb *data, void *context) +{ + /* send it back to us */ + sccp_system_incoming(data); + return 0; +} + +static void test_sccp_udt_communication(void) +{ + struct msgb *data; + unsigned int *val; + + sccp_system_init(sccp_write_loop, NULL); + sccp_set_read(&sccp_ssn_bssap, sccp_udt_read, NULL); + sccp_connection_set_incoming(NULL, NULL, NULL); + + + data = msgb_alloc(4, "test data"); + data->l3h = &data->data[0]; + val = (unsigned int *)msgb_put(data, 4); + *val = test_value; + + matched = 0; + sccp_write(data, &sccp_ssn_bssap, &sccp_ssn_bssap, 0); + + if (!matched) + FAIL("Talking with us didn't work\n"); + + msgb_free(data); +} + + +/* connection testing... open, send, close */ +static const struct connection_test *current_con_test; +static struct sccp_connection *outgoing_con; +static struct sccp_connection *incoming_con; +static int outgoing_data, incoming_data, incoming_state, outgoing_state; + +static struct msgb *test_data1, *test_data2, *test_data3; + +static void sccp_conn_in_state(struct sccp_connection *conn, int old_state) +{ + printf("\tincome: %d -> %d\n", old_state, conn->connection_state); + if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { + if (conn == incoming_con) { + sccp_connection_free(conn); + incoming_con = NULL; + } + } +} + +static void sccp_conn_in_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) +{ + /* compare the data */ + ++incoming_data; + printf("\tincoming data: %d\n", len); + + /* compare the data */ + if (len != 4) { + FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); + return; + } + + if (incoming_data == 1) { + if (memcmp(msg->l3h, test_data1->l3h, len) != 0) { + FAIL("Comparing the data failed: %d\n", incoming_data); + incoming_state = 0; + printf("Got: %s\n", hexdump(msg->l3h, len)); + printf("Wanted: %s\n", hexdump(test_data1->l3h, len)); + + } + } else if (incoming_data == 2) { + if (memcmp(msg->l3h, test_data2->l3h, len) != 0) { + FAIL("Comparing the data failed: %d\n", incoming_data); + incoming_state = 0; + printf("Got: %s\n", hexdump(msg->l3h, len)); + printf("Wanted: %s\n", hexdump(test_data2->l3h, len)); + } + } + + /* sending out data */ + if (incoming_data == 2) { + printf("\tReturning data3\n"); + sccp_connection_write(conn, test_data3); + } +} + +static int sccp_conn_accept(struct sccp_connection *conn, void *ctx) +{ + printf("\taccept: %p\n", conn); + conn->state_cb = sccp_conn_in_state; + conn->data_cb = sccp_conn_in_data; + + if (current_con_test->refuse) + return -1; + + incoming_con = conn; + return 0; +} + +/* callbacks for the outgoing side */ +static void sccp_conn_out_state(struct sccp_connection *conn, int old_state) +{ + printf("\toutgoing: %p %d -> %d\n", conn, old_state, conn->connection_state); + + if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) { + if (conn == outgoing_con) { + sccp_connection_free(conn); + outgoing_con = NULL; + } + } +} + +static void sccp_conn_out_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len) +{ + ++outgoing_data; + printf("\toutgoing data: %p %d\n", conn, len); + + if (len != 4) + FAIL("Length of packet is wrong: %u %u\n", msgb_l3len(msg), len); + + if (outgoing_data == 1) { + if (memcmp(msg->l3h, test_data3->l3h, len) != 0) { + FAIL("Comparing the data failed\n"); + outgoing_state = 0; + } + } +} + +static void do_test_sccp_connection(const struct connection_test *test) +{ + int ret; + + current_con_test = test; + outgoing_con = incoming_con = 0; + + outgoing_con = sccp_connection_socket(); + if (!outgoing_con) { + FAIL("Connection is NULL\n"); + return; + } + + outgoing_con->state_cb = sccp_conn_out_state; + outgoing_con->data_cb = sccp_conn_out_data; + outgoing_data = incoming_data = 0; + incoming_state = outgoing_state = 1; + + /* start testing */ + if (test->with_data) { + if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, test_data1) != 0) + FAIL("Binding failed\n"); + } else { + ++incoming_data; + if (sccp_connection_connect(outgoing_con, &sccp_ssn_bssap, NULL) != 0) + FAIL("Binding failed\n"); + } + + if (test->refuse) { + if (outgoing_con) + FAIL("Outgoing connection should have been refused.\n"); + } else { + if (!incoming_con) + FAIL("Creating incoming didn't work.\n"); + + printf("\tWriting test data2\n"); + sccp_connection_write(outgoing_con, test_data2); + + /* closing connection */ + if (test->close_side == 0) + ret = sccp_connection_close(outgoing_con, 0); + else + ret = sccp_connection_close(incoming_con, 0); + + if (ret != 0) + FAIL("Closing the connection failed\n"); + } + + /* outgoing should be gone now */ + if (outgoing_con) + FAIL("Outgoing connection was not properly closed\n"); + + if (incoming_con) + FAIL("Incoming connection was not propery closed.\n"); + + if (test->refuse == 0) { + if (outgoing_data != 1 || incoming_data != 2) { + FAIL("Data sending failed: %d/%d %d/%d\n", + outgoing_data, 1, + incoming_data, 2); + } + } + + if (!incoming_state || !outgoing_state) + FAIL("Failure with the state transition. %d %d\n", + outgoing_state, incoming_state); +} + +static void test_sccp_connection(void) +{ + sccp_system_init(sccp_write_loop, NULL); + sccp_set_read(NULL, NULL, NULL); + sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_conn_accept, NULL); + + test_data1 = msgb_alloc(4, "data1"); + test_data1->l3h = msgb_put(test_data1, 4); + *((unsigned int*)test_data1->l3h) = 0x23421122; + + test_data2 = msgb_alloc(4, "data2"); + test_data2->l3h = msgb_put(test_data2, 4); + *((unsigned int*)test_data2->l3h) = 0x42232211; + + test_data3 = msgb_alloc(4, "data3"); + test_data3->l3h = msgb_put(test_data3, 4); + *((unsigned int*)test_data3->l3h) = 0x2323ff55; + + + for (current_test = 0; current_test < ARRAY_SIZE(connection_tests); ++current_test) { + printf("Testing %d refuse: %d with_data: %d\n", + current_test, connection_tests[current_test].refuse, + connection_tests[current_test].with_data); + do_test_sccp_connection(&connection_tests[current_test]); + } + + msgb_free(test_data1); + msgb_free(test_data2); + msgb_free(test_data3); +} + +/* invalid input */ +static void test_sccp_system_crash(void) +{ + printf("trying to provoke a crash with invalid input\n"); + sccp_set_read(&sccp_ssn_bssap, sccp_read_cb, NULL); + sccp_connection_set_incoming(&sccp_ssn_bssap, sccp_accept_cb, NULL); + + for (current_test = 0; current_test < ARRAY_SIZE(test_data); ++current_test) { + int original_length = test_data[current_test].length; + int length = original_length + 2; + int i; + + printf("Testing packet: %d\n", current_test); + + for (i = length; i >= 0; --i) { + unsigned int length = MIN(test_data[current_test].length, i); + struct msgb *msg = msgb_alloc_headroom(length + 2, 2, __func__); + msg->l2h = msgb_put(msg, length); + memcpy(msg->l2h, test_data[current_test].data, length); + sccp_system_incoming(msg); + msgb_free(msg); + } + } + + printf("survived\n"); +} + + +int main(int argc, char **argv) +{ + test_sccp_system(); + test_sccp_send_udt(); + test_sccp_udt_communication(); + test_sccp_connection(); + test_sccp_system_crash(); + return 0; +} -- cgit v1.2.3 From 3b9516e0d86b2008ce2b3ccaff25cd804e6bc84c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 22:11:28 +0100 Subject: [sccp] Implement sending the Inactivity Test on a connection.. Currently this will send a dummy inactivity test message, there is currently no parsing or API to receive the messages. The sequencing and credit entries are empty as sequencing is currently not used at all. The test is currently limited to send the message and see if the application is crashing or not. --- openbsc/include/sccp/sccp.h | 1 + openbsc/include/sccp/sccp_types.h | 11 ++++++++++ openbsc/src/sccp/sccp.c | 42 +++++++++++++++++++++++++++++++++++++++ openbsc/tests/sccp/sccp_test.c | 1 + 4 files changed, 55 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/sccp/sccp.h b/openbsc/include/sccp/sccp.h index 8ee4b680b..3ad568c0b 100644 --- a/openbsc/include/sccp/sccp.h +++ b/openbsc/include/sccp/sccp.h @@ -101,6 +101,7 @@ int sccp_system_incoming(struct msgb *data); * Send data on an existing connection */ int sccp_connection_write(struct sccp_connection *connection, struct msgb *data); +int sccp_connection_send_it(struct sccp_connection *connection); int sccp_connection_close(struct sccp_connection *connection, int cause); int sccp_connection_free(struct sccp_connection *connection); diff --git a/openbsc/include/sccp/sccp_types.h b/openbsc/include/sccp/sccp_types.h index c6b11820c..9310a6bf0 100644 --- a/openbsc/include/sccp/sccp_types.h +++ b/openbsc/include/sccp/sccp_types.h @@ -380,4 +380,15 @@ struct sccp_data_unitdata { u_int8_t data[0]; } __attribute__((packed)); +struct sccp_data_it { + /* mandantory */ + u_int8_t type; + struct sccp_source_reference destination_local_reference; + struct sccp_source_reference source_local_reference; + u_int8_t proto_class; + + u_int8_t sequencing[2]; + u_int8_t credit; +} __attribute__((packed)); + #endif diff --git a/openbsc/src/sccp/sccp.c b/openbsc/src/sccp/sccp.c index 8b111b2f5..522afcf7a 100644 --- a/openbsc/src/sccp/sccp.c +++ b/openbsc/src/sccp/sccp.c @@ -535,6 +535,31 @@ static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb return ret; } +static int _sccp_send_connection_it(struct sccp_connection *conn) +{ + struct msgb *msgb; + struct sccp_data_it *it; + int ret; + + msgb = msgb_alloc_headroom(SCCP_MSG_SIZE, + SCCP_MSG_HEADROOM, "sccp it"); + msgb->l2h = &msgb->data[0]; + it = (struct sccp_data_it *) msgb_put(msgb, sizeof(*it)); + it->type = SCCP_MSG_TYPE_IT; + memcpy(&it->destination_local_reference, &conn->destination_local_reference, + sizeof(struct sccp_source_reference)); + memcpy(&it->source_local_reference, &conn->source_local_reference, + sizeof(struct sccp_source_reference)); + + it->proto_class = 0x2; + it->sequencing[0] = it->sequencing[1] = 0; + it->credit = 0; + + ret = _send_msg(msgb); + msgb_free(msgb); + return ret; +} + static int _sccp_send_connection_released(struct sccp_connection *conn, int cause) { struct msgb *msg; @@ -1025,6 +1050,23 @@ int sccp_connection_write(struct sccp_connection *connection, struct msgb *data) return _sccp_send_connection_data(connection, data); } +/* + * Send a Inactivity Test message. The owner of the connection + * should start a timer and call this method regularily. Calling + * this every 60 seconds should be good enough. + */ +int sccp_connection_send_it(struct sccp_connection *connection) +{ + if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM + || connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) { + DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n", + connection, connection->connection_state); + return -1; + } + + return _sccp_send_connection_it(connection); +} + /* send a connection release and wait for the connection released */ int sccp_connection_close(struct sccp_connection *connection, int cause) { diff --git a/openbsc/tests/sccp/sccp_test.c b/openbsc/tests/sccp/sccp_test.c index d3b334f3b..bd28ed179 100644 --- a/openbsc/tests/sccp/sccp_test.c +++ b/openbsc/tests/sccp/sccp_test.c @@ -622,6 +622,7 @@ static void do_test_sccp_connection(const struct connection_test *test) printf("\tWriting test data2\n"); sccp_connection_write(outgoing_con, test_data2); + sccp_connection_send_it(outgoing_con); /* closing connection */ if (test->close_side == 0) -- cgit v1.2.3 From f67945f0047d62ca546afbd74def30adfc9e2f89 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 9 Oct 2009 07:08:11 +0200 Subject: [mgcp] Add a simple mgcp gateway used for the BSC The python script is a simple call-agent driving the client. Currently it is sending a AuditEndpoint message and is printing the result. The bsc_mgcp.c is a standalone process that will implement a MGCP Gateway for the MSC. On call handling the Call-Agent will ask the Gateway to "CreateConnection" and then this gateway needs to communicate with OpenBSC. Currently CreateConnection,ModifiyConnection,DeleteConnection and Endpoint auditing is implemented. [mgcp] Send RSIP on start and on first receive of any message Ignore the first request and send a RSIP. We do that because we might tunnel UDP through some other things and have no direct way to connect to the call-agent. Also the transaction is not checked and we ignore the response from the call-agent, actually we print the '200 ' or any other value as unhandled... [mgcp] Print the MGCP command next to the response code This allows to see which commands were sent by the server mgcp: Terminate it with a new line [mgcp] Make number of endpoints static... For now this is fixed to the number of endpoints as of the GSM specification... [mgcp] The endpoint names seem to be base 16... use strtoul to parse Use strtoul to parse the base 16 number from the mgw string. [mgcp] Log the endpoints as hex numbers... [mgcp] Only send the RSIP on the first incoming message.. Remove call_agent option (also remove the number from the getopt call). [mgcp] Start couting at 1 for the mgcp [mgcp] Slight attempt to improve the grammar of the strings [mgcp] Share validation routines between DLCX and MDCX [mgcp] Remove help for dead config options [mgcp] Specify a different IN addr in the SDP records In case of NAT traversal be able to listen on a given interface (like 127.0.0.1) but claim to receive data at the beginning of the tunnel. [mgcp] Fix the static copy of the SDP file WIP verify out factoring broken.. [mgcp] Introduce VTY to the mgcp for config file parsing... Parse the MGCP config file via the VTY framework. [mgcp] Handle SDP parameters through VTY.. Currently the payload type, name and rate can be specified in the config file. [mgcp] Add an option to bind all rtp ports early This can be useful for testing and in deployment to make sure no runtime resource limit can be hit. [mgcp] Add some API doc comment [mgcp] Convert the packets of the example server to ascii This will allow to easily patch the call id... to run the server in a loop and make it work with the mediagateway [mgcp] Assign CI_UNUSED... to be more obvious... [mgcp] Use DEBUG and not DEBUGPC and specially not printf Improve the logging a bit in the mgcp [mgcp] Change the fake server to change the call id This assume the call-agent will just increment the id as well.... this is true for our implementation [mgcp] Generate the transaction id dynamically.. This way wireshark will be more happy about it... [mgcp] Recognize responses from the network.. This is just recognizing the response code and then is doing nothing with it. Also change the script to generate response messages... [mgcp] Improve debug messages for CRCX/MDCX.. Log on which ports the media gateway is listening and where the other (server) gateway is located --- openbsc/contrib/mgcp_server.py | 54 ++ openbsc/include/openbsc/mgcp.h | 48 ++ openbsc/include/vty/command.h | 1 + openbsc/src/Makefile.am | 6 +- openbsc/src/bsc_mgcp.c | 1117 ++++++++++++++++++++++++++++++++++++++++ openbsc/src/mgcp.cfg | 17 + 6 files changed, 1242 insertions(+), 1 deletion(-) create mode 100755 openbsc/contrib/mgcp_server.py create mode 100644 openbsc/include/openbsc/mgcp.h create mode 100644 openbsc/src/bsc_mgcp.c create mode 100644 openbsc/src/mgcp.cfg (limited to 'openbsc') diff --git a/openbsc/contrib/mgcp_server.py b/openbsc/contrib/mgcp_server.py new file mode 100755 index 000000000..cf3ef3845 --- /dev/null +++ b/openbsc/contrib/mgcp_server.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# Simple server for mgcp... send audit, receive response.. + +import socket, time + +MGCP_GATEWAY_PORT = 2427 +MGCP_CALLAGENT_PORT = 2727 + +rsip_resp = """200 321321332\r\n""" +audit_packet = """AUEP %d 13@mgw MGCP 1.0\r\n""" +crcx_packet = """CRCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n""" +dlcx_packet = """DLCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\n""" +mdcx_packet = """MDCX %d 14@mgw MGCP 1.0\r\nC: 4a84ad5d25f\r\nI: %d\r\nL: p:20, a:GSM-EFR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 258696477 0 IN IP4 172.16.1.107\r\ns=-\r\nc=IN IP4 172.16.1.107\r\nt=0 0\r\nm=audio 4400 RTP/AVP 127\r\na=rtpmap:127 GSM-EFR/8000/1\r\na=ptime:20\r\na=recvonly\r\nm=image 4402 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n""" + +def hexdump(src, length=8): + """Recipe is from http://code.activestate.com/recipes/142812/""" + result = [] + digits = 4 if isinstance(src, unicode) else 2 + for i in xrange(0, len(src), length): + s = src[i:i+length] + hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s]) + text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s]) + result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) ) + return b'\n'.join(result) + +server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +server_socket.bind(("127.0.0.1", MGCP_CALLAGENT_PORT)) +server_socket.setblocking(0) + + +def send_receive(packet): + server_socket.sendto(packet, ("127.0.0.1", MGCP_GATEWAY_PORT)) + try: + data, addr = server_socket.recvfrom(4096) + print hexdump(data), addr + except socket.error: + pass + +def generate_tid(): + import random + return random.randint(0, 65123) + + + +i = 1 +while True: + send_receive(rsip_resp) + send_receive(audit_packet) + send_receive(crcx_packet % generate_tid() ) + send_receive(mdcx_packet % (generate_tid(), i)) + send_receive(dlcx_packet % (generate_tid(), i)) + i = i + 1 + + time.sleep(3) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h new file mode 100644 index 000000000..fa6224c12 --- /dev/null +++ b/openbsc/include/openbsc/mgcp.h @@ -0,0 +1,48 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ + +/* + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +unsigned int rtp_base_port = 4000; + +/** + * Calculate the RTP audio port for the given multiplex + * and the direction. This allows a semi static endpoint + * to port calculation removing the need for the BSC + * and the MediaGateway to communicate. + * + * Port usage explained: + * base + (multiplex * 2) + 0 == local port to wait for network packets + * base + (multiplex * 2) + 1 == local port for rtcp + * + * The above port will receive packets from the BTS that need + * to be patched and forwarded to the network. + * The above port will receive packets from the network that + * need to be patched and forwarded to the BTS. + * + * We assume to have a static BTS IP address so we can differentiate + * network and BTS. + * + */ +int rtp_calculate_port(int multiplex, int base) +{ + return base + (multiplex * 2); +} diff --git a/openbsc/include/vty/command.h b/openbsc/include/vty/command.h index 9daa2d62d..10a60add5 100644 --- a/openbsc/include/vty/command.h +++ b/openbsc/include/vty/command.h @@ -106,6 +106,7 @@ enum node_type { TRX_NODE, TS_NODE, SUBSCR_NODE, + MGCP_NODE, }; /* Node which has some commands and prompt string and configuration diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 79120081d..7651132b6 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -1,7 +1,8 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync +sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync \ + isdnsync bsc_mgcp noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h @@ -32,3 +33,6 @@ ipaccess_config_SOURCES = ipaccess-config.c ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT) isdnsync_SOURCES = isdnsync.c + +bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c +bsc_mgcp_LDADD = libvty.a diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c new file mode 100644 index 000000000..8b59b31cb --- /dev/null +++ b/openbsc/src/bsc_mgcp.c @@ -0,0 +1,1117 @@ +/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */ + +/* + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by on-waves.com + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* this is here for the vty... it will never be called */ +void subscr_put() { abort(); } +void vty_event() { } + +#define _GNU_SOURCE +#include + +#warning "Make use of the rtp proxy code" + +static int source_port = 2427; +static const char *local_ip = NULL; +static const char *source_addr = "0.0.0.0"; +static struct bsc_fd bfd; +static const unsigned int number_endpoints = 32 + 1; +static const char *bts_ip = NULL; +static struct in_addr bts_in; +static int first_request = 1; +static const char *audio_name = "GSM-EFR/8000"; +static int audio_payload = 97; +static int early_bind = 0; + +static char *config_file = "mgcp.cfg"; + +/* used by msgb and mgcp */ +void *tall_bsc_ctx = NULL; + +enum mgcp_connection_mode { + MGCP_CONN_NONE = 0, + MGCP_CONN_RECV_ONLY = 1, + MGCP_CONN_SEND_ONLY = 2, + MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, +}; + +#define CI_UNUSED 0 +static unsigned int last_call_id = 0; + +struct mgcp_endpoint { + int ci; + char *callid; + char *local_options; + int conn_mode; + + /* the local rtp port */ + int rtp_port; + + /* + * RTP mangling: + * - we get RTP and RTCP to us and need to forward to the BTS + * - we get RTP and RTCP from the BTS and forward to the network + */ + struct bsc_fd local_rtp; + struct bsc_fd local_rtcp; + + struct in_addr remote; + + /* in network byte order */ + int rtp, rtcp; + int bts_rtp, bts_rtcp; +}; + +static struct mgcp_endpoint *endpoints = NULL; +#define ENDPOINT_NUMBER(endp) abs(endp - endpoints) + +/** + * Macro for tokenizing MGCP messages and SDP in one go. + * + */ +#define MSG_TOKENIZE_START \ + line_start = 0; \ + for (i = 0; i < msgb_l3len(msg); ++i) { \ + /* we have a line end */ \ + if (msg->l3h[i] == '\n') { \ + /* skip the first line */ \ + if (line_start == 0) { \ + line_start = i + 1; \ + continue; \ + } \ + \ + /* check if we have a proper param */ \ + if (i - line_start == 1 && msg->l3h[line_start] == '\r') { \ + } else if (i - line_start > 2 \ + && islower(msg->l3h[line_start]) \ + && msg->l3h[line_start + 1] == '=') { \ + } else if (i - line_start < 3 \ + || msg->l3h[line_start + 1] != ':' \ + || msg->l3h[line_start + 2] != ' ') \ + goto error; \ + \ + msg->l3h[i] = '\0'; \ + if (msg->l3h[i-1] == '\r') \ + msg->l3h[i-1] = '\0'; + +#define MSG_TOKENIZE_END \ + line_start = i + 1; \ + } \ + } + + +struct mgcp_msg_ptr { + unsigned int start; + unsigned int length; +}; + +struct mgcp_request { + char *name; + void (*handle_request) (struct msgb *msg, struct sockaddr_in *source); + char *debug_name; +}; + +#define MGCP_REQUEST(NAME, REQ, DEBUG_NAME) \ + { .name = NAME, .handle_request = REQ, .debug_name = DEBUG_NAME }, + +static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source); +static void handle_create_con(struct msgb *msg, struct sockaddr_in *source); +static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source); +static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source); + +static int generate_call_id() +{ + int i; + + /* use the call id */ + ++last_call_id; + + /* handle wrap around */ + if (last_call_id == CI_UNUSED) + ++last_call_id; + + /* callstack can only be of size number_of_endpoints */ + /* verify that the call id is free, e.g. in case of overrun */ + for (i = 1; i < number_endpoints; ++i) + if (endpoints[i].ci == last_call_id) + return generate_call_id(); + + return last_call_id; +} + +/* FIXIME/TODO: need to have a list of pending transactions and check that */ +static unsigned int generate_transaction_id() +{ + return abs(rand()); +} + +static int _send(int fd, struct in_addr *addr, int port, char *buf, int len) +{ + struct sockaddr_in out; + out.sin_family = AF_INET; + out.sin_port = port; + memcpy(&out.sin_addr, addr, sizeof(*addr)); + + return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out)); +} + +/* + * There is data coming. We will have to figure out if it + * came from the BTS or the MediaGateway of the MSC. On top + * of that we need to figure out if it was RTP or RTCP. + * + * Currently we do not communicate with the BSC so we have + * no idea where the BTS is listening for RTP and need to + * do the classic routing trick. Wait for the first packet + * from the BTS and then go ahead. + */ +static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) +{ + char buf[4096]; + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct mgcp_endpoint *endp; + int rc, is_remote; + + endp = (struct mgcp_endpoint *) fd->data; + + rc = recvfrom(fd->fd, &buf, sizeof(buf), 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + DEBUGP(DMGCP, "Failed to receive message on: 0x%x\n", + ENDPOINT_NUMBER(endp)); + return -1; + } + + /* + * Figure out where to forward it to. This code assumes that we + * have received the Connection Modify and know who is a legitimate + * partner. According to the spec we could attempt to forward even + * after the Create Connection but we will not as we are not really + * able to tell if this is legitimate. + */ + #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." + is_remote = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0; + if (is_remote) { + if (endp->rtp == addr.sin_port) { + return _send(fd->fd, &bts_in, endp->bts_rtp, buf, rc); + } else if (endp->rtcp == addr.sin_port) { + return _send(fd->fd, &bts_in, endp->bts_rtcp, buf, rc); + } else { + DEBUGP(DMGCP, "Unknown remote port. Not able to forward on 0x%x port: %d\n", + ENDPOINT_NUMBER(endp), ntohs(addr.sin_port)); + } + + return -1; + } + + /* We have no idea who called us, maybe it is the BTS. */ + if (endp->bts_rtp == 0) { + /* it was the BTS... */ + if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { + if (fd == &endp->local_rtp) { + endp->bts_rtp = addr.sin_port; + endp->bts_rtcp = htons(ntohs(addr.sin_port) + 1); + } else { + endp->bts_rtp = htons(ntohs(addr.sin_port) - 1); + endp->bts_rtcp = addr.sin_port; + } + + DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp)); + } + } + + if (endp->bts_rtp == 0 || endp->conn_mode == MGCP_CONN_RECV_ONLY) { + DEBUGP(DMGCP, "Not forwarding data from possible BTS conn: %d on 0x%x\n", + endp->conn_mode, ENDPOINT_NUMBER(endp)); + return -1; + } + + if (fd == &endp->local_rtp) { + return _send(fd->fd, &endp->remote, endp->rtp, buf, rc); + } else { + return _send(fd->fd, &endp->remote, endp->rtcp, buf, rc); + } +} + +static int create_bind(struct bsc_fd *fd, int port) +{ + struct sockaddr_in addr; + int on = 1; + + fd->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd->fd < 0) + return -1; + + setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) + return -1; + + return 0; +} + +static int bind_rtp(struct mgcp_endpoint *endp) +{ + /* set to zero until we get the info */ + memset(&endp->remote, 0, sizeof(endp->remote)); + endp->bts_rtp = endp->bts_rtcp = 0; + endp->rtp = endp->rtcp = 0; + + if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { + DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup0; + } + + if (create_bind(&endp->local_rtcp, endp->rtp_port + 1) != 0) { + DEBUGP(DMGCP, "Failed to create RTCP port: %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup1; + } + + endp->local_rtp.cb = rtp_data_cb; + endp->local_rtp.data = endp; + endp->local_rtp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtp) != 0) { + DEBUGP(DMGCP, "Failed to register RTP port %d on 0x%x\n", + endp->rtp_port, ENDPOINT_NUMBER(endp)); + goto cleanup2; + } + + endp->local_rtcp.cb = rtp_data_cb; + endp->local_rtcp.data = endp; + endp->local_rtcp.when = BSC_FD_READ; + if (bsc_register_fd(&endp->local_rtcp) != 0) { + DEBUGP(DMGCP, "Failed to register RTCP port %d on 0x%x\n", + endp->rtp_port + 1, ENDPOINT_NUMBER(endp)); + goto cleanup3; + } + + return 0; + +cleanup3: + bsc_unregister_fd(&endp->local_rtp); +cleanup2: + close(endp->local_rtcp.fd); + endp->local_rtcp.fd = -1; +cleanup1: + close(endp->local_rtp.fd); + endp->local_rtp.fd = -1; +cleanup0: + return -1; +} + +/* + * array of function pointers for handling various + * messages. In the future this might be binary sorted + * for performance reasons. + */ +static const struct mgcp_request mgcp_requests [] = { + MGCP_REQUEST("AUEP", handle_audit_endpoint, "AuditEndpoint") + MGCP_REQUEST("CRCX", handle_create_con, "CreateConnection") + MGCP_REQUEST("DLCX", handle_delete_con, "DeleteConnection") + MGCP_REQUEST("MDCX", handle_modify_con, "ModifiyConnection") +}; + +static void send_response_with_data(int code, const char *msg, const char *trans, + const char *data, struct sockaddr_in *source) +{ + char buf[4096]; + int len; + + if (data) { + len = snprintf(buf, sizeof(buf), "%d %s\n%s", code, trans, data); + } else { + len = snprintf(buf, sizeof(buf), "%d %s\n", code, trans); + } + DEBUGP(DMGCP, "Sending response: code: %d for '%s'\n", code, msg); + + sendto(bfd.fd, buf, len, 0, (struct sockaddr *)source, sizeof(*source)); +} + +static void send_response(int code, const char *msg, const char *trans, struct sockaddr_in *source) +{ + send_response_with_data(code, msg, trans, NULL, source); +} + +static void send_with_sdp(struct mgcp_endpoint *endp, const char *msg, const char *trans_id, struct sockaddr_in *source) +{ + const char *addr = local_ip; + char sdp_record[4096]; + + if (!addr) + addr = source_addr; + + snprintf(sdp_record, sizeof(sdp_record) - 1, + "I: %d\n\n" + "v=0\r\n" + "c=IN IP4 %s\r\n" + "m=audio %d RTP/AVP %d\r\n" + "a=rtpmap:%d %s\r\n", + endp->ci, addr, endp->rtp_port, + audio_payload, audio_payload, audio_name); + return send_response_with_data(200, msg, trans_id, sdp_record, source); +} + +/* send a static record */ +static void send_rsip(struct sockaddr_in *source) +{ + char reset[4096]; + int len, rc; + + len = snprintf(reset, sizeof(reset) - 1, + "RSIP %u *@mgw MGCP 1.0\n" + "RM: restart\n", generate_transaction_id()); + rc = sendto(bfd.fd, reset, len, 0, (struct sockaddr *) source, sizeof(*source)); + if (rc < 0) { + DEBUGP(DMGCP, "Failed to send RSIP: %d\n", rc); + } +} + +/* + * handle incoming messages: + * - this can be a command (four letters, space, transaction id) + * - or a response (three numbers, space, transaction id) + */ +static void handle_message(struct msgb *msg, struct sockaddr_in *source) +{ + int code; + + if (msg->len < 4) { + DEBUGP(DMGCP, "mgs too short: %d\n", msg->len); + return; + } + + /* attempt to treat it as a response */ + if (sscanf((const char *)&msg->data[0], "%3d %*s", &code) == 1) { + DEBUGP(DMGCP, "Response: Code: %d\n", code); + } else { + int i, handled = 0; + msg->l3h = &msg->l2h[4]; + for (i = 0; i < ARRAY_SIZE(mgcp_requests); ++i) + if (strncmp(mgcp_requests[i].name, (const char *) &msg->data[0], 4) == 0) { + handled = 1; + mgcp_requests[i].handle_request(msg, source); + } + if (!handled) { + DEBUGP(DMGCP, "MSG with type: '%.4s' not handled\n", &msg->data[0]); + } + } +} + +/* string tokenizer for the poor */ +static int find_msg_pointers(struct msgb *msg, struct mgcp_msg_ptr *ptrs, int ptrs_length) +{ + int i, found = 0; + + int whitespace = 1; + for (i = 0; i < msgb_l3len(msg) && ptrs_length > 0; ++i) { + /* if we have a space we found an end */ + if (msg->l3h[i] == ' ' || msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + if (!whitespace) { + ++found; + whitespace = 1; + ptrs->length = i - ptrs->start - 1; + ++ptrs; + --ptrs_length; + } else { + /* skip any number of whitespace */ + } + + /* line end... stop */ + if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') + break; + } else if (msg->l3h[i] == '\r' || msg->l3h[i] == '\n') { + /* line end, be done */ + break; + } else if (whitespace) { + whitespace = 0; + ptrs->start = i; + } + } + + if (ptrs_length == 0) + return -1; + return found; +} + +static struct mgcp_endpoint *find_endpoint(const char *mgcp) +{ + char *endptr = NULL; + unsigned int gw = INT_MAX; + + gw = strtoul(mgcp, &endptr, 16); + if (gw == 0 || gw >= number_endpoints || strcmp(endptr, "@mgw") != 0) { + DEBUGP(DMGCP, "Not able to find endpoint: '%s'\n", mgcp); + return NULL; + } + + return &endpoints[gw]; +} + +static int analyze_header(struct msgb *msg, struct mgcp_msg_ptr *ptr, int size, + const char **transaction_id, struct mgcp_endpoint **endp) +{ + int found; + + if (size < 3) { + DEBUGP(DMGCP, "Not enough space in ptr\n"); + return -1; + } + + found = find_msg_pointers(msg, ptr, size); + + if (found < 3) { + DEBUGP(DMGCP, "Gateway: Not enough params. Found: %d\n", found); + return -1; + } + + /* + * replace the space with \0. the main method gurantess that + * we still have + 1 for null termination + */ + msg->l3h[ptr[3].start + ptr[3].length + 1] = '\0'; + msg->l3h[ptr[2].start + ptr[2].length + 1] = '\0'; + msg->l3h[ptr[1].start + ptr[1].length + 1] = '\0'; + msg->l3h[ptr[0].start + ptr[0].length + 1] = '\0'; + + if (strncmp("1.0", (const char *)&msg->l3h[ptr[3].start], 3) != 0 + || strncmp("MGCP", (const char *)&msg->l3h[ptr[2].start], 4) != 0) { + DEBUGP(DMGCP, "Wrong MGCP version. Not handling: '%s' '%s'\n", + (const char *)&msg->l3h[ptr[3].start], + (const char *)&msg->l3h[ptr[2].start]); + return -1; + } + + *transaction_id = (const char *)&msg->l3h[ptr[0].start]; + *endp = find_endpoint((const char *)&msg->l3h[ptr[1].start]); + return *endp == NULL; +} + +static int verify_call_id(const struct mgcp_endpoint *endp, + const char *callid) +{ + if (strcmp(endp->callid, callid) != 0) { + DEBUGP(DMGCP, "CallIDs does not match on 0x%x. '%s' != '%s'\n", + ENDPOINT_NUMBER(endp), endp->callid, callid); + return -1; + } + + return 0; +} + +static int verify_ci(const struct mgcp_endpoint *endp, + const char *ci) +{ + if (atoi(ci) != endp->ci) { + DEBUGP(DMGCP, "ConnectionIdentifiers do not match on 0x%x. %d != %s\n", + ENDPOINT_NUMBER(endp), endp->ci, ci); + return -1; + } + + return 0; +} + +static void handle_audit_endpoint(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, response; + const char *trans_id; + struct mgcp_endpoint *endp; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + response = 500; + else + response = 200; + + return send_response(response, "AUEP", trans_id, source); +} + +static int parse_conn_mode(const char* msg, int *conn_mode) +{ + int ret = 0; + if (strcmp(msg, "recvonly") == 0) + *conn_mode = MGCP_CONN_RECV_ONLY; + else if (strcmp(msg, "sendrecv") == 0) + *conn_mode = MGCP_CONN_RECV_SEND; + else { + DEBUGP(DMGCP, "Unknown connection mode: '%s'\n", msg); + ret = -1; + } + + return ret; +} + +static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(500, "CRCX", trans_id, source); + + if (endp->ci != CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(500, "CRCX", trans_id, source); + } + + /* parse CallID C: and LocalParameters L: */ + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'L': + endp->local_options = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'C': + endp->callid = talloc_strdup(endpoints, + (const char *)&msg->l3h[line_start + 3]); + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error2; + } + break; + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + + /* bind to the port now */ + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (!early_bind && bind_rtp(endp) != 0) + goto error2; + + /* assign a local call identifier or fail */ + endp->ci = generate_call_id(); + if (endp->ci == CI_UNUSED) + goto error2; + + DEBUGP(DMGCP, "Creating endpoint on: 0x%x CI: %u port: %u\n", + ENDPOINT_NUMBER(endp), endp->ci, endp->rtp_port); + return send_with_sdp(endp, "CRCX", trans_id, source); +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(error_code, "CRCX", trans_id, source); + +error2: + DEBUGP(DMGCP, "Resource error on 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "CRCX", trans_id, source); +} + +static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(error_code, "MDCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not holding a connection. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "MDCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'L': + /* skip */ + break; + case 'M': + if (parse_conn_mode((const char *)&msg->l3h[line_start + 3], + &endp->conn_mode) != 0) { + error_code = 517; + goto error3; + } + break; + case '\0': + /* SDP file begins */ + break; + case 'a': + case 'o': + case 's': + case 't': + case 'v': + /* skip these SDP attributes */ + break; + case 'm': { + int port; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { + endp->rtp = htons(port); + endp->rtcp = htons(port + 1); + } + break; + } + case 'c': { + char ipv4[16]; + const char *param = (const char *)&msg->l3h[line_start]; + + if (sscanf(param, "c=IN IP4 %15s", ipv4) == 1) { + inet_aton(ipv4, &endp->remote); + } + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + /* modify */ + DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", + ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp); + return send_with_sdp(endp, "MDCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i, msg->l3h[line_start]); + return send_response(error_code, "MDCX", trans_id, source); + +error3: + return send_response(error_code, "MDCX", trans_id, source); +} + +static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) +{ + struct mgcp_msg_ptr data_ptrs[6]; + int found, i, line_start; + const char *trans_id; + struct mgcp_endpoint *endp; + int error_code = 500; + + found = analyze_header(msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp); + if (found != 0) + return send_response(error_code, "DLCX", trans_id, source); + + if (endp->ci == CI_UNUSED) { + DEBUGP(DMGCP, "Endpoint is not used. 0x%x\n", ENDPOINT_NUMBER(endp)); + return send_response(error_code, "DLCX", trans_id, source); + } + + MSG_TOKENIZE_START + switch (msg->l3h[line_start]) { + case 'C': { + if (verify_call_id(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + case 'I': { + if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0) + goto error3; + break; + } + default: + DEBUGP(DMGCP, "Unhandled option: '%c'/%d on 0x%x\n", + msg->l3h[line_start], msg->l3h[line_start], + ENDPOINT_NUMBER(endp)); + break; + } + MSG_TOKENIZE_END + + + /* free the connection */ + DEBUGP(DMGCP, "Deleting endpoint on: 0x%x\n", ENDPOINT_NUMBER(endp)); + endp->ci= CI_UNUSED; + talloc_free(endp->callid); + talloc_free(endp->local_options); + + if (!early_bind) { + bsc_unregister_fd(&endp->local_rtp); + bsc_unregister_fd(&endp->local_rtcp); + } + + return send_response(250, "DLCX", trans_id, source); + +error: + DEBUGP(DMGCP, "Malformed line: %s on 0x%x with: line_start: %d %d\n", + hexdump(msg->l3h, msgb_l3len(msg)), + ENDPOINT_NUMBER(endp), line_start, i); + return send_response(error_code, "DLCX", trans_id, source); + +error3: + return send_response(error_code, "DLCX", trans_id, source); +} + +static void print_help() +{ + printf("Some useful help...\n"); + printf(" -h --help is printing this text.\n"); + printf(" -c --config-file filename The config file to use.\n"); +} + +static void handle_options(int argc, char** argv) +{ + while (1) { + int option_index = 0, c; + static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"config-file", 1, 0, 'c'}, + {0, 0, 0, 0}, + }; + + c = getopt_long(argc, argv, "hc:", long_options, &option_index); + + if (c == -1) + break; + + switch(c) { + case 'h': + print_help(); + exit(0); + break; + case 'c': + config_file = talloc_strdup(tall_bsc_ctx, optarg); + break; + default: + /* ignore */ + break; + }; + } +} + +static int read_call_agent(struct bsc_fd *fd, unsigned int what) +{ + struct sockaddr_in addr; + socklen_t slen = sizeof(addr); + struct msgb *msg; + + msg = (struct msgb *) fd->data; + + /* read one less so we can use it as a \0 */ + int rc = recvfrom(bfd.fd, msg->data, msg->data_len - 1, 0, + (struct sockaddr *) &addr, &slen); + if (rc < 0) { + perror("Gateway failed to read"); + return -1; + } else if (slen > sizeof(addr)) { + fprintf(stderr, "Gateway received message from outerspace: %d %d\n", + slen, sizeof(addr)); + return -1; + } + + if (first_request) { + first_request = 0; + send_rsip(&addr); + return 0; + } + + /* handle message now */ + msg->l2h = msgb_put(msg, rc); + handle_message(msg, &addr); + msgb_reset(msg); + return 0; +} + +/* + * vty code for mgcp below + */ +struct cmd_node mgcp_node = { + MGCP_NODE, + "%s(mgcp)#", + 1, +}; + +static int config_write_mgcp(struct vty *vty) +{ + vty_out(vty, "mgcp%s", VTY_NEWLINE); + if (local_ip) + vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); + vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); + vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); + vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); + vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp, + cfg_mgcp_cmd, + "mgcp", + "Configure the MGCP") +{ + vty->node = MGCP_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_local_ip, + cfg_mgcp_local_ip_cmd, + "local ip IP", + "Set the IP to be used in SDP records") +{ + local_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bts_ip, + cfg_mgcp_bts_ip_cmd, + "bts ip IP", + "Set the IP of the BTS for RTP forwarding") +{ + bts_ip = talloc_strdup(tall_bsc_ctx, argv[0]); + inet_aton(bts_ip, &bts_in); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_ip, + cfg_mgcp_bind_ip_cmd, + "bind ip IP", + "Bind the MGCP to this local addr") +{ + source_addr = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_port, + cfg_mgcp_bind_port_cmd, + "bind port <0-65534>", + "Bind the MGCP to this port") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + source_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_bind_early, + cfg_mgcp_bind_early_cmd, + "bind early (0|1)", + "Bind all RTP ports early") +{ + unsigned int bind = atoi(argv[0]); + if (bind != 0 && bind != 1) { + vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE); + return CMD_WARNING; + } + + early_bind = bind == 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_rtp_base_port, + cfg_mgcp_rtp_base_port_cmd, + "rtp base <0-65534>", + "Base port to use") +{ + unsigned int port = atoi(argv[0]); + if (port > 65534) { + vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + rtp_base_port = port; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_number, + cfg_mgcp_sdp_payload_number_cmd, + "sdp audio payload number <1-255>", + "Set the audio codec to use") +{ + unsigned int payload = atoi(argv[0]); + if (payload > 255) { + vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + audio_payload = payload; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_sdp_payload_name, + cfg_mgcp_sdp_payload_name_cmd, + "sdp audio payload name NAME", + "Set the audio name to use") +{ + audio_name = talloc_strdup(tall_bsc_ctx, argv[0]); + return CMD_SUCCESS; +} + +static void mgcp_vty_init() +{ + cmd_init(1); + vty_init(); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); + install_node(&mgcp_node, config_write_mgcp); + install_default(MGCP_NODE); + install_element(MGCP_NODE, &cfg_mgcp_local_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bts_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_ip_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd); + install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); + install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); +} + +int main(int argc, char** argv) +{ + struct sockaddr_in addr; + int on = 1, i, rc; + + tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); + handle_options(argc, argv); + + mgcp_vty_init(); + rc = vty_read_config_file(config_file); + if (rc < 0) { + fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); + return rc; + } + + + if (!bts_ip) { + fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n"); + return -1; + } + + endpoints = _talloc_zero_array(tall_bsc_ctx, + sizeof(struct mgcp_endpoint), + number_endpoints, "endpoints"); + if (!endpoints) { + fprintf(stderr, "Failed to allocate endpoints: %d. Quitting.\n", number_endpoints); + return -1; + } + + /* Initialize all endpoints */ + for (i = 0; i < number_endpoints; ++i) { + endpoints[i].local_rtp.fd = -1; + endpoints[i].local_rtcp.fd = -1; + endpoints[i].ci = CI_UNUSED; + } + + /* initialize the socket */ + bfd.when = BSC_FD_READ; + bfd.cb = read_call_agent; + bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); + if (bfd.fd < 0) { + perror("Gateway failed to listen"); + return -1; + } + + setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(source_port); + inet_aton(source_addr, &addr.sin_addr); + + if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + perror("Gateway failed to bind"); + return -1; + } + + bfd.data = msgb_alloc(4096, "mgcp-msg"); + if (!bfd.data) { + fprintf(stderr, "Gateway memory error.\n"); + return -1; + } + + + if (bsc_register_fd(&bfd) != 0) { + DEBUGP(DMGCP, "Failed to register the fd\n"); + return -1; + } + + /* initialisation */ + srand(time(NULL)); + + /* early bind */ + if (early_bind) { + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); + if (bind_rtp(endp) != 0) + return -1; + } + } + + /* main loop */ + while (1) { + bsc_select_main(0); + } + + + return 0; +} diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg new file mode 100644 index 000000000..c4da05162 --- /dev/null +++ b/openbsc/src/mgcp.cfg @@ -0,0 +1,17 @@ +! +! MGCP configuration hand edited +! ! +password foo +! +line vty + no login +! +mgcp + local ip 172.23.23.23 + bts ip 192.168.100.100 + bind ip 0.0.0.0 + bind port 2427 + bind early 1 + rtp base 4000 + sdp audio payload number 97 + sdp audio payload name GSM-EFR/8000 -- cgit v1.2.3 From 138b7ecd5e695f2d00d6fe49756bd1d85e6a5a96 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 18 Nov 2009 18:32:31 +0100 Subject: [mgcp] Add option to route audio back to both ends This is a simple echo functionality in the MGCP... it will send the audio back to the network|bts.. --- openbsc/src/bsc_mgcp.c | 59 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 23 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 8b59b31cb..c7db3bf3d 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -61,6 +61,7 @@ static struct in_addr bts_in; static int first_request = 1; static const char *audio_name = "GSM-EFR/8000"; static int audio_payload = 97; +static int audio_loop = 0; static int early_bind = 0; static char *config_file = "mgcp.cfg"; @@ -75,6 +76,16 @@ enum mgcp_connection_mode { MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY, }; +enum { + DEST_NETWORK = 0, + DEST_BTS = 1, +}; + +enum { + PROTO_RTP, + PROTO_RTCP, +}; + #define CI_UNUSED 0 static unsigned int last_call_id = 0; @@ -211,7 +222,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) struct sockaddr_in addr; socklen_t slen = sizeof(addr); struct mgcp_endpoint *endp; - int rc, is_remote; + int rc, dest, proto; endp = (struct mgcp_endpoint *) fd->data; @@ -231,22 +242,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) * able to tell if this is legitimate. */ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward." - is_remote = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0; - if (is_remote) { - if (endp->rtp == addr.sin_port) { - return _send(fd->fd, &bts_in, endp->bts_rtp, buf, rc); - } else if (endp->rtcp == addr.sin_port) { - return _send(fd->fd, &bts_in, endp->bts_rtcp, buf, rc); - } else { - DEBUGP(DMGCP, "Unknown remote port. Not able to forward on 0x%x port: %d\n", - ENDPOINT_NUMBER(endp), ntohs(addr.sin_port)); - } - - return -1; - } + dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 + ? DEST_BTS : DEST_NETWORK; + proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; /* We have no idea who called us, maybe it is the BTS. */ - if (endp->bts_rtp == 0) { + if (dest == DEST_NETWORK && endp->bts_rtp == 0) { /* it was the BTS... */ if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { @@ -262,16 +263,18 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) } } - if (endp->bts_rtp == 0 || endp->conn_mode == MGCP_CONN_RECV_ONLY) { - DEBUGP(DMGCP, "Not forwarding data from possible BTS conn: %d on 0x%x\n", - endp->conn_mode, ENDPOINT_NUMBER(endp)); - return -1; - } + /* dispatch */ + if (audio_loop) + dest = !dest; - if (fd == &endp->local_rtp) { - return _send(fd->fd, &endp->remote, endp->rtp, buf, rc); + if (dest == DEST_NETWORK) { + return _send(fd->fd, &endp->remote, + proto == PROTO_RTP ? endp->rtp : endp->rtcp, + buf, rc); } else { - return _send(fd->fd, &endp->remote, endp->rtcp, buf, rc); + return _send(fd->fd, &bts_in, + proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, + buf, rc); } } @@ -1007,6 +1010,15 @@ DEFUN(cfg_mgcp_sdp_payload_name, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_loop, + cfg_mgcp_loop_cmd, + "loop (0|1)", + "Loop the audio") +{ + audio_loop = atoi(argv[0]); + return CMD_SUCCESS; +} + static void mgcp_vty_init() { cmd_init(1); @@ -1023,6 +1035,7 @@ static void mgcp_vty_init() install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); + install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); } int main(int argc, char** argv) -- cgit v1.2.3 From 1cf9cf3eebdd0fce1d81feae3bb12f7f03932b0b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 11:45:43 +0100 Subject: [mgcp] MGCP... update config file to use AMR --- openbsc/src/mgcp.cfg | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg index c4da05162..d9950ab95 100644 --- a/openbsc/src/mgcp.cfg +++ b/openbsc/src/mgcp.cfg @@ -7,11 +7,12 @@ line vty no login ! mgcp - local ip 172.23.23.23 - bts ip 192.168.100.100 - bind ip 0.0.0.0 +! local ip 213.167.134.14 + bts ip 172.16.252.43 + bind ip 213.167.134.141 bind port 2427 bind early 1 rtp base 4000 - sdp audio payload number 97 - sdp audio payload name GSM-EFR/8000 + sdp audio payload number 98 + sdp audio payload name AMR/8000 + loop 1 -- cgit v1.2.3 From 338fa562c0a8be518182d62e22de89a3e429fdb4 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:03:39 +0100 Subject: [mgcp] Add telnet interface for mgcp. --- openbsc/src/Makefile.am | 2 +- openbsc/src/bsc_mgcp.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index 7651132b6..d28c80354 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -34,5 +34,5 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP isdnsync_SOURCES = isdnsync.c -bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c +bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_LDADD = libvty.a diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index c7db3bf3d..df9564140 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -38,13 +38,13 @@ #include #include #include +#include #include #include /* this is here for the vty... it will never be called */ void subscr_put() { abort(); } -void vty_event() { } #define _GNU_SOURCE #include @@ -1019,7 +1019,7 @@ DEFUN(cfg_mgcp_loop, return CMD_SUCCESS; } -static void mgcp_vty_init() +int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); vty_init(); @@ -1036,17 +1036,19 @@ static void mgcp_vty_init() install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + return 0; } int main(int argc, char** argv) { + struct gsm_network dummy_network; struct sockaddr_in addr; int on = 1, i, rc; tall_bsc_ctx = talloc_named_const(NULL, 1, "mgcp-callagent"); handle_options(argc, argv); - mgcp_vty_init(); + telnet_init(&dummy_network, 4243); rc = vty_read_config_file(config_file); if (rc < 0) { fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); -- cgit v1.2.3 From 5fddf475d522e73462472dadc9068aad698907ab Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:08:02 +0100 Subject: [mgcp] Fix writing the configuration file --- openbsc/src/bsc_mgcp.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index df9564140..4820465f7 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -899,7 +899,11 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); + vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); vty_out(vty, " rtp base %u%s", rtp_base_port, VTY_NEWLINE); + vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); + vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); + vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); return CMD_SUCCESS; } -- cgit v1.2.3 From 17e791666d527f83ad80b346ad58ecc39a913054 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 15:20:48 +0100 Subject: [mgcp] Add a show command for the mgcp... --- openbsc/src/bsc_mgcp.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 4820465f7..4ebf6c84e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -908,6 +908,23 @@ static int config_write_mgcp(struct vty *vty) return CMD_SUCCESS; } +DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp", + SHOW_STR "Display information about the MGCP Media Gateway") +{ + int i; + + vty_out(vty, "MGCP is up and running with %u endpoints:%s", number_endpoints - 1, VTY_NEWLINE); + for (i = 1; i < number_endpoints; ++i) { + struct mgcp_endpoint *endp = &endpoints[i]; + vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", + i, endp->ci, + ntohs(endp->rtp), ntohs(endp->rtcp), + ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); + } + + return CMD_SUCCESS; +} + DEFUN(cfg_mgcp, cfg_mgcp_cmd, "mgcp", @@ -1028,6 +1045,9 @@ int bsc_vty_init(struct gsm_network *dummy) cmd_init(1); vty_init(); + install_element(VIEW_NODE, &show_mgcp_cmd); + + install_element(CONFIG_NODE, &cfg_mgcp_cmd); install_node(&mgcp_node, config_write_mgcp); install_default(MGCP_NODE); -- cgit v1.2.3 From 48ecad48c7e79d3cc233d337db6950c9e5acbc16 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:04:10 +0100 Subject: [mgcp] Do not forward or find the BTS if the endpoint is unused Forget where the bts and network is located on DLCX and CRCX otherwise we would have forwarded BTS data to the wrong endpoint and would have not tried to discover the BTS again. In the case of early bind we might get data from the BTS before the CRCX and after DLCX... just ignore it then --- openbsc/src/bsc_mgcp.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index 4ebf6c84e..bb27d5634 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -234,6 +234,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) return -1; } + /* do not forward aynthing... maybe there is a packet from the bts */ + if (endp->ci == CI_UNUSED) + return -1; + /* * Figure out where to forward it to. This code assumes that we * have received the Connection Modify and know who is a legitimate @@ -635,6 +639,8 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source) } MSG_TOKENIZE_END + /* initialize */ + endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; /* bind to the port now */ endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); @@ -800,6 +806,8 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source) bsc_unregister_fd(&endp->local_rtcp); } + endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; + return send_response(250, "DLCX", trans_id, source); error: -- cgit v1.2.3 From 39e94ebbd2d70c47e1491e598a2f44b7670d45b2 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:25:14 +0100 Subject: [mgcp] The initialisation is done inside CRCX, remove here --- openbsc/src/bsc_mgcp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index bb27d5634..d0af8c61e 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -307,8 +307,6 @@ static int bind_rtp(struct mgcp_endpoint *endp) { /* set to zero until we get the info */ memset(&endp->remote, 0, sizeof(endp->remote)); - endp->bts_rtp = endp->bts_rtcp = 0; - endp->rtp = endp->rtcp = 0; if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", -- cgit v1.2.3 From 8ea4b5688a65e2e3cd8cd2529e40721f435dd18a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 16:25:53 +0100 Subject: [mgcp] The nanoBTS is not binding a RTCP port Do not guess the RTCP port as it might be the RTP port of another connection. --- openbsc/src/bsc_mgcp.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index d0af8c61e..d4007a0ec 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -256,14 +256,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what) if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (fd == &endp->local_rtp) { endp->bts_rtp = addr.sin_port; - endp->bts_rtcp = htons(ntohs(addr.sin_port) + 1); } else { - endp->bts_rtp = htons(ntohs(addr.sin_port) - 1); endp->bts_rtcp = addr.sin_port; } - DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d\n", - ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp)); + DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", + ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); } } -- cgit v1.2.3 From 4ec389e58f139fda2a540789f54ac38185dd1584 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 11:10:31 +0100 Subject: [mgcp] Make the number of endpoints configurable... Allow to configure the number of endpoints at start. Currently this will not be changed at runtime but one needs to save the config and restart the system. --- openbsc/src/bsc_mgcp.c | 14 +++++++++++++- openbsc/src/mgcp.cfg | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_mgcp.c b/openbsc/src/bsc_mgcp.c index d4007a0ec..6d5e6b154 100644 --- a/openbsc/src/bsc_mgcp.c +++ b/openbsc/src/bsc_mgcp.c @@ -55,7 +55,7 @@ static int source_port = 2427; static const char *local_ip = NULL; static const char *source_addr = "0.0.0.0"; static struct bsc_fd bfd; -static const unsigned int number_endpoints = 32 + 1; +static unsigned int number_endpoints = 0; static const char *bts_ip = NULL; static struct in_addr bts_in; static int first_request = 1; @@ -908,6 +908,7 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " sdp audio payload number %u%s", audio_payload, VTY_NEWLINE); vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); + vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); return CMD_SUCCESS; } @@ -1044,6 +1045,16 @@ DEFUN(cfg_mgcp_loop, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_number_endp, + cfg_mgcp_number_endp_cmd, + "number endpoints <0-65534>", + "The number of endpoints to allocate. This is not dynamic.") +{ + /* + 1 as we start counting at one */ + number_endpoints = atoi(argv[0]) + 1; + return CMD_SUCCESS; +} + int bsc_vty_init(struct gsm_network *dummy) { cmd_init(1); @@ -1064,6 +1075,7 @@ int bsc_vty_init(struct gsm_network *dummy) install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); + install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); return 0; } diff --git a/openbsc/src/mgcp.cfg b/openbsc/src/mgcp.cfg index d9950ab95..678f54637 100644 --- a/openbsc/src/mgcp.cfg +++ b/openbsc/src/mgcp.cfg @@ -15,4 +15,5 @@ mgcp rtp base 4000 sdp audio payload number 98 sdp audio payload name AMR/8000 + number endpoints 31 loop 1 -- cgit v1.2.3 From adb8bcea5f0a5f34b5742df124b2a9de1cba602a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 19 Aug 2009 06:31:59 +0200 Subject: [contrib] Add a utility to convert an IE page to an enum This script is parsing the values, converting the bits into a number and replacing the text... This should help to go from spec to code more quickly... next thing would be this for the structs used... --- openbsc/contrib/convert_to_enum.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 openbsc/contrib/convert_to_enum.py (limited to 'openbsc') diff --git a/openbsc/contrib/convert_to_enum.py b/openbsc/contrib/convert_to_enum.py new file mode 100755 index 000000000..bcd6f2cee --- /dev/null +++ b/openbsc/contrib/convert_to_enum.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# +# Convert ETSI documents to an enum +# + +import re, sys + +def convert(string): + string = string.strip().replace(" ", "").rjust(8, "0") + var = 0 + offset = 7 + for char in string: + assert offset >= 0 + var = var | (int(char) << offset) + offset = offset - 1 + + return var + +def string(name): + name = name.replace(" ", "_") + name = name.replace('"', "") + name = name.replace('/', '_') + name = name.replace('(', '_') + name = name.replace(')', '_') + return "%s_%s" % (sys.argv[2], name.upper()) + +file = open(sys.argv[1]) + + +for line in file: + m = re.match(r"[ \t]*(?P[01 ]+)[ ]+(?P[a-zA-Z /0-9()]+)", line[:-1]) + + if m: + print "\t%s\t\t= %d," % (string(m.groupdict()["name"]), convert(m.groupdict()["value"])) + else: + print line[:-1] -- cgit v1.2.3 From 7466351026f09364aa9b92ae921e564519bb115e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 20 Nov 2009 17:57:58 +0100 Subject: [misc] Fix the make distcheck Mention the two new header files, do not list isdnsync twice --- openbsc/include/openbsc/Makefile.am | 3 ++- openbsc/src/Makefile.am | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 461f5a89e..8bb64eb91 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -3,4 +3,5 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \ timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \ subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ - bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h + bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ + silent_call.h mgcp.h diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index d28c80354..9c8fa7b4d 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS=-Wall -sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync \ +sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ isdnsync bsc_mgcp noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_HEADERS = vty/cardshell.h -- cgit v1.2.3 From a8816dd9c76627ea2f99f7405e4f44b008f1401a Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 19:41:06 +0100 Subject: [talloc] Provide a copy of strnlen on OSX The implementation is taken from a blogspot and I don't think it is copyrightable... --- openbsc/src/talloc.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/talloc.c b/openbsc/src/talloc.c index bd5e1b0e0..d8213238e 100644 --- a/openbsc/src/talloc.c +++ b/openbsc/src/talloc.c @@ -105,6 +105,15 @@ #endif #endif +#ifdef __APPLE__ +/* taken from http://insanecoding.blogspot.com/2007/03/methods-for-safe-string-handling.html */ +size_t strnlen(const char *s, size_t n) +{ + const char *p = (const char *)memchr(s, 0, n); + return(p ? p-s : n); +} +#endif + /* this null_context is only used if talloc_enable_leak_report() or talloc_enable_leak_report_full() is called, otherwise it remains NULL -- cgit v1.2.3 From d61654cf544e5aa1bec50724589bb76d31471709 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 20:20:43 +0100 Subject: [chan] Alloc SDCCH for certain reserved types Follow notes: 2.) Allocate a SDCCH for type "LMU" 2a.)Allocate a SDCCH for the three reserved types 2b.)Pick LCHAN type none to "ignore" the request --- openbsc/include/openbsc/gsm_04_08.h | 3 +++ openbsc/src/gsm_04_08_utils.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index 40a76549e..b7c8a2662 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -656,6 +656,9 @@ enum chreq_type { CHREQ_T_PAG_R_ANY_NECI1, CHREQ_T_PAG_R_TCH_F, CHREQ_T_PAG_R_TCH_FH, + CHREQ_T_LMU, + CHREQ_T_RESERVED_SDCCH, + CHREQ_T_RESERVED_IGNORE, }; /* Chapter 11.3 */ diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c index b2fbdc2c3..ad038fba6 100644 --- a/openbsc/src/gsm_04_08_utils.c +++ b/openbsc/src/gsm_04_08_utils.c @@ -258,6 +258,11 @@ static const struct chreq chreq_type_neci1[] = { { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI1 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, + { 0x67, 0xff, CHREQ_T_LMU }, + { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, + { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, + { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, + { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, }; /* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */ @@ -270,6 +275,11 @@ static const struct chreq chreq_type_neci0[] = { { 0x80, 0xe0, CHREQ_T_PAG_R_ANY_NECI0 }, { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F }, { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH }, + { 0x67, 0xff, CHREQ_T_LMU }, + { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH }, + { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH }, + { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH }, + { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE }, }; static const enum gsm_chan_t ctype_by_chreq[] = { @@ -286,6 +296,9 @@ static const enum gsm_chan_t ctype_by_chreq[] = { [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH, [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F, [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F, + [CHREQ_T_LMU] = GSM_LCHAN_SDCCH, + [CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH, + [CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN, }; static const enum gsm_chreq_reason_t reason_by_chreq[] = { @@ -302,6 +315,9 @@ static const enum gsm_chreq_reason_t reason_by_chreq[] = { [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG, [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG, + [CHREQ_T_LMU] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_RESERVED_SDCCH] = GSM_CHREQ_REASON_OTHER, + [CHREQ_T_RESERVED_IGNORE] = GSM_CHREQ_REASON_OTHER, }; enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra, int neci) -- cgit v1.2.3 From c4d88ad9718a6cd4bd4bdfd57251bdd325d4db2f Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:18:38 +0100 Subject: [network] Make T3101 configurable and use it in abis_rsl --- openbsc/include/openbsc/gsm_data.h | 3 +++ openbsc/src/abis_rsl.c | 2 +- openbsc/src/openbsc.cfg.1-1 | 1 + openbsc/src/openbsc.cfg.1-2 | 1 + openbsc/src/openbsc.cfg.2-2 | 1 + openbsc/src/openbsc.cfg.nanobts | 1 + openbsc/src/vty_interface.c | 23 +++++++++++++++++++++++ 7 files changed, 31 insertions(+), 1 deletion(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0ac8674fd..0c400fdde 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -422,6 +422,9 @@ struct gsm_network { unsigned int num_bts; struct llist_head bts_list; + + /* timer values */ + int T3101; }; #define SMS_HDR_SIZE 128 diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 0dee79b17..692536c50 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -1186,7 +1186,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg) /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */ lchan->T3101.cb = t3101_expired; lchan->T3101.data = lchan; - bsc_schedule_timer(&lchan->T3101, 10, 0); + bsc_schedule_timer(&lchan->T3101, bts->network->T3101, 0); /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */ ret = rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia); diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index a8331ddbd..bad6df72d 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.1-2 b/openbsc/src/openbsc.cfg.1-2 index 10aa7b48b..b4c956d16 100644 --- a/openbsc/src/openbsc.cfg.1-2 +++ b/openbsc/src/openbsc.cfg.1-2 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index 0dd9d9b5d..e123a448b 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index a12794ffd..7f9846803 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -11,6 +11,7 @@ network mobile network code 1 short name OpenBSC long name OpenBSC + timer t3101 10 bts 0 type nanobts ip.access unit_id 1801 0 diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 5712ca1c7..e6513513b 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -275,6 +275,7 @@ static int config_write_net(struct vty *vty) vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); + vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); return CMD_SUCCESS; } @@ -801,6 +802,27 @@ DEFUN(cfg_net_neci, return CMD_SUCCESS; } +#define DECLARE_TIMER(number) \ + DEFUN(cfg_net_T##number, \ + cfg_net_T##number##_cmd, \ + "timer t" #number " <0-65535>", \ + "Set the T" #number " value.") \ +{ \ + int value = atoi(argv[0]); \ + \ + if (value < 0 || value > 65535) { \ + vty_out(vty, "Timer value %s out of range.%s", \ + argv[0], VTY_NEWLINE); \ + return CMD_WARNING; \ + } \ + \ + gsmnet->T##number = value; \ + return CMD_SUCCESS; \ +} + +DECLARE_TIMER(3101) + + /* per-BTS configuration */ DEFUN(cfg_bts, cfg_bts_cmd, @@ -1241,6 +1263,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); + install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); -- cgit v1.2.3 From 23975e718fd456ff8be7effbb915903f1bc173be Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:42:26 +0100 Subject: [network] Add config option for the remaining network timers There are all set to 0 and not used within the code yet but should be used in the future. --- openbsc/include/openbsc/gsm_data.h | 10 ++++++++++ openbsc/src/vty_interface.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 0c400fdde..18e115c1e 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -425,6 +425,16 @@ struct gsm_network { /* timer values */ int T3101; + int T3103; + int T3105; + int T3107; + int T3109; + int T3111; + int T3113; + int T3115; + int T3117; + int T3119; + int T3141; }; #define SMS_HDR_SIZE 128 diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index e6513513b..f8bba2c44 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -276,6 +276,16 @@ static int config_write_net(struct vty *vty) vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE); vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE); vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE); + vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE); + vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE); + vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE); + vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE); + vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE); + vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE); + vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE); + vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE); + vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE); + vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); return CMD_SUCCESS; } @@ -821,6 +831,16 @@ DEFUN(cfg_net_neci, } DECLARE_TIMER(3101) +DECLARE_TIMER(3103) +DECLARE_TIMER(3105) +DECLARE_TIMER(3107) +DECLARE_TIMER(3109) +DECLARE_TIMER(3111) +DECLARE_TIMER(3113) +DECLARE_TIMER(3115) +DECLARE_TIMER(3117) +DECLARE_TIMER(3119) +DECLARE_TIMER(3141) /* per-BTS configuration */ @@ -1264,6 +1284,16 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd); + install_element(GSMNET_NODE, &cfg_net_T3103_cmd); + install_element(GSMNET_NODE, &cfg_net_T3105_cmd); + install_element(GSMNET_NODE, &cfg_net_T3107_cmd); + install_element(GSMNET_NODE, &cfg_net_T3109_cmd); + install_element(GSMNET_NODE, &cfg_net_T3111_cmd); + install_element(GSMNET_NODE, &cfg_net_T3113_cmd); + install_element(GSMNET_NODE, &cfg_net_T3115_cmd); + install_element(GSMNET_NODE, &cfg_net_T3117_cmd); + install_element(GSMNET_NODE, &cfg_net_T3119_cmd); + install_element(GSMNET_NODE, &cfg_net_T3141_cmd); install_element(GSMNET_NODE, &cfg_bts_cmd); install_node(&bts_node, config_write_bts); -- cgit v1.2.3 From 4642d4917f0ced8ddf47d7f58a7d9e2ae2d23d24 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 21 Nov 2009 21:48:53 +0100 Subject: [network] Make use of T3113 for paging Add it to the configuration files and make use of it in the the paging.c. --- openbsc/include/openbsc/gsm_data.h | 1 - openbsc/src/openbsc.cfg.1-1 | 1 + openbsc/src/openbsc.cfg.1-2 | 1 + openbsc/src/openbsc.cfg.2-2 | 1 + openbsc/src/openbsc.cfg.nanobts | 1 + openbsc/src/paging.c | 2 +- 6 files changed, 5 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 18e115c1e..86a872b86 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -286,7 +286,6 @@ struct gsm_paging_request { gsm_cbfn *cbfn; void *cbfn_param; }; -#define T3113_VALUE 60, 0 /* * This keeps track of the paging status of one BTS. It diff --git a/openbsc/src/openbsc.cfg.1-1 b/openbsc/src/openbsc.cfg.1-1 index bad6df72d..d312843b0 100644 --- a/openbsc/src/openbsc.cfg.1-1 +++ b/openbsc/src/openbsc.cfg.1-1 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.1-2 b/openbsc/src/openbsc.cfg.1-2 index b4c956d16..84d50c75c 100644 --- a/openbsc/src/openbsc.cfg.1-2 +++ b/openbsc/src/openbsc.cfg.1-2 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.2-2 b/openbsc/src/openbsc.cfg.2-2 index e123a448b..c1468a647 100644 --- a/openbsc/src/openbsc.cfg.2-2 +++ b/openbsc/src/openbsc.cfg.2-2 @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type bs11 band GSM900 diff --git a/openbsc/src/openbsc.cfg.nanobts b/openbsc/src/openbsc.cfg.nanobts index 7f9846803..a1ceaec79 100644 --- a/openbsc/src/openbsc.cfg.nanobts +++ b/openbsc/src/openbsc.cfg.nanobts @@ -12,6 +12,7 @@ network short name OpenBSC long name OpenBSC timer t3101 10 + timer t3113 60 bts 0 type nanobts ip.access unit_id 1801 0 diff --git a/openbsc/src/paging.c b/openbsc/src/paging.c index 69902e8b1..fe6ea52d1 100644 --- a/openbsc/src/paging.c +++ b/openbsc/src/paging.c @@ -239,7 +239,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr, req->cbfn_param = data; req->T3113.cb = paging_T3113_expired; req->T3113.data = req; - bsc_schedule_timer(&req->T3113, T3113_VALUE); + bsc_schedule_timer(&req->T3113, bts->network->T3113, 0); llist_add_tail(&req->entry, &bts_entry->pending_requests); if (!bsc_timer_pending(&bts_entry->work_timer)) -- cgit v1.2.3 From fdd0ddf7e9eb6a8a7de8021678287b3d1677a070 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 22 Nov 2009 18:01:42 +0100 Subject: [sms] Fix compile warning by including gsm_data.h In file included from sms_test.c:27: ../../include/openbsc/gsm_utils.h:33: warning: `enum gsm_band' declared inside parameter list ../../include/openbsc/gsm_utils.h:33: warning: its scope is only this definition or declaration, which is probably not what you want ../../include/openbsc/gsm_utils.h:34: warning: `enum gsm_band' declared inside parameter list --- openbsc/tests/sms/sms_test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'openbsc') diff --git a/openbsc/tests/sms/sms_test.c b/openbsc/tests/sms/sms_test.c index fa0963644..2ce2cc6c4 100644 --- a/openbsc/tests/sms/sms_test.c +++ b/openbsc/tests/sms/sms_test.c @@ -24,6 +24,7 @@ #include #include #include +#include #include int main(int argc, char** argv) -- cgit v1.2.3 From 1ce10f3854ae110f6eb73383f44de3191934804b Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 19 Nov 2009 19:18:29 +0100 Subject: [bsc_init] Activate the RC and the RSL link from the Software Activated Callback On cold start the RSL link will not be brought up. Wait for the Software to be Activated before starting the RSL link. This is working reliable on the BTS I have tested with. This is a partial revert of 8406ec2437fcc28906b2085e305d79ae73accc2a and was discussed on the mailinglist. --- openbsc/src/bsc_init.c | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index d11cde578..66d560601 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -391,38 +391,11 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj, break; case NM_OC_RADIO_CARRIER: trx = obj; - if (new_state->operational == 1 && - new_state->availability == NM_AVSTATE_OFF_LINE) { - /* Patch ARFCN into radio attribute */ - nanobts_attr_radio[5] &= 0xf0; - nanobts_attr_radio[5] |= trx->arfcn >> 8; - nanobts_attr_radio[6] = trx->arfcn & 0xff; - abis_nm_set_radio_attr(trx, nanobts_attr_radio, - sizeof(nanobts_attr_radio)); - abis_nm_chg_adm_state(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, - trx->nr, 0xff); - } if (new_state->operational == 1 && new_state->availability == NM_AVSTATE_OK) abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr, trx->nr, 0xff); break; - case NM_OC_BASEB_TRANSC: - trx = container_of(obj, struct gsm_bts_trx, bb_transc); - if (new_state->operational == 1 && - new_state->availability == NM_AVSTATE_DEPENDENCY) { - abis_nm_chg_adm_state(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); - abis_nm_opstart(trx->bts, obj_class, - trx->bts->bts_nr, trx->nr, 0xff); - /* TRX software is active, tell it to initiate RSL Link */ - abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); - } - break; default: break; } @@ -438,6 +411,28 @@ static int sw_activ_rep(struct msgb *mb) switch (foh->obj_class) { + case NM_OC_BASEB_TRANSC: + abis_nm_chg_adm_state(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff); + /* TRX software is active, tell it to initiate RSL Link */ + abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); + break; + case NM_OC_RADIO_CARRIER: + /* Patch ARFCN into radio attribute */ + nanobts_attr_radio[5] &= 0xf0; + nanobts_attr_radio[5] |= trx->arfcn >> 8; + nanobts_attr_radio[6] = trx->arfcn & 0xff; + abis_nm_set_radio_attr(trx, nanobts_attr_radio, + sizeof(nanobts_attr_radio)); + abis_nm_chg_adm_state(trx->bts, foh->obj_class, + trx->bts->bts_nr, trx->nr, 0xff, + NM_STATE_UNLOCKED); + abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr, + trx->nr, 0xff); + break; } return 0; } -- cgit v1.2.3 From 2d501ea26a219176b1c556449e45ebd90d4accfb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 11 Nov 2009 11:54:24 +0100 Subject: [vty] Add option to disable RF on a given TRX. - Make sure that on runtime the Radio Carrier can be locked and unlocked. The vty code calls into the Abis NM to lock/unlock the channel and the state is stored there. - Make sure that on start the Radio Carries remains offline and we are not starting it. On start the radio carrier is either locked or unlocked. This means the RSL will not connect until the RF is unlocked. It will connect then. To see RSL bringup failures one needs to parse the RSL nack message. - When the TRX is locked on startup the RSL link will only be established after it will be unlocked. --- openbsc/include/openbsc/gsm_data.h | 5 +++++ openbsc/src/abis_nm.c | 13 +++++++++++++ openbsc/src/bsc_init.c | 16 ++++++++++++++-- openbsc/src/gsm_data.c | 1 + openbsc/src/vty_interface.c | 12 ++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 86a872b86..638b03506 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -257,6 +257,9 @@ struct gsm_bts_trx { } bs11; }; struct gsm_bts_trx_ts ts[TRX_NR_TS]; + + /* NM state */ + int rf_locked; }; enum gsm_bts_type { @@ -518,4 +521,6 @@ static inline int is_siemens_bts(struct gsm_bts *bts) enum gsm_auth_policy gsm_auth_policy_parse(const char *arg); const char *gsm_auth_policy_name(enum gsm_auth_policy policy); +void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); + #endif diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c index 4d4cec0a3..b1fe97ddf 100755 --- a/openbsc/src/abis_nm.c +++ b/openbsc/src/abis_nm.c @@ -2699,6 +2699,19 @@ int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class, attr, attr_len); } +void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked) +{ + int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED; + + trx->rf_locked = locked; + if (!trx->bts || !trx->bts->oml_link) + return; + + abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER, + trx->bts->bts_nr, trx->nr, 0xff, + new_state); +} + static const char *ipacc_testres_names[] = { [NM_IPACC_TESTRES_SUCCESS] = "SUCCESS", [NM_IPACC_TESTRES_TIMEOUT] = "TIMEOUT", diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c index 66d560601..153e024e4 100644 --- a/openbsc/src/bsc_init.c +++ b/openbsc/src/bsc_init.c @@ -420,7 +420,18 @@ static int sw_activ_rep(struct msgb *mb) /* TRX software is active, tell it to initiate RSL Link */ abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei); break; - case NM_OC_RADIO_CARRIER: + case NM_OC_RADIO_CARRIER: { + /* + * Locking the radio carrier will make it go + * offline again and we would come here. The + * framework should determine that there was + * no change and avoid recursion. + * + * This code is here to make sure that on start + * a TRX remains locked. + */ + int rc_state = trx->rf_locked ? + NM_STATE_LOCKED : NM_STATE_UNLOCKED; /* Patch ARFCN into radio attribute */ nanobts_attr_radio[5] &= 0xf0; nanobts_attr_radio[5] |= trx->arfcn >> 8; @@ -429,10 +440,11 @@ static int sw_activ_rep(struct msgb *mb) sizeof(nanobts_attr_radio)); abis_nm_chg_adm_state(trx->bts, foh->obj_class, trx->bts->bts_nr, trx->nr, 0xff, - NM_STATE_UNLOCKED); + rc_state); abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr, trx->nr, 0xff); break; + } } return 0; } diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index 69a9096ca..8212346ec 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -27,6 +27,7 @@ #include #include +#include void *tall_bsc_ctx; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index f8bba2c44..066dfd5a9 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -1200,6 +1200,17 @@ DEFUN(cfg_trx_rsl_e1_tei, return CMD_SUCCESS; } +DEFUN(cfg_trx_rf_locked, + cfg_trx_rf_locked_cmd, + "rf_locked (0|1)", + "Turn off RF of the TRX.\n") +{ + int locked = atoi(argv[0]); + struct gsm_bts_trx *trx = vty->index; + + gsm_trx_lock_rf(trx, locked); + return CMD_SUCCESS; +} /* per TS configuration */ DEFUN(cfg_ts, @@ -1321,6 +1332,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(TRX_NODE, &cfg_trx_max_power_red_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd); install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd); + install_element(TRX_NODE, &cfg_trx_rf_locked_cmd); install_element(TRX_NODE, &cfg_ts_cmd); install_node(&ts_node, dummy_config_write); -- cgit v1.2.3 From f326267fb7c146a73d93a50e670ea95a2c47f0c1 Mon Sep 17 00:00:00 2001 From: Steffen Neubauer Date: Thu, 26 Nov 2009 12:28:41 +0100 Subject: [SMS] Implement TP-VPF-ENHANCED While doing so, we also restructure/reorganize the vailidity period parsing in general. --- openbsc/src/gsm_04_11.c | 249 ++++++++++++++++++++++++++++++------------------ 1 file changed, 156 insertions(+), 93 deletions(-) (limited to 'openbsc') diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c index 75ddf9dd9..8e3c64974 100644 --- a/openbsc/src/gsm_04_11.c +++ b/openbsc/src/gsm_04_11.c @@ -198,48 +198,172 @@ static int gsm411_rp_sendmsg(struct msgb *msg, struct gsm_trans *trans, return gsm411_cp_sendmsg(msg, trans, GSM411_MT_CP_DATA); } -static time_t gsm340_scts(u_int8_t *scts); +/* Turn int into semi-octet representation: 98 => 0x89 */ +static u_int8_t bcdify(u_int8_t value) +{ + u_int8_t ret; -static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) + ret = value / 10; + ret |= (value % 10) << 4; + + return ret; +} + +/* Turn semi-octet representation into int: 0x89 => 98 */ +static u_int8_t unbcdify(u_int8_t value) +{ + u_int8_t ret; + + if ((value & 0x0F) > 9 || (value >> 4) > 9) + DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); + + ret = (value&0x0F)*10; + if (ret > 90) + ret += value>>4; + + return ret; +} + +/* Generate 03.40 TP-SCTS */ +static void gsm340_gen_scts(u_int8_t *scts, time_t time) +{ + struct tm *tm = localtime(&time); + + *scts++ = bcdify(tm->tm_year % 100); + *scts++ = bcdify(tm->tm_mon + 1); + *scts++ = bcdify(tm->tm_mday); + *scts++ = bcdify(tm->tm_hour); + *scts++ = bcdify(tm->tm_min); + *scts++ = bcdify(tm->tm_sec); + *scts++ = bcdify(tm->tm_gmtoff/(60*15)); +} + +/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ +static time_t gsm340_scts(u_int8_t *scts) +{ + struct tm tm; + + u_int8_t yr = unbcdify(*scts++); + + if (yr <= 80) + tm.tm_year = 100 + yr; + else + tm.tm_year = yr; + tm.tm_mon = unbcdify(*scts++) - 1; + tm.tm_mday = unbcdify(*scts++); + tm.tm_hour = unbcdify(*scts++); + tm.tm_min = unbcdify(*scts++); + tm.tm_sec = unbcdify(*scts++); + /* according to gsm 03.40 time zone is + "expressed in quarters of an hour" */ + tm.tm_gmtoff = unbcdify(*scts++) * 15*60; + + return mktime(&tm); +} + +/* Return the default validity period in minutes */ +static unsigned long gsm340_vp_default(void) +{ + unsigned long minutes; + /* Default validity: two days */ + minutes = 24 * 60 * 2; + return minutes; +} + +/* Decode validity period format 'relative' */ +static unsigned long gsm340_vp_relative(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.1 */ + u_int8_t vp; + unsigned long minutes; + + vp = *(sms_vp); + if (vp <= 143) + minutes = vp + 1 * 5; + else if (vp <= 167) + minutes = 12*60 + (vp-143) * 30; + else if (vp <= 196) + minutes = vp-166 * 60 * 24; + else + minutes = vp-192 * 60 * 24 * 7; + return minutes; +} + +/* Decode validity period format 'absolute' */ +static unsigned long gsm340_vp_absolute(u_int8_t *sms_vp) +{ + /* Chapter 9.2.3.12.2 */ + time_t expires, now; + unsigned long minutes; + + expires = gsm340_scts(sms_vp); + now = mktime(gmtime(NULL)); + if (expires <= now) + minutes = 0; + else + minutes = (expires-now)/60; + return minutes; +} + +/* Decode validity period format 'relative in integer representation' */ +static unsigned long gsm340_vp_relative_integer(u_int8_t *sms_vp) { u_int8_t vp; unsigned long minutes; - time_t expires; - time_t now; + vp = *(sms_vp); + if (vp == 0) { + DEBUGP(DSMS, "reserved relative_integer validity period\n"); + return gsm340_vp_default(); + } + minutes = vp/60; + return minutes; +} + +/* Decode validity period format 'relative in semi-octet representation' */ +static unsigned long gsm340_vp_relative_semioctet(u_int8_t *sms_vp) +{ + unsigned long minutes; + minutes = unbcdify(*sms_vp++)*60; /* hours */ + minutes += unbcdify(*sms_vp++); /* minutes */ + minutes += unbcdify(*sms_vp++)/60; /* seconds */ + return minutes; +} + +/* decode validity period. return minutes */ +static unsigned long gsm340_validity_period(u_int8_t sms_vpf, u_int8_t *sms_vp) +{ + u_int8_t fi; /* functionality indicator */ switch (sms_vpf) { case GSM340_TP_VPF_RELATIVE: - /* Chapter 9.2.3.12.1 */ - vp = *(sms_vp); - if (vp <= 143) - minutes = vp + 1 * 5; - else if (vp <= 167) - minutes = 12*60 + (vp-143) * 30; - else if (vp <= 196) - minutes = vp-166 * 60 * 24; - else - minutes = vp-192 * 60 * 24 * 7; - break; + return gsm340_vp_relative(sms_vp); case GSM340_TP_VPF_ABSOLUTE: - /* Chapter 9.2.3.12.2 */ - expires = gsm340_scts(sms_vp); - now = mktime(gmtime(NULL)); - if (expires <= now) - minutes = 0; - else - minutes = (expires-now)/60; - break; + return gsm340_vp_absolute(sms_vp); case GSM340_TP_VPF_ENHANCED: /* Chapter 9.2.3.12.3 */ - /* FIXME: implementation */ - DEBUGP(DSMS, "VPI enhanced not implemented yet\n"); - break; + fi = *sms_vp++; + /* ignore additional fi */ + if (fi & (1<<7)) sms_vp++; + /* read validity period format */ + switch (fi & 0b111) { + case 0b000: + return gsm340_vp_default(); /* no vpf specified */ + case 0b001: + return gsm340_vp_relative(sms_vp); + case 0b010: + return gsm340_vp_relative_integer(sms_vp); + case 0b011: + return gsm340_vp_relative_semioctet(sms_vp); + default: + /* The GSM spec says that the SC should reject any + unsupported and/or undefined values. FIXME */ + DEBUGP(DSMS, "Reserved enhanced validity period format\n"); + return gsm340_vp_default(); + } case GSM340_TP_VPF_NONE: - /* Default validity: two days */ - minutes = 24 * 60 * 2; - break; + default: + return gsm340_vp_default(); } - return minutes; } /* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */ @@ -307,69 +431,6 @@ static int gsm340_gen_oa(u_int8_t *oa, unsigned int oa_len, return len_in_bytes; } -/* Turn int into semi-octet representation: 98 => 0x89 */ -static u_int8_t bcdify(u_int8_t value) -{ - u_int8_t ret; - - ret = value / 10; - ret |= (value % 10) << 4; - - return ret; -} - -/* Turn semi-octet representation into int: 0x89 => 98 */ -static u_int8_t unbcdify(u_int8_t value) -{ - u_int8_t ret; - - if ((value & 0x0F) > 9 || (value >> 4) > 9) - DEBUGP(DSMS, "unbcdify got too big nibble: 0x%02X\n", value); - - ret = (value&0x0F)*10; - if (ret > 90) - ret += value>>4; - - return ret; -} - -/* Generate 03.40 TP-SCTS */ -static void gsm340_gen_scts(u_int8_t *scts, time_t time) -{ - struct tm *tm = localtime(&time); - - *scts++ = bcdify(tm->tm_year % 100); - *scts++ = bcdify(tm->tm_mon + 1); - *scts++ = bcdify(tm->tm_mday); - *scts++ = bcdify(tm->tm_hour); - *scts++ = bcdify(tm->tm_min); - *scts++ = bcdify(tm->tm_sec); - *scts++ = bcdify(tm->tm_gmtoff/(60*15)); -} - -/* Decode 03.40 TP-SCTS (into utc/gmt timestamp) */ -static time_t gsm340_scts(u_int8_t *scts) -{ - struct tm tm; - - u_int8_t yr = unbcdify(*scts++); - - if (yr <= 80) - tm.tm_year = 100 + yr; - else - tm.tm_year = yr; - tm.tm_mon = unbcdify(*scts++) - 1; - tm.tm_mday = unbcdify(*scts++); - tm.tm_hour = unbcdify(*scts++); - tm.tm_min = unbcdify(*scts++); - tm.tm_sec = unbcdify(*scts++); - /* according to gsm 03.40 time zone is - "expressed in quarters of an hour" */ - tm.tm_gmtoff = unbcdify(*scts++) * 15*60; - - return mktime(&tm); -} - /* generate a msgb containing a TPDU derived from struct gsm_sms, * returns total size of TPDU */ static int gsm340_gen_tpdu(struct msgb *msg, struct gsm_sms *sms) @@ -499,6 +560,8 @@ static int gsm340_rx_tpdu(struct msgb *msg) case GSM340_TP_VPF_ABSOLUTE: case GSM340_TP_VPF_ENHANCED: sms_vp = smsp; + /* the additional functionality indicator... */ + if (*smsp & (1<<7)) smsp++; smsp += 7; break; case GSM340_TP_VPF_NONE: -- cgit v1.2.3 From 1a79d364401dfad2a71f1e61ff13a3861e3da46e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 27 Nov 2009 08:55:16 +0100 Subject: RSL: catch inconsistent parameters ofr channel_mode_from_lchan() --- openbsc/src/abis_rsl.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openbsc') diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c index 692536c50..219b01aa0 100644 --- a/openbsc/src/abis_rsl.c +++ b/openbsc/src/abis_rsl.c @@ -488,6 +488,11 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, /* set TCH Speech/Data */ cm->spd_ind = lchan->rsl_cmode; + if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && + lchan->tch_mode != GSM48_CMODE_SIGN) + DEBUGP(DRSL, "unsupported: rsl_mode == signalling, " + "but tch_mode != signalling\n"); + switch (lchan->type) { case GSM_LCHAN_SDCCH: cm->chan_rt = RSL_CMOD_CRT_SDCCH; -- cgit v1.2.3