This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Neels Hofmeyr gerrit-no-reply at lists.osmocom.orgReview at https://gerrit.osmocom.org/3695 NOT FOR MERGE combined changes from openbsc.git for gerrit checking Change-Id: Id072aa07793aceca66bd74950bc40dd504982a55 --- M configure.ac M contrib/jenkins.sh M doc/examples/osmo-bsc/osmo-bsc.cfg M include/openbsc/Makefile.am M include/openbsc/gprs_sgsn.h M include/openbsc/gprs_utils.h A include/openbsc/gsm_04_14.h M include/openbsc/gsm_data.h M include/openbsc/gsm_data_shared.h M include/openbsc/osmux.h M src/gprs/gb_proxy.c M src/gprs/gb_proxy_main.c M src/gprs/gb_proxy_patch.c M src/gprs/gb_proxy_peer.c M src/gprs/gb_proxy_vty.c M src/gprs/gprs_sgsn.c M src/gprs/gprs_subscriber.c M src/gprs/gprs_utils.c M src/gprs/gtphub.c M src/gprs/gtphub_main.c M src/gprs/sgsn_cdr.c M src/gprs/sgsn_libgtp.c M src/gprs/sgsn_main.c M src/gprs/sgsn_vty.c M src/libbsc/abis_nm.c M src/libbsc/abis_rsl.c M src/libbsc/bsc_api.c M src/libbsc/bsc_init.c M src/libbsc/bsc_vty.c M src/libbsc/handover_logic.c M src/libbsc/net_init.c M src/libcommon-cs/common_cs.c M src/libcommon/gsm_data.c M src/libcommon/gsm_data_shared.c M src/libmgcp/mgcp_osmux.c M src/libmgcp/mgcp_protocol.c M src/libmsc/Makefile.am M src/libmsc/db.c M src/libmsc/gsm_04_08.c M src/libmsc/gsm_04_11.c A src/libmsc/gsm_04_14.c M src/libmsc/smpp_openbsc.c M src/libmsc/smpp_smsc.c M src/libmsc/smpp_smsc.h M src/libmsc/transaction.c M src/libmsc/vty_interface_layer3.c M src/osmo-bsc/osmo_bsc_main.c M src/osmo-msc/msc_main.c M src/utils/smpp_mirror.c M tests/channel/channel_test.c M tests/channel/channel_test.ok M tests/db/db_test.err M tests/gprs/gprs_test.c M tests/gsm0408/gsm0408_test.c M tests/gtphub/Makefile.am M tests/sgsn/sgsn_test.c 56 files changed, 1,087 insertions(+), 405 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/95/3695/1 diff --git a/configure.ac b/configure.ac index f184e78..871f7e5 100644 --- a/configure.ac +++ b/configure.ac @@ -66,7 +66,7 @@ AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])], [osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"]) if test "$osmo_ac_build_smpp" = "yes" ; then - PKG_CHECK_MODULES(LIBSMPP34, libsmpp34 >= 1.10) + PKG_CHECK_MODULES(LIBSMPP34, libsmpp34 >= 1.12) AC_DEFINE(BUILD_SMPP, 1, [Define if we want to build SMPP]) fi AM_CONDITIONAL(BUILD_SMPP, test "x$osmo_ac_build_smpp" = "xyes") diff --git a/contrib/jenkins.sh b/contrib/jenkins.sh index b4074e4..7734965 100755 --- a/contrib/jenkins.sh +++ b/contrib/jenkins.sh @@ -1,4 +1,11 @@ #!/usr/bin/env bash +# jenkins build helper script for openbsc. This is how we build on jenkins.osmocom.org + +if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then + echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !" + exit 2 +fi + set -ex diff --git a/doc/examples/osmo-bsc/osmo-bsc.cfg b/doc/examples/osmo-bsc/osmo-bsc.cfg index b974b76..534605a 100644 --- a/doc/examples/osmo-bsc/osmo-bsc.cfg +++ b/doc/examples/osmo-bsc/osmo-bsc.cfg @@ -28,18 +28,6 @@ handover power budget interval 6 handover power budget hysteresis 3 handover maximum distance 9999 - timer t3101 10 - timer t3103 0 - timer t3105 0 - timer t3107 0 - timer t3109 0 - timer t3111 0 - timer t3113 60 - timer t3115 0 - timer t3117 0 - timer t3119 0 - timer t3122 0 - timer t3141 0 bts 0 type nanobts band DCS1800 diff --git a/include/openbsc/Makefile.am b/include/openbsc/Makefile.am index 2558d7c..995f02d 100644 --- a/include/openbsc/Makefile.am +++ b/include/openbsc/Makefile.am @@ -37,6 +37,7 @@ gprs_utils.h \ gsm_04_08.h \ gsm_04_11.h \ + gsm_04_14.h \ gsm_04_80.h \ gsm_data.h \ gsm_data_shared.h \ diff --git a/include/openbsc/gprs_sgsn.h b/include/openbsc/gprs_sgsn.h index fd86174..4e49c08 100644 --- a/include/openbsc/gprs_sgsn.h +++ b/include/openbsc/gprs_sgsn.h @@ -393,6 +393,8 @@ char apn_str[GSM_APN_LENGTH]; uint8_t qos_subscribed[20]; size_t qos_subscribed_len; + uint8_t pdp_charg[2]; + bool has_pdp_charg; }; struct sgsn_subscriber_data { @@ -407,6 +409,9 @@ uint8_t hlr[9]; size_t hlr_len; + + uint8_t pdp_charg[2]; + bool has_pdp_charg; }; #define SGSN_ERROR_CAUSE_NONE (-1) diff --git a/include/openbsc/gprs_utils.h b/include/openbsc/gprs_utils.h index 603605c..574f5c5 100644 --- a/include/openbsc/gprs_utils.h +++ b/include/openbsc/gprs_utils.h @@ -30,7 +30,6 @@ struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name); int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area, size_t old_size, size_t new_size); -char *gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars); int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str); /* GSM 04.08, 10.5.7.3 GPRS Timer */ diff --git a/include/openbsc/gsm_04_14.h b/include/openbsc/gsm_04_14.h new file mode 100644 index 0000000..3cdbe04 --- /dev/null +++ b/include/openbsc/gsm_04_14.h @@ -0,0 +1,15 @@ +#pragma once + +#include <osmocom/gsm/protocol/gsm_04_14.h> + +int gsm0414_tx_close_tch_loop_cmd(struct gsm_subscriber_connection *conn, + enum gsm414_tch_loop_mode loop_mode); +int gsm0414_tx_open_loop_cmd(struct gsm_subscriber_connection *conn); +int gsm0414_tx_act_emmi_cmd(struct gsm_subscriber_connection *conn); +int gsm0414_tx_test_interface(struct gsm_subscriber_connection *conn, + uint8_t tested_devs); +int gsm0414_tx_reset_ms_pos_store(struct gsm_subscriber_connection *conn, + uint8_t technology); + +int gsm0414_rcv_test(struct gsm_subscriber_connection *conn, + struct msgb *msg); diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index c307fee..f4de381 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -323,10 +323,18 @@ GSM_AUTH_POLICY_REGEXP, /* accept IMSIs matching given regexp */ }; -#define GSM_T3101_DEFAULT 10 -#define GSM_T3105_DEFAULT 40 +#define GSM_T3101_DEFAULT 10 /* s */ +#define GSM_T3103_DEFAULT 5 /* s */ +#define GSM_T3105_DEFAULT 100 /* ms */ +#define GSM_T3107_DEFAULT 5 /* s */ +#define GSM_T3109_DEFAULT 19 /* s, must be 2s + radio_link_timeout*0.48 */ +#define GSM_T3111_DEFAULT 2 /* s */ #define GSM_T3113_DEFAULT 60 +#define GSM_T3115_DEFAULT 10 +#define GSM_T3117_DEFAULT 10 +#define GSM_T3119_DEFAULT 10 #define GSM_T3122_DEFAULT 10 +#define GSM_T3141_DEFAULT 10 struct gsm_tz { int override; /* if 0, use system's time zone instead. */ @@ -503,6 +511,8 @@ } smpp; unsigned long validity_minutes; + time_t created; + bool is_report; uint8_t reply_path_req; uint8_t status_rep_req; uint8_t ud_hdr_ind; diff --git a/include/openbsc/gsm_data_shared.h b/include/openbsc/gsm_data_shared.h index 0790807..60da2e5 100644 --- a/include/openbsc/gsm_data_shared.h +++ b/include/openbsc/gsm_data_shared.h @@ -899,7 +899,7 @@ }; -struct gsm_bts *gsm_bts_alloc(void *talloc_ctx); +struct gsm_bts *gsm_bts_alloc(void *talloc_ctx, uint8_t bts_num); struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num); struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts); diff --git a/include/openbsc/osmux.h b/include/openbsc/osmux.h index 0b64a7f..f3ea72a 100644 --- a/include/openbsc/osmux.h +++ b/include/openbsc/osmux.h @@ -11,8 +11,7 @@ }; int osmux_init(int role, struct mgcp_config *cfg); -int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role, - struct in_addr *addr, uint16_t port); +int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port); void osmux_disable_endpoint(struct mgcp_endpoint *endp); void osmux_allocate_cid(struct mgcp_endpoint *endp); void osmux_release_cid(struct mgcp_endpoint *endp); diff --git a/src/gprs/gb_proxy.c b/src/gprs/gb_proxy.c index d95139f..cd38d23 100644 --- a/src/gprs/gb_proxy.c +++ b/src/gprs/gb_proxy.c @@ -1266,8 +1266,7 @@ rc = bssgp_tx_status(BSSGP_CAUSE_PDU_INCOMP_FEAT, NULL, orig_msg); break; default: - LOGP(DGPRS, LOGL_NOTICE, "BSSGP PDU type 0x%02x unknown\n", - pdu_type); + LOGP(DGPRS, LOGL_NOTICE, "BSSGP PDU type %s not supported\n", bssgp_pdu_str(pdu_type)); rate_ctr_inc(&cfg->ctrg-> ctr[GBPROX_GLOB_CTR_PROTO_ERR_SGSN]); rc = bssgp_tx_status(BSSGP_CAUSE_PROTO_ERR_UNSPEC, NULL, orig_msg); @@ -1370,9 +1369,8 @@ /* from BSS to SGSN */ peer = gbproxy_peer_by_nsei(cfg, nsvc->nsei); if (!peer) { - LOGP(DGPRS, LOGL_NOTICE, "signal %u for unknown peer " - "NSEI=%u/NSVCI=%u\n", signal, nsvc->nsei, - nsvc->nsvci); + LOGP(DGPRS, LOGL_NOTICE, "signal '%s' for unknown peer NSEI=%u/NSVCI=%u\n", + get_value_string(gprs_ns_signal_ns_names, signal), nsvc->nsei, nsvc->nsvci); return 0; } switch (signal) { @@ -1380,9 +1378,8 @@ case S_NS_BLOCK: if (!peer->blocked) break; - LOGP(DGPRS, LOGL_NOTICE, "Converting NS_RESET from " - "NSEI=%u/NSVCI=%u into BSSGP_BVC_BLOCK to SGSN\n", - nsvc->nsei, nsvc->nsvci); + LOGP(DGPRS, LOGL_NOTICE, "Converting '%s' from NSEI=%u/NSVCI=%u into BSSGP_BVC_BLOCK to SGSN\n", + get_value_string(gprs_ns_signal_ns_names, signal), nsvc->nsei, nsvc->nsvci); bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK, nsvc->nsei, peer->bvci, 0); break; @@ -1431,6 +1428,10 @@ INIT_LLIST_HEAD(&cfg->bts_peers); cfg->ctrg = rate_ctr_group_alloc(tall_bsc_ctx, &global_ctrg_desc, 0); + if (!cfg->ctrg) { + LOGP(DGPRS, LOGL_ERROR, "Cannot allocate global counter group!\n"); + return -1; + } clock_gettime(CLOCK_REALTIME, &tp); return 0; diff --git a/src/gprs/gb_proxy_main.c b/src/gprs/gb_proxy_main.c index 69a93b6..caff27f 100644 --- a/src/gprs/gb_proxy_main.c +++ b/src/gprs/gb_proxy_main.c @@ -98,6 +98,7 @@ switch (signal) { case SIGINT: + case SIGTERM: osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); sleep(1); exit(0); @@ -232,6 +233,7 @@ msgb_talloc_ctx_init(tall_bsc_ctx, 0); signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); diff --git a/src/gprs/gb_proxy_patch.c b/src/gprs/gb_proxy_patch.c index 7bddc44..210fb2b 100644 --- a/src/gprs/gb_proxy_patch.c +++ b/src/gprs/gb_proxy_patch.c @@ -28,6 +28,7 @@ #include <osmocom/gprs/protocol/gsm_08_18.h> #include <osmocom/core/rate_ctr.h> +#include <osmocom/gsm/apn.h> /* patch RA identifier in place */ static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer, @@ -101,7 +102,7 @@ LOGP(DGPRS, LOGL_DEBUG, "Patching %s to SGSN: Removing APN '%s'\n", log_text, - gprs_apn_to_str(str1, apn, apn_len)); + osmo_apn_to_str(str1, apn, apn_len)); *new_apn_ie_len = 0; gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0); @@ -116,8 +117,8 @@ "Patching %s to SGSN: " "Replacing APN '%s' -> '%s'\n", log_text, - gprs_apn_to_str(str1, apn, apn_len), - gprs_apn_to_str(str2, peer->cfg->core_apn, + osmo_apn_to_str(str1, apn, apn_len), + osmo_apn_to_str(str2, peer->cfg->core_apn, peer->cfg->core_apn_size)); *new_apn_ie_len = peer->cfg->core_apn_size + 2; diff --git a/src/gprs/gb_proxy_peer.c b/src/gprs/gb_proxy_peer.c index 5365ff0..8909687 100644 --- a/src/gprs/gb_proxy_peer.c +++ b/src/gprs/gb_proxy_peer.c @@ -177,6 +177,10 @@ peer->bvci = bvci; peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci); + if (!peer->ctrg) { + talloc_free(peer); + return NULL; + } peer->cfg = cfg; llist_add(&peer->list, &cfg->bts_peers); diff --git a/src/gprs/gb_proxy_vty.c b/src/gprs/gb_proxy_vty.c index 933b6b0..86d65a8 100644 --- a/src/gprs/gb_proxy_vty.c +++ b/src/gprs/gb_proxy_vty.c @@ -29,6 +29,7 @@ #include <openbsc/gsm_04_08.h> #include <osmocom/gprs/gprs_ns.h> +#include <osmocom/gsm/apn.h> #include <openbsc/debug.h> #include <openbsc/gb_proxy.h> @@ -107,7 +108,7 @@ if (g_cfg->core_apn_size > 0) { char str[500] = {0}; vty_out(vty, " core-access-point-name %s%s", - gprs_apn_to_str(str, g_cfg->core_apn, + osmo_apn_to_str(str, g_cfg->core_apn, g_cfg->core_apn_size), VTY_NEWLINE); } else { diff --git a/src/gprs/gprs_sgsn.c b/src/gprs/gprs_sgsn.c index 18625ae..43eeaaa 100644 --- a/src/gprs/gprs_sgsn.c +++ b/src/gprs/gprs_sgsn.c @@ -30,6 +30,7 @@ #include <osmocom/gprs/gprs_ns.h> #include <osmocom/gprs/gprs_bssgp.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> +#include <osmocom/gsm/apn.h> #include <openbsc/gprs_subscriber.h> #include <openbsc/debug.h> @@ -129,6 +130,7 @@ void sgsn_rate_ctr_init() { sgsn->rate_ctrs = rate_ctr_group_alloc(tall_bsc_ctx, &sgsn_ctrg_desc, 0); + OSMO_ASSERT(sgsn->rate_ctrs); } /* look-up an SGSN MM context based on Iu UE context (struct ue_conn_ctx)*/ @@ -229,6 +231,11 @@ LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n", get_value_string(gprs_cipher_names, ctx->ciph_algo)); ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli); + if (!ctx->ctrg) { + LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n"); + talloc_free(ctx); + return NULL; + } INIT_LLIST_HEAD(&ctx->pdp_list); llist_add(&ctx->list, &sgsn_mm_ctxts); @@ -253,6 +260,11 @@ ctx->pmm_state = PMM_DETACHED; ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0); + if (!ctx->ctrg) { + LOGMMCTXP(LOGL_ERROR, ctx, "Cannot allocate counter group\n"); + talloc_free(ctx); + return NULL; + } /* Need to get RAID from IU conn */ ctx->ra = ctx->iu.ue_ctx->ra_id; @@ -380,6 +392,11 @@ pdp->mm = mm; pdp->nsapi = nsapi; pdp->ctrg = rate_ctr_group_alloc(pdp, &pdpctx_ctrg_desc, nsapi); + if (!pdp->ctrg) { + LOGPDPCTXP(LOGL_ERROR, pdp, "Error allocation counter group\n"); + talloc_free(pdp); + return NULL; + } llist_add(&pdp->list, &mm->pdp_list); llist_add(&pdp->g_list, &sgsn_pdp_ctxts); @@ -699,10 +716,21 @@ sgsn_auth_update(mmctx); } -static void insert_qos(struct tlv_parsed *tp, struct sgsn_subscriber_pdp_data *pdp) +static void insert_extra(struct tlv_parsed *tp, + struct sgsn_subscriber_data *data, + struct sgsn_subscriber_pdp_data *pdp) { tp->lv[OSMO_IE_GSM_SUB_QOS].len = pdp->qos_subscribed_len; tp->lv[OSMO_IE_GSM_SUB_QOS].val = pdp->qos_subscribed; + + /* Prefer PDP charging characteristics of per subscriber one */ + if (pdp->has_pdp_charg) { + tp->lv[OSMO_IE_GSM_CHARG_CHAR].len = sizeof(pdp->pdp_charg); + tp->lv[OSMO_IE_GSM_CHARG_CHAR].val = &pdp->pdp_charg[0]; + } else if (data->has_pdp_charg) { + tp->lv[OSMO_IE_GSM_CHARG_CHAR].len = sizeof(data->pdp_charg); + tp->lv[OSMO_IE_GSM_CHARG_CHAR].val = &data->pdp_charg[0]; + } } /** @@ -731,7 +759,7 @@ return NULL; } - gprs_apn_to_str(req_apn_str, + osmo_apn_to_str(req_apn_str, TLVP_VAL(tp, GSM48_IE_GSM_APN), TLVP_LEN(tp, GSM48_IE_GSM_APN)); @@ -751,7 +779,7 @@ { allow_any_apn = 1; selected_apn_str = ""; - insert_qos(tp, pdp); + insert_extra(tp, mmctx->subscr->sgsn_data, pdp); continue; } if (!llist_empty(&sgsn_apn_ctxts)) { @@ -760,7 +788,7 @@ if (apn_ctx == NULL) continue; } - insert_qos(tp, pdp); + insert_extra(tp, mmctx->subscr->sgsn_data, pdp); selected_apn_str = pdp->apn_str; break; } @@ -768,13 +796,13 @@ /* Check whether the given APN is granted */ llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) { if (strcmp(pdp->apn_str, "*") == 0) { - insert_qos(tp, pdp); + insert_extra(tp, mmctx->subscr->sgsn_data, pdp); selected_apn_str = req_apn_str; allow_any_apn = 1; continue; } if (strcasecmp(pdp->apn_str, req_apn_str) == 0) { - insert_qos(tp, pdp); + insert_extra(tp, mmctx->subscr->sgsn_data, pdp); selected_apn_str = req_apn_str; break; } diff --git a/src/gprs/gprs_subscriber.c b/src/gprs/gprs_subscriber.c index 176583b..94297d0 100644 --- a/src/gprs/gprs_subscriber.c +++ b/src/gprs/gprs_subscriber.c @@ -22,6 +22,7 @@ #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> #include <osmocom/gsm/gsup.h> +#include <osmocom/gsm/apn.h> #include <osmocom/core/utils.h> #include <osmocom/core/logging.h> #include <openbsc/gprs_subscriber.h> @@ -325,6 +326,13 @@ } } + if (gsup_msg->pdp_charg_enc && gsup_msg->pdp_charg_enc_len >= sizeof(sdata->pdp_charg)) { + memcpy(&sdata->pdp_charg, gsup_msg->pdp_charg_enc, sizeof(sdata->pdp_charg)); + sdata->has_pdp_charg = 1; + } else { + sdata->has_pdp_charg = 0; + } + if (gsup_msg->pdp_info_compl) { rc = gprs_subscr_pdp_data_clear(subscr); if (rc > 0) @@ -364,10 +372,17 @@ OSMO_ASSERT(pdp_data != NULL); pdp_data->pdp_type = pdp_info->pdp_type; - gprs_apn_to_str(pdp_data->apn_str, + osmo_apn_to_str(pdp_data->apn_str, pdp_info->apn_enc, pdp_info->apn_enc_len); memcpy(pdp_data->qos_subscribed, pdp_info->qos_enc, pdp_info->qos_enc_len); pdp_data->qos_subscribed_len = pdp_info->qos_enc_len; + + if (pdp_info->pdp_charg_enc && pdp_info->pdp_charg_enc_len >= sizeof(pdp_data->pdp_charg)) { + memcpy(&pdp_data->pdp_charg, pdp_info->pdp_charg_enc, sizeof(pdp_data->pdp_charg)); + pdp_data->has_pdp_charg = 1; + } else { + pdp_data->has_pdp_charg = 0; + } } } diff --git a/src/gprs/gprs_utils.c b/src/gprs/gprs_utils.c index 64ed978..91a09d2 100644 --- a/src/gprs/gprs_utils.c +++ b/src/gprs/gprs_utils.c @@ -114,34 +114,6 @@ return 0; } -/* TODO: Move these conversion functions to a utils file. */ -/* TODO: consolidate with gprs_apn2str(). */ -/** memmove apn_enc to out_str, replacing the length octets in apn_enc with '.' - * (omitting the first one) and terminating with a '\0'. - * out_str needs to have rest_chars amount of bytes or 1 whatever is bigger. - */ -char * gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars) -{ - char *str = out_str; - - while (rest_chars > 0 && apn_enc[0]) { - size_t label_size = apn_enc[0]; - if (label_size + 1 > rest_chars) - return NULL; - - memmove(str, apn_enc + 1, label_size); - str += label_size; - rest_chars -= label_size + 1; - apn_enc += label_size + 1; - - if (rest_chars) - *(str++) = '.'; - } - str[0] = '\0'; - - return out_str; -} - int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str) { uint8_t *last_len_field; diff --git a/src/gprs/gtphub.c b/src/gprs/gtphub.c index 211018b..0a8e375 100644 --- a/src/gprs/gtphub.c +++ b/src/gprs/gtphub.c @@ -42,6 +42,8 @@ #include <osmocom/core/rate_ctr.h> #include <osmocom/core/stats.h> +#include <osmocom/gsm/apn.h> + static const int GTPH_GC_TICK_SECONDS = 1; @@ -498,7 +500,7 @@ len = sizeof(apn_buf) - 1; apn_buf[len] = '\0'; - *apn_str = gprs_apn_to_str(apn_buf, (uint8_t*)apn_buf, len); + *apn_str = osmo_apn_to_str(apn_buf, (uint8_t*)apn_buf, len); if (!(*apn_str)) { LOG(LOGL_ERROR, "APN IE: present but cannot be decoded: %s\n", osmo_hexdump((uint8_t*)apn_buf, len)); @@ -2708,6 +2710,10 @@ pp->counters_io = rate_ctr_group_alloc(osmo_gtphub_ctx, >phub_ctrg_io_desc, 0); + if (!pp->counters_io) { + talloc_free(pp); + return NULL; + } llist_add(&pp->entry, &a->ports); diff --git a/src/gprs/gtphub_main.c b/src/gprs/gtphub_main.c index 73a122c..2b87d19 100644 --- a/src/gprs/gtphub_main.c +++ b/src/gprs/gtphub_main.c @@ -96,6 +96,7 @@ switch (signal) { case SIGINT: + case SIGTERM: osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); sleep(1); exit(0); @@ -302,6 +303,7 @@ msgb_talloc_ctx_init(osmo_gtphub_ctx, 0); signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); diff --git a/src/gprs/sgsn_cdr.c b/src/gprs/sgsn_cdr.c index 0910896..16ea9d4 100644 --- a/src/gprs/sgsn_cdr.c +++ b/src/gprs/sgsn_cdr.c @@ -22,6 +22,7 @@ #include <openbsc/signal.h> #include <openbsc/gprs_utils.h> #include <openbsc/debug.h> +#include <osmocom/gsm/apn.h> #include <openbsc/vty.h> @@ -145,7 +146,7 @@ if (pdp->lib) { - gprs_apn_to_str(apni, pdp->lib->apn_use.v, pdp->lib->apn_use.l); + osmo_apn_to_str(apni, pdp->lib->apn_use.v, pdp->lib->apn_use.l); inet_ntop(AF_INET, &pdp->lib->hisaddr0.s_addr, ggsn_addr, sizeof(ggsn_addr)); extract_eua(&pdp->lib->eua, eua_addr); } diff --git a/src/gprs/sgsn_libgtp.c b/src/gprs/sgsn_libgtp.c index 7595bf8..7ff8ece 100644 --- a/src/gprs/sgsn_libgtp.c +++ b/src/gprs/sgsn_libgtp.c @@ -234,6 +234,10 @@ memcpy(pdp->qos_req.v, qos, pdp->qos_req.l); } + /* charging characteristics if present */ + if (TLVP_LEN(tp, OSMO_IE_GSM_CHARG_CHAR) >= sizeof(pdp->cch_pdp)) + pdp->cch_pdp = tlvp_val16be(tp, OSMO_IE_GSM_CHARG_CHAR); + /* SGSN address for control plane */ pdp->gsnlc.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr); memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr, @@ -247,18 +251,28 @@ memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr, sizeof(sgsn->cfg.gtp_listenaddr.sin_addr)); - /* Routing Area Identifier with LAC and RAC fixed values, as - * requested in 29.006 7.3.1 */ + /* Encode RAT Type according to TS 29.060 7.7.50 */ + pdp->rattype.l = 1; + if (mmctx->ran_type == MM_CTX_T_UTRAN_Iu) + pdp->rattype.v[0] = 1; + else + pdp->rattype.v[0] = 2; + pdp->rattype_given = 1; + + /* Include RAI and ULI all the time */ pdp->rai_given = 1; pdp->rai.l = 6; + + /* Routing Area Identifier with LAC and RAC fixed values, as + * requested in 29.006 7.3.1 */ raid = mmctx->ra; raid.lac = 0xFFFE; raid.rac = 0xFF; gsm48_construct_ra(pdp->rai.v, &raid); - pdp->rattype.l = 1; - pdp->rattype_given = 1; - + /* Encode User Location Information accordint to TS 29.060 7.7.51 */ + pdp->userloc_given = 1; + pdp->userloc.l = 8; switch (mmctx->ran_type) { case MM_CTX_T_GERAN_Gb: case MM_CTX_T_GERAN_Iu: @@ -270,8 +284,9 @@ bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->gb.cell_id); break; case MM_CTX_T_UTRAN_Iu: - pdp->rattype.v[0] = 1; - /* FIXME: Optional User Location Information with SAI */ + pdp->userloc.v[0] = 1; /* SAI for UTRAN */ + /* SAI is like CGI but with SAC instead of CID, so we can abuse this function */ + bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->iu.sac); break; } diff --git a/src/gprs/sgsn_main.c b/src/gprs/sgsn_main.c index 71cb18c..d5d43ad 100644 --- a/src/gprs/sgsn_main.c +++ b/src/gprs/sgsn_main.c @@ -145,6 +145,7 @@ switch (signal) { case SIGINT: + case SIGTERM: osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); sleep(1); exit(0); @@ -332,6 +333,7 @@ msgb_talloc_ctx_init(tall_bsc_ctx, 0); signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); diff --git a/src/gprs/sgsn_vty.c b/src/gprs/sgsn_vty.c index 888f53a..cf44cc4 100644 --- a/src/gprs/sgsn_vty.c +++ b/src/gprs/sgsn_vty.c @@ -28,6 +28,7 @@ #include <osmocom/core/utils.h> #include <osmocom/core/rate_ctr.h> #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> +#include <osmocom/gsm/apn.h> #include <openbsc/debug.h> #include <openbsc/sgsn.h> @@ -116,7 +117,6 @@ #define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */ -/* TODO: consolidate with gprs_apn_to_str(). */ /** Copy apn to a static buffer, replacing the length octets in apn_enc with '.' * and terminating with a '\0'. Return the static buffer. * len: the length of the encoded APN (which has no terminating zero). @@ -124,23 +124,10 @@ static char *gprs_apn2str(uint8_t *apn, unsigned int len) { static char apnbuf[GSM48_MAX_APN_LEN+1]; - unsigned int i = 0; if (!apn) return ""; - - if (len > sizeof(apnbuf)-1) - len = sizeof(apnbuf)-1; - - memcpy(apnbuf, apn, len); - apnbuf[len] = '\0'; - - /* replace the domain name step sizes with dots */ - while (i < len) { - unsigned int step = apnbuf[i]; - apnbuf[i] = '.'; - i += step+1; - } + osmo_apn_to_str(apnbuf, apn, len); return apnbuf+1; } @@ -468,20 +455,22 @@ const char *imsi = pdp->mm ? pdp->mm->imsi : "(detaching)"; vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u, TI: %u%s", pfx, imsi, pdp->sapi, pdp->nsapi, pdp->ti, VTY_NEWLINE); - vty_out(vty, "%s APN: %s%s", pfx, - gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l), - VTY_NEWLINE); - vty_out(vty, "%s PDP Address: %s%s", pfx, - gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l), - VTY_NEWLINE); - vty_out(vty, "%s GTP Local Control(%s / TEIC: 0x%08x) ", pfx, - gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own); - vty_out(vty, "Data(%s / TEID: 0x%08x)%s", - gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE); - vty_out(vty, "%s GTP Remote Control(%s / TEIC: 0x%08x) ", pfx, - gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn); - vty_out(vty, "Data(%s / TEID: 0x%08x)%s", - gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE); + if (pdp->lib) { + vty_out(vty, "%s APN: %s%s", pfx, + gprs_apn2str(pdp->lib->apn_use.v, pdp->lib->apn_use.l), + VTY_NEWLINE); + vty_out(vty, "%s PDP Address: %s%s", pfx, + gprs_pdpaddr2str(pdp->lib->eua.v, pdp->lib->eua.l), + VTY_NEWLINE); + vty_out(vty, "%s GTP Local Control(%s / TEIC: 0x%08x) ", pfx, + gtp_ntoa(&pdp->lib->gsnlc), pdp->lib->teic_own); + vty_out(vty, "Data(%s / TEID: 0x%08x)%s", + gtp_ntoa(&pdp->lib->gsnlu), pdp->lib->teid_own, VTY_NEWLINE); + vty_out(vty, "%s GTP Remote Control(%s / TEIC: 0x%08x) ", pfx, + gtp_ntoa(&pdp->lib->gsnrc), pdp->lib->teic_gn); + vty_out(vty, "Data(%s / TEID: 0x%08x)%s", + gtp_ntoa(&pdp->lib->gsnru), pdp->lib->teid_gn, VTY_NEWLINE); + } vty_out_rate_ctr_group(vty, " ", pdp->ctrg); } diff --git a/src/libbsc/abis_nm.c b/src/libbsc/abis_nm.c index 019d039..cf20d7c 100644 --- a/src/libbsc/abis_nm.c +++ b/src/libbsc/abis_nm.c @@ -1590,10 +1590,17 @@ const uint8_t *attr, uint8_t attr_len) { struct abis_om_hdr *oh; - struct msgb *msg = nm_msgb_alloc(); + struct msgb *msg; + + if (bts->type != GSM_BTS_TYPE_OSMOBTS) { + LOGPC(DNM, LOGL_NOTICE, "Getting attributes from BTS%d type %s is not supported.\n", + bts->nr, btstype2str(bts->type)); + return -EINVAL; + } DEBUGP(DNM, "Get Attr (bts=%d)\n", bts->nr); + msg = nm_msgb_alloc(); oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE); fill_om_fom_hdr(oh, attr_len, NM_MT_GET_ATTR, obj_class, bts_nr, trx_nr, ts_nr); diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c index 441b386..4f687a0 100644 --- a/src/libbsc/abis_rsl.c +++ b/src/libbsc/abis_rsl.c @@ -245,12 +245,14 @@ && type == RSL_SYSTEM_INFO_13) { /* Ericsson proprietary encoding of SI13 */ msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, RSL_ERIC_SYSTEM_INFO_13); - msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); + if (data) + msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); msgb_tv_put(msg, RSL_IE_ERIC_BCCH_MAPPING, 0x00); } else { /* Normal encoding */ msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); + if (data) + msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data); } msg->dst = trx->rsl_link; @@ -269,7 +271,8 @@ ch->msg_type = RSL_MT_SACCH_FILL; msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); + if (data) + msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); msg->dst = trx->rsl_link; @@ -288,7 +291,8 @@ dh->chan_nr = chan_nr; msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type); - msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); + if (data) + msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data); msg->dst = lchan->ts->trx->rsl_link; @@ -2446,7 +2450,7 @@ dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh)); init_dchan_hdr(dh, msg_type); dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN; - dh->chan_nr = gsm_pchan2chan_nr(GSM_PCHAN_PDCH, ts->nr, 0); + dh->chan_nr = gsm_pchan2chan_nr(GSM_PCHAN_TCH_F, ts->nr, 0); DEBUGP(DRSL, "%s IPAC PDCH %sACT\n", gsm_ts_name(ts), act ? "" : "DE"); @@ -2905,10 +2909,6 @@ int rsl_start_t3109(struct gsm_lchan *lchan) { struct gsm_bts *bts = lchan->ts->trx->bts; - - /* Disabled, mostly legacy code */ - if (bts->network->T3109 == 0) - return -1; osmo_timer_setup(&lchan->T3109, t3109_expired, lchan); osmo_timer_schedule(&lchan->T3109, bts->network->T3109, 0); diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c index c2828e3..c60f818 100644 --- a/src/libbsc/bsc_api.c +++ b/src/libbsc/bsc_api.c @@ -607,7 +607,7 @@ break; case GSM48_MT_RR_STATUS: LOGP(DRR, LOGL_NOTICE, "%s (cause: %s)\n", - gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ), + gsm48_rr_msg_name(GSM48_MT_RR_STATUS), rr_cause_name(gh->data[0])); break; case GSM48_MT_RR_MEAS_REP: diff --git a/src/libbsc/bsc_init.c b/src/libbsc/bsc_init.c index 64dcd15..78ca2ab 100644 --- a/src/libbsc/bsc_init.c +++ b/src/libbsc/bsc_init.c @@ -104,8 +104,11 @@ struct gsm_bts *bts = trx->bts; int rc, j; - DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i), - osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN)); + if (si_len) { + DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i), + osmo_hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN)); + } else + DEBUGP(DRR, "SI%s: OFF\n", get_value_string(osmo_sitype_strs, i)); switch (i) { case SYSINFO_TYPE_5: @@ -113,14 +116,18 @@ case SYSINFO_TYPE_5ter: case SYSINFO_TYPE_6: rc = rsl_sacch_filling(trx, osmo_sitype2rsl(i), - GSM_BTS_SI(bts, i), si_len); + si_len ? GSM_BTS_SI(bts, i) : NULL, si_len); break; case SYSINFO_TYPE_2quater: + if (si_len == 0) { + rc = rsl_bcch_info(trx, i, NULL, 0); + break; + } for (j = 0; j <= bts->si2q_count; j++) rc = rsl_bcch_info(trx, i, (const uint8_t *)GSM_BTS_SI2Q(bts, j), GSM_MACBLOCK_LEN); break; default: - rc = rsl_bcch_info(trx, i, GSM_BTS_SI(bts, i), si_len); + rc = rsl_bcch_info(trx, i, si_len ? GSM_BTS_SI(bts, i) : NULL, si_len); break; } @@ -139,8 +146,8 @@ ms_pwr_ctl_lvl(bts->band, bts->ms_max_power); bts->si_common.cell_sel_par.neci = bts->network->neci; - /* Zero, forget the state of the SIs */ - bts->si_valid = 0; + /* Zero/forget the state of the dynamically computed SIs, leeping the static ones */ + bts->si_valid = bts->si_mode_static; /* First, we determine which of the SI messages we actually need */ @@ -193,9 +200,13 @@ for (n = 0; n < n_si; n++) { i = gen_si[n]; + /* if we don't currently have this SI, we send a zero-length + * RSL BCCH FILLING / SACCH FILLING * in order to deactivate + * the SI, in case it might have previously been active */ if (!GSM_BTS_HAS_SI(bts, i)) - continue; - rc = rsl_si(trx, i, si_len[i]); + rc = rsl_si(trx, i, 0); + else + rc = rsl_si(trx, i, si_len[i]); if (rc < 0) return rc; } @@ -350,12 +361,12 @@ generate_cell_chan_list(ca, trx->bts); /* Request generic BTS-level attributes */ - abis_nm_get_attr(trx->bts, NM_OC_BTS, trx->bts->nr, trx->nr, 0xFF, bts_attr, sizeof(bts_attr)); + abis_nm_get_attr(trx->bts, NM_OC_BTS, 0xFF, 0xFF, 0xFF, bts_attr, sizeof(bts_attr)); llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) { int i; /* Request TRX-level attributes */ - abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, cur_trx->bts->nr, cur_trx->nr, 0xFF, + abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, 0, cur_trx->nr, 0xFF, trx_attr, sizeof(trx_attr)); for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++) generate_ma_for_ts(&cur_trx->ts[i]); diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c index 722753a..bd363ae 100644 --- a/src/libbsc/bsc_vty.c +++ b/src/libbsc/bsc_vty.c @@ -30,6 +30,7 @@ #include <osmocom/vty/misc.h> #include <osmocom/gsm/protocol/gsm_04_08.h> #include <osmocom/gsm/gsm0502.h> +#include <osmocom/ctrl/control_if.h> #include <arpa/inet.h> @@ -776,6 +777,11 @@ return CMD_SUCCESS; } +/* small helper macro for conditional dumping of timer */ +#define VTY_OUT_TIMER(number) \ + if (gsmnet->T##number != GSM_T##number##_DEFAULT) \ + vty_out(vty, " timer t"#number" %u%s", gsmnet->T##number, VTY_NEWLINE) + static int config_write_net(struct vty *vty) { struct gsm_network *gsmnet = gsmnet_from_vty(vty); @@ -812,18 +818,18 @@ gsmnet->handover.pwr_hysteresis, VTY_NEWLINE); vty_out(vty, " handover maximum distance %u%s", gsmnet->handover.max_distance, 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 t3122 %u%s", gsmnet->T3122, VTY_NEWLINE); - vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); + VTY_OUT_TIMER(3101); + VTY_OUT_TIMER(3103); + VTY_OUT_TIMER(3105); + VTY_OUT_TIMER(3107); + VTY_OUT_TIMER(3109); + VTY_OUT_TIMER(3111); + VTY_OUT_TIMER(3113); + VTY_OUT_TIMER(3115); + VTY_OUT_TIMER(3117); + VTY_OUT_TIMER(3119); + VTY_OUT_TIMER(3122); + VTY_OUT_TIMER(3141); vty_out(vty, " dyn_ts_allow_tch_f %d%s", gsmnet->dyn_ts_allow_tch_f ? 1 : 0, VTY_NEWLINE); if (gsmnet->tz.override != 0) { @@ -1534,38 +1540,43 @@ return CMD_SUCCESS; } +#define DEFAULT_TIMER(number) GSM_T##number##_DEFAULT +/* Add another expansion so that DEFAULT_TIMER() becomes its value */ +#define EXPAND_AND_STRINGIFY(x) OSMO_STRINGIFY(x) + #define DECLARE_TIMER(number, doc) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ - "timer t" #number " <0-65535>", \ + "timer t" #number " (default|<1-65535>)", \ "Configure GSM Timers\n" \ - doc "Timer Value in seconds\n") \ + doc " (default: " EXPAND_AND_STRINGIFY(DEFAULT_TIMER(number)) " seconds)\n" \ + "Set to default timer value" \ + " (" EXPAND_AND_STRINGIFY(DEFAULT_TIMER(number)) " seconds)\n" \ + "Timer Value in seconds\n") \ { \ struct gsm_network *gsmnet = gsmnet_from_vty(vty); \ - 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; \ - } \ + int value; \ + if (strcmp(argv[0], "default") == 0) \ + value = DEFAULT_TIMER(number); \ + else \ + value = atoi(argv[0]); \ \ gsmnet->T##number = value; \ return CMD_SUCCESS; \ } -DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n") -DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n") -DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n") -DECLARE_TIMER(3107, "Currently not used.\n") -DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n") -DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n") -DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n") -DECLARE_TIMER(3115, "Currently not used.\n") -DECLARE_TIMER(3117, "Currently not used.\n") -DECLARE_TIMER(3119, "Currently not used.\n") -DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n") -DECLARE_TIMER(3141, "Currently not used.\n") +DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT") +DECLARE_TIMER(3103, "Set the timeout value for HANDOVER") +DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION") +DECLARE_TIMER(3107, "Currently not used") +DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout") +DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel") +DECLARE_TIMER(3113, "Set the time to try paging a subscriber") +DECLARE_TIMER(3115, "Currently not used") +DECLARE_TIMER(3117, "Currently not used") +DECLARE_TIMER(3119, "Currently not used") +DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT") +DECLARE_TIMER(3141, "Currently not used") DEFUN_DEPRECATED(cfg_net_dtx, cfg_net_dtx_cmd, @@ -3801,6 +3812,38 @@ return CMD_SUCCESS; } +DEFUN(bts_resend, bts_resend_cmd, + "bts <0-255> resend-system-information", + "BTS Specific Commands\n" "BTS Number\n" + "Re-generate + re-send BCCH SYSTEM INFORMATION\n") +{ + struct gsm_network *gsmnet; + struct gsm_bts_trx *trx; + struct gsm_bts *bts; + unsigned int bts_nr; + + gsmnet = gsmnet_from_vty(vty); + + bts_nr = atoi(argv[0]); + if (bts_nr >= gsmnet->num_bts) { + vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s", + gsmnet->num_bts, bts_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + bts = gsm_bts_num(gsmnet, bts_nr); + if (!bts) { + vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE); + return CMD_WARNING; + } + + llist_for_each_entry_reverse(trx, &bts->trx_list, list) + gsm_bts_trx_set_system_infos(trx); + + return CMD_SUCCESS; +} + + DEFUN(smscb_cmd, smscb_cmd_cmd, "bts <0-255> smscb-command <1-4> HEXSTRING", "BTS related commands\n" "BTS Number\n" @@ -4061,6 +4104,20 @@ rsl_ipacc_mdcx(lchan, ntohl(ia.s_addr), port, 0); return CMD_SUCCESS; } + +DEFUN(ctrl_trap, ctrl_trap_cmd, + "ctrl-interface generate-trap TRAP VALUE", + "Commands related to the CTRL Interface\n" + "Generate a TRAP for test purpose\n" + "Identity/Name of the TRAP variable\n" + "Value of the TRAP variable\n") +{ + struct gsm_network *net = gsmnet_from_vty(vty); + + ctrl_cmd_send_trap(net->ctrl, argv[0], (char *) argv[1]); + return CMD_SUCCESS; +} + extern int bsc_vty_init_extra(void); int bsc_vty_init(struct gsm_network *network) @@ -4256,10 +4313,12 @@ install_element(ENABLE_NODE, &drop_bts_cmd); install_element(ENABLE_NODE, &restart_bts_cmd); + install_element(ENABLE_NODE, &bts_resend_cmd); install_element(ENABLE_NODE, &pdch_act_cmd); install_element(ENABLE_NODE, &lchan_act_cmd); install_element(ENABLE_NODE, &lchan_mdcx_cmd); install_element(ENABLE_NODE, &smscb_cmd_cmd); + install_element(ENABLE_NODE, &ctrl_trap_cmd); abis_nm_vty_init(); abis_om2k_vty_init(); diff --git a/src/libbsc/handover_logic.c b/src/libbsc/handover_logic.c index c03563f..57d1dcd 100644 --- a/src/libbsc/handover_logic.c +++ b/src/libbsc/handover_logic.c @@ -282,6 +282,7 @@ new_lchan->conn->ho_lchan = NULL; new_lchan->conn->lchan = new_lchan; + new_lchan->conn->bts = new_lchan->ts->trx->bts; ho->old_lchan->conn = NULL; lchan_release(ho->old_lchan, 0, RSL_REL_LOCAL_END); diff --git a/src/libbsc/net_init.c b/src/libbsc/net_init.c index bc5ed35..9d54319 100644 --- a/src/libbsc/net_init.c +++ b/src/libbsc/net_init.c @@ -44,10 +44,17 @@ net->num_bts = 0; net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED; net->T3101 = GSM_T3101_DEFAULT; + net->T3103 = GSM_T3103_DEFAULT; net->T3105 = GSM_T3105_DEFAULT; + net->T3107 = GSM_T3107_DEFAULT; + net->T3109 = GSM_T3109_DEFAULT; + net->T3111 = GSM_T3111_DEFAULT; net->T3113 = GSM_T3113_DEFAULT; + net->T3115 = GSM_T3115_DEFAULT; + net->T3117 = GSM_T3117_DEFAULT; + net->T3119 = GSM_T3119_DEFAULT; net->T3122 = GSM_T3122_DEFAULT; - /* FIXME: initialize all other timers! */ + net->T3141 = GSM_T3141_DEFAULT; /* default set of handover parameters */ net->handover.win_rxlev_avg = 10; @@ -61,6 +68,10 @@ /* init statistics */ net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0); + if (!net->bsc_ctrs) { + talloc_free(net); + return NULL; + } gsm_net_update_ctype(net); diff --git a/src/libcommon-cs/common_cs.c b/src/libcommon-cs/common_cs.c index 8e19bb2..99206c8 100644 --- a/src/libcommon-cs/common_cs.c +++ b/src/libcommon-cs/common_cs.c @@ -68,6 +68,10 @@ /* init statistics */ net->msc_ctrs = rate_ctr_group_alloc(net, &msc_ctrg_desc, 0); + if (!net->msc_ctrs) { + talloc_free(net); + return NULL; + } net->active_calls = osmo_counter_alloc("msc.active_calls"); net->mncc_recv = mncc_recv; diff --git a/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c index b5bf059..7be2240 100644 --- a/src/libcommon/gsm_data.c +++ b/src/libcommon/gsm_data.c @@ -254,12 +254,13 @@ if (!model && type != GSM_BTS_TYPE_UNKNOWN) return NULL; - bts = gsm_bts_alloc(net); + bts = gsm_bts_alloc(net, net->num_bts); if (!bts) return NULL; + net->num_bts++; + bts->network = net; - bts->nr = net->num_bts++; bts->type = type; bts->model = model; bts->bsic = bsic; diff --git a/src/libcommon/gsm_data_shared.c b/src/libcommon/gsm_data_shared.c index 8992636..2696273 100644 --- a/src/libcommon/gsm_data_shared.c +++ b/src/libcommon/gsm_data_shared.c @@ -312,7 +312,7 @@ .initial_mcs = 6, }; -struct gsm_bts *gsm_bts_alloc(void *ctx) +struct gsm_bts *gsm_bts_alloc(void *ctx, uint8_t bts_num) { struct gsm_bts *bts = talloc_zero(ctx, struct gsm_bts); int i; @@ -320,6 +320,7 @@ if (!bts) return NULL; + bts->nr = bts_num; bts->num_trx = 0; INIT_LLIST_HEAD(&bts->trx_list); bts->ms_max_power = 15; /* dBm */ @@ -643,11 +644,14 @@ switch (pchan) { case GSM_PCHAN_TCH_F: - case GSM_PCHAN_PDCH: case GSM_PCHAN_TCH_F_PDCH: OSMO_ASSERT(lchan_nr == 0); cbits = 0x01; break; + case GSM_PCHAN_PDCH: + OSMO_ASSERT(lchan_nr == 0); + cbits = RSL_CHAN_OSMO_PDCH >> 3; + break; case GSM_PCHAN_TCH_H: OSMO_ASSERT(lchan_nr < 2); cbits = 0x02; diff --git a/src/libmgcp/mgcp_osmux.c b/src/libmgcp/mgcp_osmux.c index b46a80e..c52984b 100644 --- a/src/libmgcp/mgcp_osmux.c +++ b/src/libmgcp/mgcp_osmux.c @@ -340,8 +340,7 @@ if (endp->osmux.state == OSMUX_STATE_ENABLED) goto out; - if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC_NAT, - &addr->sin_addr, addr->sin_port) < 0 ){ + if (osmux_enable_endpoint(endp, &addr->sin_addr, addr->sin_port) < 0 ) { LOGP(DMGCP, LOGL_ERROR, "Could not enable osmux in endpoint %d\n", ENDPOINT_NUMBER(endp)); @@ -433,8 +432,7 @@ return 0; } -int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role, - struct in_addr *addr, uint16_t port) +int osmux_enable_endpoint(struct mgcp_endpoint *endp, struct in_addr *addr, uint16_t port) { /* If osmux is enabled, initialize the output handler. This handler is * used to reconstruct the RTP flow from osmux. The RTP SSRC is @@ -522,8 +520,7 @@ return 0; if (endp->osmux.state == OSMUX_STATE_ACTIVATING) { - if (osmux_enable_endpoint(endp, OSMUX_ROLE_BSC, - &endp->net_end.addr, + if (osmux_enable_endpoint(endp, &endp->net_end.addr, htons(endp->cfg->osmux_port)) < 0) { LOGP(DMGCP, LOGL_ERROR, "Could not activate osmux in endpoint %d\n", diff --git a/src/libmgcp/mgcp_protocol.c b/src/libmgcp/mgcp_protocol.c index 78e41f1..96542c5 100644 --- a/src/libmgcp/mgcp_protocol.c +++ b/src/libmgcp/mgcp_protocol.c @@ -277,10 +277,12 @@ if (!addr) addr = mgcp_net_src_addr(endp); - if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) + if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) { sprintf(osmux_extension, "\nX-Osmux: %u", endp->osmux.cid); - else + endp->osmux.state = OSMUX_STATE_ACTIVATING; + } else { osmux_extension[0] = '\0'; + } len = snprintf(sdp_record, sizeof(sdp_record), "I: %u%s\n\n", endp->ci, osmux_extension); diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am index 16154ff..4726bbe 100644 --- a/src/libmsc/Makefile.am +++ b/src/libmsc/Makefile.am @@ -30,6 +30,7 @@ db.c \ gsm_04_08.c \ gsm_04_11.c \ + gsm_04_14.c \ gsm_04_80.c \ gsm_subscriber.c \ iucs.c \ diff --git a/src/libmsc/db.c b/src/libmsc/db.c index 28e9782..ae7e287 100644 --- a/src/libmsc/db.c +++ b/src/libmsc/db.c @@ -48,7 +48,7 @@ static char *db_dirname = NULL; static dbi_conn conn; -#define SCHEMA_REVISION "4" +#define SCHEMA_REVISION "5" enum { SCHEMA_META, @@ -122,6 +122,8 @@ "valid_until TIMESTAMP, " "reply_path_req INTEGER NOT NULL, " "status_rep_req INTEGER NOT NULL, " + "is_report INTEGER NOT NULL, " + "msg_ref INTEGER NOT NULL, " "protocol_id INTEGER NOT NULL, " "data_coding_scheme INTEGER NOT NULL, " "ud_hdr_ind INTEGER NOT NULL, " @@ -378,6 +380,152 @@ return -EINVAL; } +/* Just like v3, but there is a new message reference field for status reports, + * that is set to zero for existing entries since there is no way we can infer + * this. + */ +static struct gsm_sms *sms_from_result_v4(dbi_result result) +{ + struct gsm_sms *sms = sms_alloc(); + const unsigned char *user_data; + const char *text, *addr; + + if (!sms) + return NULL; + + sms->id = dbi_result_get_ulonglong(result, "id"); + + sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req"); + sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req"); + sms->ud_hdr_ind = dbi_result_get_ulonglong(result, "ud_hdr_ind"); + sms->protocol_id = dbi_result_get_ulonglong(result, "protocol_id"); + sms->data_coding_scheme = dbi_result_get_ulonglong(result, + "data_coding_scheme"); + + addr = dbi_result_get_string(result, "src_addr"); + osmo_strlcpy(sms->src.addr, addr, sizeof(sms->src.addr)); + sms->src.ton = dbi_result_get_ulonglong(result, "src_ton"); + sms->src.npi = dbi_result_get_ulonglong(result, "src_npi"); + + addr = dbi_result_get_string(result, "dest_addr"); + osmo_strlcpy(sms->dst.addr, addr, sizeof(sms->dst.addr)); + sms->dst.ton = dbi_result_get_ulonglong(result, "dest_ton"); + sms->dst.npi = dbi_result_get_ulonglong(result, "dest_npi"); + + sms->user_data_len = dbi_result_get_field_length(result, "user_data"); + user_data = dbi_result_get_binary(result, "user_data"); + if (sms->user_data_len > sizeof(sms->user_data)) + sms->user_data_len = (uint8_t) sizeof(sms->user_data); + memcpy(sms->user_data, user_data, sms->user_data_len); + + text = dbi_result_get_string(result, "text"); + if (text) + osmo_strlcpy(sms->text, text, sizeof(sms->text)); + return sms; +} + +static int update_db_revision_4(void) +{ + dbi_result result; + struct gsm_sms *sms; + + LOGP(DDB, LOGL_NOTICE, "Going to migrate from revision 4\n"); + + result = dbi_conn_query(conn, "BEGIN EXCLUSIVE TRANSACTION"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to begin transaction (upgrade from rev 4)\n"); + return -EINVAL; + } + dbi_result_free(result); + + /* Rename old SMS table to be able create a new one */ + result = dbi_conn_query(conn, "ALTER TABLE SMS RENAME TO SMS_4"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to rename the old SMS table (upgrade from rev 4).\n"); + goto rollback; + } + dbi_result_free(result); + + /* Create new SMS table with all the bells and whistles! */ + result = dbi_conn_query(conn, create_stmts[SCHEMA_SMS]); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to create a new SMS table (upgrade from rev 4).\n"); + goto rollback; + } + dbi_result_free(result); + + /* Cycle through old messages and convert them to the new format */ + result = dbi_conn_query(conn, "SELECT * FROM SMS_4"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed fetch messages from the old SMS table (upgrade from rev 4).\n"); + goto rollback; + } + while (dbi_result_next_row(result)) { + sms = sms_from_result_v4(result); + if (db_sms_store(sms) != 0) { + LOGP(DDB, LOGL_ERROR, "Failed to store message to the new SMS table(upgrade from rev 4).\n"); + sms_free(sms); + dbi_result_free(result); + goto rollback; + } + sms_free(sms); + } + dbi_result_free(result); + + /* Remove the temporary table */ + result = dbi_conn_query(conn, "DROP TABLE SMS_4"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to drop the old SMS table (upgrade from rev 4).\n"); + goto rollback; + } + dbi_result_free(result); + + /* We're done. Bump DB Meta revision to 4 */ + result = dbi_conn_query(conn, + "UPDATE Meta " + "SET value = '5' " + "WHERE key = 'revision'"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to update DB schema revision (upgrade from rev 4).\n"); + goto rollback; + } + dbi_result_free(result); + + result = dbi_conn_query(conn, "COMMIT TRANSACTION"); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to commit the transaction (upgrade from rev 4)\n"); + return -EINVAL; + } else { + dbi_result_free(result); + } + + /* Shrink DB file size by actually wiping out SMS_4 table data */ + result = dbi_conn_query(conn, "VACUUM"); + if (!result) + LOGP(DDB, LOGL_ERROR, + "VACUUM failed. Ignoring it (upgrade from rev 4).\n"); + else + dbi_result_free(result); + + return 0; + +rollback: + result = dbi_conn_query(conn, "ROLLBACK TRANSACTION"); + if (!result) + LOGP(DDB, LOGL_ERROR, + "Rollback failed (upgrade from rev 4).\n"); + else + dbi_result_free(result); + return -EINVAL; +} + static int check_db_revision(void) { dbi_result result; @@ -420,6 +568,9 @@ goto error; case 3: if (update_db_revision_3()) + goto error; + case 4: + if (update_db_revision_4()) goto error; /* The end of waterfall */ @@ -546,20 +697,23 @@ result = dbi_conn_queryf(conn, "INSERT INTO SMS " "(created, valid_until, " - "reply_path_req, status_rep_req, protocol_id, " - "data_coding_scheme, ud_hdr_ind, " + "reply_path_req, status_rep_req, is_report, " + "msg_ref, protocol_id, data_coding_scheme, " + "ud_hdr_ind, " "user_data, text, " "dest_addr, dest_ton, dest_npi, " "src_addr, src_ton, src_npi) VALUES " "(datetime('now'), %u, " "%u, %u, %u, " - "%u, %u, " + "%u, %u, %u, " + "%u, " "%s, %s, " "%s, %u, %u, " "%s, %u, %u)", validity_timestamp, - sms->reply_path_req, sms->status_rep_req, sms->protocol_id, - sms->data_coding_scheme, sms->ud_hdr_ind, + sms->reply_path_req, sms->status_rep_req, sms->is_report, + sms->msg_ref, sms->protocol_id, sms->data_coding_scheme, + sms->ud_hdr_ind, q_udata, q_text, q_daddr, sms->dst.ton, sms->dst.npi, q_saddr, sms->src.ton, sms->src.npi); @@ -588,13 +742,15 @@ /* FIXME: validity */ /* FIXME: those should all be get_uchar, but sqlite3 is braindead */ + sms->created = dbi_result_get_datetime(result, "created"); sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req"); sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req"); + sms->is_report = dbi_result_get_ulonglong(result, "is_report"); + sms->msg_ref = dbi_result_get_ulonglong(result, "msg_ref"); sms->ud_hdr_ind = dbi_result_get_ulonglong(result, "ud_hdr_ind"); sms->protocol_id = dbi_result_get_ulonglong(result, "protocol_id"); sms->data_coding_scheme = dbi_result_get_ulonglong(result, "data_coding_scheme"); - /* sms->msg_ref is temporary and not stored in DB */ sms->dst.npi = dbi_result_get_ulonglong(result, "dest_npi"); sms->dst.ton = dbi_result_get_ulonglong(result, "dest_ton"); diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c index d97bde2..28cba5b 100644 --- a/src/libmsc/gsm_04_08.c +++ b/src/libmsc/gsm_04_08.c @@ -43,6 +43,7 @@ #include <openbsc/gsm_04_11.h> #include <openbsc/gsm_04_08.h> #include <openbsc/gsm_04_80.h> +#include <openbsc/gsm_04_14.h> #include <openbsc/abis_rsl.h> #include <openbsc/chan_alloc.h> #include <openbsc/paging.h> @@ -496,12 +497,19 @@ else { /* Need to get GSM offset and convert into 15 min units */ /* This probably breaks if gmtoff returns a value not evenly divisible by 15? */ - local_time = localtime(&cur_t); #ifdef HAVE_TM_GMTOFF_IN_TM + local_time = localtime(&cur_t); tzunits = (local_time->tm_gmtoff/60)/15; #else -#warning find a portable way to obtain the timezone offset - tzunits = 0; + /* find timezone offset */ + time_t utc; + double offsetFromUTC; + utc = mktime(gmt_time); + local_time = localtime(&cur_t); + offsetFromUTC = difftime(cur_t, utc); + if (local_time->tm_isdst) + offsetFromUTC += 3600.0; + tzunits = ((int)offsetFromUTC) / 60 / 15; #endif if (tzunits < 0) { tzunits = tzunits/-1; @@ -3072,6 +3080,9 @@ case GSM48_PDISC_NC_SS: rc = handle_rcv_ussd(conn, msg); break; + case GSM48_PDISC_TEST: + rc = gsm0414_rcv_test(conn, msg); + break; default: LOGP(DRLL, LOGL_NOTICE, "Unknown " "GSM 04.08 discriminator 0x%02x\n", pdisc); diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c index bdf2ad7..c5bcce7 100644 --- a/src/libmsc/gsm_04_11.c +++ b/src/libmsc/gsm_04_11.c @@ -189,7 +189,7 @@ return gsm411_smc_send(&trans->sms.smc_inst, msg_type, msg); } -static int gsm340_rx_sms_submit(struct msgb *msg, struct gsm_sms *gsms) +static int gsm340_rx_sms_submit(struct gsm_sms *gsms) { if (db_sms_store(gsms) != 0) { LOGP(DLSMS, LOGL_ERROR, "Failed to store SMS in Database\n"); @@ -215,9 +215,9 @@ { uint8_t *smsp; uint8_t oa[12]; /* max len per 03.40 */ - uint8_t oa_len = 0; uint8_t octet_len; unsigned int old_msg_len = msg->len; + int oa_len; /* generate first octet with masked bits */ smsp = msgb_put(msg, 1); @@ -235,6 +235,9 @@ /* generate originator address */ oa_len = gsm340_gen_oa_sub(oa, sizeof(oa), &sms->src); + if (oa_len < 0) + return -ENOSPC; + smsp = msgb_put(msg, oa_len); memcpy(smsp, oa, oa_len); @@ -279,8 +282,55 @@ return msg->len - old_msg_len; } -int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg, - struct gsm_sms *gsms, uint8_t sms_mti, bool *deferred) +/* As defined by GSM 03.40, Section 9.2.2.3. */ +static int gsm340_gen_sms_status_report_tpdu(struct msgb *msg, + struct gsm_sms *sms) +{ + unsigned int old_msg_len = msg->len; + uint8_t oa[12]; /* max len per 03.40 */ + uint8_t *smsp; + int oa_len; + + /* generate first octet with masked bits */ + smsp = msgb_put(msg, 1); + /* TP-MTI (message type indicator) */ + *smsp = GSM340_SMS_STATUS_REP_SC2MS; + /* TP-MMS (more messages to send) */ + if (0 /* FIXME */) + *smsp |= 0x04; + /* TP-MR (message reference) */ + smsp = msgb_put(msg, 1); + *smsp = sms->msg_ref; + + /* generate recipient address */ + oa_len = gsm340_gen_oa_sub(oa, sizeof(oa), &sms->src); + if (oa_len < 0) + return -ENOSPC; + + smsp = msgb_put(msg, oa_len); + memcpy(smsp, oa, oa_len); + + /* generate TP-SCTS (Service centre timestamp) */ + smsp = msgb_put(msg, 7); + gsm340_gen_scts(smsp, sms->created); + + /* generate TP-DT (Discharge time, in TP-SCTS format). */ + smsp = msgb_put(msg, 7); + gsm340_gen_scts(smsp, sms->created); + + /* TP-ST (status) */ + smsp = msgb_put(msg, 1); + /* From GSM 03.40, Section 9.2.3.15, 0x00 means OK. */ + *smsp = 0x00; + + LOGP(DLSMS, LOGL_INFO, "sending status report for SMS reference %x\n", + sms->msg_ref); + + return msg->len - old_msg_len; +} + +static int sms_route_mt_sms(struct gsm_subscriber_connection *conn, + struct gsm_sms *gsms) { int rc; @@ -294,8 +344,9 @@ * delivery of the SMS. */ if (smpp_first) { - rc = smpp_try_deliver(gsms, conn, deferred); + rc = smpp_try_deliver(gsms, conn); if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED) + /* unknown subscriber, try local */ goto try_local; if (rc < 0) { LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.", @@ -322,7 +373,7 @@ return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; } - rc = smpp_try_deliver(gsms, conn, deferred); + rc = smpp_try_deliver(gsms, conn); if (rc == GSM411_RP_CAUSE_MO_NUM_UNASSIGNED) { rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); } else if (rc < 0) { @@ -337,27 +388,7 @@ rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]); #endif - return rc; } - - switch (sms_mti) { - case GSM340_SMS_SUBMIT_MS2SC: - /* MS is submitting a SMS */ - rc = gsm340_rx_sms_submit(msg, gsms); - break; - case GSM340_SMS_COMMAND_MS2SC: - case GSM340_SMS_DELIVER_REP_MS2SC: - LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); - rc = GSM411_RP_CAUSE_IE_NOTEXIST; - break; - default: - LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); - rc = GSM411_RP_CAUSE_IE_NOTEXIST; - break; - } - - if (!rc && !gsms->receiver) - rc = GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; return rc; } @@ -366,7 +397,7 @@ /* process an incoming TPDU (called from RP-DATA) * return value > 0: RP CAUSE for ERROR; < 0: silent error; 0 = success */ static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg, - uint32_t gsm411_msg_ref, bool *deferred) + uint32_t gsm411_msg_ref) { struct gsm_subscriber_connection *conn = trans->conn; uint8_t *smsp = msgb_sms(msg); @@ -387,7 +418,7 @@ /* invert those fields where 0 means active/present */ sms_mti = *smsp & 0x03; sms_vpf = (*smsp & 0x18) >> 3; - gsms->status_rep_req = (*smsp & 0x20); + gsms->status_rep_req = (*smsp & 0x20) >> 5; gsms->ud_hdr_ind = (*smsp & 0x40); /* * Not evaluating MMS (More Messages to Send) because the @@ -487,10 +518,29 @@ /* FIXME: This looks very wrong */ send_signal(0, NULL, gsms, 0); - rc = sms_route_mt_sms(conn, msg, gsms, sms_mti, deferred); + rc = sms_route_mt_sms(conn, gsms); + + /* This SMS got routed through SMPP or no receiver exists. */ + if (!gsms->receiver) + return rc; + + switch (sms_mti) { + case GSM340_SMS_SUBMIT_MS2SC: + /* MS is submitting a SMS */ + rc = gsm340_rx_sms_submit(gsms); + break; + case GSM340_SMS_COMMAND_MS2SC: + case GSM340_SMS_DELIVER_REP_MS2SC: + LOGP(DLSMS, LOGL_NOTICE, "Unimplemented MTI 0x%02x\n", sms_mti); + rc = GSM411_RP_CAUSE_IE_NOTEXIST; + break; + default: + LOGP(DLSMS, LOGL_NOTICE, "Undefined MTI 0x%02x\n", sms_mti); + rc = GSM411_RP_CAUSE_IE_NOTEXIST; + break; + } out: - if (!deferred) - sms_free(gsms); + sms_free(gsms); return rc; } @@ -543,7 +593,6 @@ uint8_t dst_len, uint8_t *dst, uint8_t tpdu_len, uint8_t *tpdu) { - bool deferred = false; int rc = 0; if (src_len && src) @@ -560,8 +609,8 @@ DEBUGP(DLSMS, "DST(%u,%s)\n", dst_len, osmo_hexdump(dst, dst_len)); - rc = gsm340_rx_tpdu(trans, msg, rph->msg_ref, &deferred); - if (rc == 0 && !deferred) + rc = gsm340_rx_tpdu(trans, msg, rph->msg_ref); + if (rc == 0) return gsm411_send_rp_ack(trans, rph->msg_ref); else if (rc > 0) return gsm411_send_rp_error(trans, rph->msg_ref, rc); @@ -595,6 +644,62 @@ rpud_len, rp_ud); } +static struct gsm_sms *sms_report_alloc(struct gsm_sms *sms) +{ + struct gsm_sms *sms_report; + int len; + + sms_report = sms_alloc(); + OSMO_ASSERT(sms_report); + + sms_report->msg_ref = sms->msg_ref; + sms_report->protocol_id = sms->protocol_id; + sms_report->data_coding_scheme = GSM338_DCS_1111_8BIT_DATA; + + /* Invert address to send status report back to origin. */ + sms_report->src = sms->dst; + sms_report->dst = sms->src; + + /* As specified by Appendix B. Delivery Receipt Format. + * TODO: Many fields in this string are just set with dummy values, + * revisit this. + */ + len = snprintf((char *)sms_report->user_data, + sizeof(sms_report->user_data), + "id:%.08llu sub:000 dlvrd:000 submit date:YYMMDDhhmm done date:YYMMDDhhmm stat:DELIVRD err:000 text:%.20s", + sms->id, sms->text); + sms_report->user_data_len = len; + LOGP(DLSMS, LOGL_NOTICE, "%s\n", sms_report->user_data); + + /* This represents a sms report. */ + sms_report->is_report = true; + + return sms_report; +} + +static void sms_status_report(struct gsm_sms *gsms, + struct gsm_subscriber_connection *conn) +{ + struct gsm_sms *sms_report; + int rc; + + sms_report = sms_report_alloc(gsms); + + rc = sms_route_mt_sms(conn, sms_report); + if (rc < 0) { + LOGP(DLSMS, LOGL_ERROR, + "Failed to send status report! err=%d\n", rc); + } + + /* No route via SMPP, send the GSM 03.40 status-report now. */ + if (gsms->receiver) + gsm340_rx_sms_submit(sms_report); + + LOGP(DLSMS, LOGL_NOTICE, "Status report has been sent\n"); + + sms_free(sms_report); +} + /* Receive a 04.11 RP-ACK message (response to RP-DATA from us) */ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) @@ -615,6 +720,9 @@ db_sms_mark_delivered(sms); send_signal(S_SMS_DELIVERED, trans, sms, 0); + + if (sms->status_rep_req) + sms_status_report(sms, trans->conn); sms_free(sms); trans->sms.sms = NULL; @@ -940,8 +1048,13 @@ /* obtain a pointer for the rp_ud_len, so we can fill it later */ rp_ud_len = (uint8_t *)msgb_put(msg, 1); - /* generate the 03.40 SMS-DELIVER TPDU */ - rc = gsm340_gen_sms_deliver_tpdu(msg, sms); + if (sms->is_report) { + /* generate the 03.40 SMS-STATUS-REPORT TPDU */ + rc = gsm340_gen_sms_status_report_tpdu(msg, sms); + } else { + /* generate the 03.40 SMS-DELIVER TPDU */ + rc = gsm340_gen_sms_deliver_tpdu(msg, sms); + } if (rc < 0) { send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0); sms_free(sms); diff --git a/src/libmsc/gsm_04_14.c b/src/libmsc/gsm_04_14.c new file mode 100644 index 0000000..b529f4c --- /dev/null +++ b/src/libmsc/gsm_04_14.c @@ -0,0 +1,133 @@ +/* GSM MS Testing Layer 3 messages + * 3GPP TS 44.014 / GSM TS 04.14 */ + +/* (C) 2017 by Harald Welte <laforge at gnumonks.org> + * + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "bscconfig.h" + +#include <openbsc/debug.h> +#include <openbsc/gsm_data.h> +#include <openbsc/gsm_subscriber.h> +#include <openbsc/gsm_04_08.h> +#include <openbsc/bsc_api.h> +#include <openbsc/msc_ifaces.h> + +#include <osmocom/gsm/gsm48.h> +#include <osmocom/gsm/gsm_utils.h> +#include <osmocom/gsm/protocol/gsm_04_14.h> +#include <osmocom/gsm/tlv.h> +#include <osmocom/core/msgb.h> +#include <osmocom/core/talloc.h> +#include <osmocom/core/utils.h> + +static struct msgb *create_gsm0414_msg(uint8_t msg_type) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.14"); + struct gsm48_hdr *gh; + + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); + gh->proto_discr = GSM48_PDISC_TEST; + gh->msg_type = msg_type; + return msg; +} + +static int gsm0414_conn_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + return msc_tx_dtap(conn, msg); +} + +static int gsm0414_tx_simple(struct gsm_subscriber_connection *conn, uint8_t msg_type) +{ + struct msgb *msg = create_gsm0414_msg(msg_type); + + return gsm0414_conn_sendmsg(conn, msg); +} + + +/* Send a CLOSE_TCH_LOOOP_CMD according to Section 8.1 */ +int gsm0414_tx_close_tch_loop_cmd(struct gsm_subscriber_connection *conn, + enum gsm414_tch_loop_mode loop_mode) +{ + struct msgb *msg = create_gsm0414_msg(GSM414_MT_CLOSE_TCH_LOOP_CMD); + uint8_t subch; + + subch = (loop_mode << 1); + msgb_put_u8(msg, subch); + + msg->lchan = conn->lchan; + return gsm0414_conn_sendmsg(conn, msg); +} + +/* Send a OPEN_LOOP_CMD according to Section 8.3 */ +int gsm0414_tx_open_loop_cmd(struct gsm_subscriber_connection *conn) +{ + return gsm0414_tx_simple(conn, GSM414_MT_OPEN_LOOP_CMD); +} + +/* Send a ACT_EMMI_CMD according to Section 8.8 */ +int gsm0414_tx_act_emmi_cmd(struct gsm_subscriber_connection *conn) +{ + return gsm0414_tx_simple(conn, GSM414_MT_ACT_EMMI_CMD); +} + +/* Send a DEACT_EMMI_CMD according to Section 8.10 */ +int gsm0414_tx_deact_emmi_cmd(struct gsm_subscriber_connection *conn) +{ + return gsm0414_tx_simple(conn, GSM414_MT_DEACT_EMMI_CMD); +} + +/* Send a TEST_INTERFACE according to Section 8.11 */ +int gsm0414_tx_test_interface(struct gsm_subscriber_connection *conn, + uint8_t tested_devs) +{ + struct msgb *msg = create_gsm0414_msg(GSM414_MT_TEST_INTERFACE); + msgb_put_u8(msg, tested_devs); + return gsm0414_conn_sendmsg(conn, msg); +} + +/* Send a RESET_MS_POSITION_STORED according to Section 8.11 */ +int gsm0414_tx_reset_ms_pos_store(struct gsm_subscriber_connection *conn, + uint8_t technology) +{ + struct msgb *msg = create_gsm0414_msg(GSM414_MT_RESET_MS_POS_STORED); + msgb_put_u8(msg, technology); + return gsm0414_conn_sendmsg(conn, msg); +} + + + +/* Entry point for incoming GSM48_PDISC_TEST received from MS */ +int gsm0414_rcv_test(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + + if (msgb_l3len(msg) < sizeof(*gh)) + return -1; + + LOGP(DMM, LOGL_NOTICE, "%s: Received TEST class message '%s'\n", "FIXME", + get_value_string(gsm414_msgt_names, gh->msg_type)); + + return 0; +} diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c index 24a4653..431cb4d 100644 --- a/src/libmsc/smpp_openbsc.c +++ b/src/libmsc/smpp_openbsc.c @@ -73,27 +73,32 @@ return vsub; } -/*! \brief find a TLV with given tag in list of libsmpp34 TLVs */ -static struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag) +static int smpp34_submit_tlv_msg_payload(const struct tlv_t *t, + const struct submit_sm_t *submit, + const uint8_t **sms_msg, + unsigned int *sms_msg_len) { - struct tlv_t *t; - - for (t = head; t != NULL; t = t->next) { - if (t->tag == tag) - return t; + if (submit->sm_length) { + LOGP(DLSMS, LOGL_ERROR, + "SMPP cannot have payload in TLV _and_ in the header\n"); + return -1; } - return NULL; + *sms_msg = t->value.octet; + *sms_msg_len = t->length; + + return 0; } /*! \brief convert from submit_sm_t to gsm_sms */ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net, const struct submit_sm_t *submit) { + const uint8_t *sms_msg = NULL; + unsigned int sms_msg_len = 0; struct vlr_subscr *dest; + uint16_t msg_ref = 0; struct gsm_sms *sms; struct tlv_t *t; - const uint8_t *sms_msg; - unsigned int sms_msg_len; int mode; dest = subscr_by_dst(net, submit->dest_addr_npi, @@ -106,30 +111,40 @@ return ESME_RINVDSTADR; } - t = find_tlv(submit->tlv, TLVID_message_payload); - if (t) { - if (submit->sm_length) { - /* ERROR: we cannot have both! */ - LOGP(DLSMS, LOGL_ERROR, "SMPP Cannot have payload in " - "TLV _and_ in the header\n"); - vlr_subscr_put(dest); - return ESME_ROPTPARNOTALLWD; + smpp34_tlv_for_each(t, submit->tlv) { + switch (t->tag) { + case TLVID_message_payload: + if (smpp34_submit_tlv_msg_payload(t, submit, &sms_msg, + &sms_msg_len) < 0) { + vlr_subscr_put(dest); + return ESME_ROPTPARNOTALLWD; + } + break; + case TLVID_user_message_reference: + msg_ref = t->value.val16; + break; + default: + break; } - sms_msg = t->value.octet; - sms_msg_len = t->length; - } else if (submit->sm_length > 0 && submit->sm_length < 255) { - sms_msg = submit->short_message; - sms_msg_len = submit->sm_length; - } else { - LOGP(DLSMS, LOGL_ERROR, - "SMPP neither message payload nor valid sm_length.\n"); - vlr_subscr_put(dest); - return ESME_RINVPARLEN; + } + + if (!sms_msg) { + if (submit->sm_length > 0 && submit->sm_length < 255) { + sms_msg = submit->short_message; + sms_msg_len = submit->sm_length; + } else { + LOGP(DLSMS, LOGL_ERROR, + "SMPP neither message payload nor valid sm_length.\n"); + vlr_subscr_put(dest); + return ESME_RINVPARLEN; + } } sms = sms_alloc(); sms->source = SMS_SOURCE_SMPP; sms->smpp.sequence_nr = submit->sequence_number; + sms->status_rep_req = submit->registered_delivery; + sms->msg_ref = msg_ref; /* fill in the destination address */ sms->receiver = dest; @@ -143,10 +158,13 @@ osmo_strlcpy(sms->src.addr, (char *)submit->source_addr, sizeof(sms->src.addr)); - if (submit->esm_class & 0x40) + if (submit->esm_class == SMPP34_DELIVERY_ACK) + sms->is_report = true; + + if (submit->esm_class & SMPP34_UDHI_IND) sms->ud_hdr_ind = 1; - if (submit->esm_class & 0x80) { + if (submit->esm_class & SMPP34_REPLY_PATH) { sms->reply_path_req = 1; #warning Implement reply path } @@ -222,7 +240,7 @@ sms->smpp.esme = esme; sms->protocol_id = submit->protocol_id; - switch (submit->esm_class & 3) { + switch (submit->esm_class & SMPP34_MSG_MODE_MASK) { case 0: /* default */ case 1: /* datagram */ case 3: /* store-and-forward */ @@ -419,7 +437,7 @@ memset(&tlv, 0, sizeof(tlv)); tlv.tag = tag; tlv.length = 2; - tlv.value.val16 = htons(val); + tlv.value.val16 = val; build_tlv(req_tlv, &tlv); } @@ -501,7 +519,6 @@ osmo_timer_del(&cmd->response_timer); llist_del(&cmd->list); vlr_subscr_put(cmd->vsub); - sms_free(cmd->sms); talloc_free(cmd); } @@ -518,21 +535,24 @@ struct gsm_subscriber_connection *conn; struct gsm_trans *trans; + if (cmd->is_report) + goto out; + conn = connection_for_subscr(cmd->vsub); if (!conn) { LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n"); - return; + goto out; } - trans = trans_find_by_id(conn, GSM48_PDISC_SMS, - cmd->sms->gsm411.transaction_id); + trans = trans_find_by_id(conn, GSM48_PDISC_SMS, cmd->gsm411_trans_id); if (!trans) { LOGP(DSMPP, LOGL_ERROR, "GSM transaction %u is gone\n", - cmd->sms->gsm411.transaction_id); - return; + cmd->gsm411_trans_id); + goto out; } - gsm411_send_rp_ack(trans, cmd->sms->gsm411.msg_ref); + gsm411_send_rp_ack(trans, cmd->gsm411_msg_ref); +out: smpp_cmd_free(cmd); } @@ -542,25 +562,27 @@ struct gsm_trans *trans; int gsm411_cause; + if (cmd->is_report) + goto out; + conn = connection_for_subscr(cmd->vsub); if (!conn) { LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n"); - return; + goto out; } - trans = trans_find_by_id(conn, GSM48_PDISC_SMS, - cmd->sms->gsm411.transaction_id); + trans = trans_find_by_id(conn, GSM48_PDISC_SMS, cmd->gsm411_trans_id); if (!trans) { LOGP(DSMPP, LOGL_ERROR, "GSM transaction %u is gone\n", - cmd->sms->gsm411.transaction_id); - return; + cmd->gsm411_trans_id); + goto out; } if (smpp_to_gsm411_err(status, &gsm411_cause) < 0) gsm411_cause = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER; - gsm411_send_rp_error(trans, cmd->sms->gsm411.msg_ref, gsm411_cause); - + gsm411_send_rp_error(trans, cmd->gsm411_msg_ref, gsm411_cause); +out: smpp_cmd_free(cmd); } @@ -571,7 +593,7 @@ static int smpp_cmd_enqueue(struct osmo_esme *esme, struct vlr_subscr *vsub, struct gsm_sms *sms, - uint32_t sequence_number, bool *deferred) + uint32_t sequence_number) { struct osmo_smpp_cmd *cmd; @@ -580,7 +602,9 @@ return -1; cmd->sequence_nr = sequence_number; - cmd->sms = sms; + cmd->is_report = sms->is_report; + cmd->gsm411_msg_ref = sms->gsm411.msg_ref; + cmd->gsm411_trans_id = sms->gsm411.transaction_id; cmd->vsub = vlr_subscr_get(vsub); /* FIXME: No predefined value for this response_timer as specified by @@ -591,7 +615,6 @@ osmo_timer_setup(&cmd->response_timer, smpp_deliver_sm_cb, cmd); osmo_timer_schedule(&cmd->response_timer, 5, 0); llist_add_tail(&cmd->list, &esme->smpp_cmd_list); - *deferred = true; return 0; } @@ -609,8 +632,7 @@ } static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms, - struct gsm_subscriber_connection *conn, - bool *deferred) + struct gsm_subscriber_connection *conn) { struct deliver_sm_t deliver; int mode, ret; @@ -641,15 +663,20 @@ memcpy(deliver.destination_addr, sms->dst.addr, sizeof(deliver.destination_addr)); - deliver.esm_class = 1; /* datagram mode */ + if (sms->is_report) + deliver.esm_class = SMPP34_DELIVERY_RECEIPT; + else + deliver.esm_class = SMPP34_DATAGRAM_MODE; + if (sms->ud_hdr_ind) - deliver.esm_class |= 0x40; + deliver.esm_class |= SMPP34_UDHI_IND; if (sms->reply_path_req) - deliver.esm_class |= 0x80; + deliver.esm_class |= SMPP34_REPLY_PATH; deliver.protocol_id = sms->protocol_id; deliver.priority_flag = 0; - deliver.registered_delivery = 0; + if (sms->status_rep_req) + deliver.registered_delivery = SMPP34_DELIVERY_RECEIPT_ON; /* Figure out SMPP DCS from TP-DCS */ dcs = sms->data_coding_scheme; @@ -679,8 +706,6 @@ } else { deliver.sm_length = sms->user_data_len; memcpy(deliver.short_message, sms->user_data, deliver.sm_length); - deliver.sm_length = sms->user_data_len; - memcpy(deliver.short_message, sms->user_data, deliver.sm_length); } #if BEFORE_MSCSPLIT @@ -689,12 +714,15 @@ append_osmo_tlvs(&deliver.tlv, conn->lchan); #endif + append_tlv_u16(&deliver.tlv, TLVID_user_message_reference, + sms->msg_ref); + ret = smpp_tx_deliver(esme, &deliver); if (ret < 0) return ret; return smpp_cmd_enqueue(esme, conn->vsub, sms, - deliver.sequence_number, deferred); + deliver.sequence_number); } static struct smsc *g_smsc; @@ -705,21 +733,22 @@ } int smpp_try_deliver(struct gsm_sms *sms, - struct gsm_subscriber_connection *conn, bool *deferred) + struct gsm_subscriber_connection *conn) { struct osmo_esme *esme; struct osmo_smpp_addr dst; + int rc; memset(&dst, 0, sizeof(dst)); dst.ton = sms->dst.ton; dst.npi = sms->dst.npi; memcpy(dst.addr, sms->dst.addr, sizeof(dst.addr)); - esme = smpp_route(g_smsc, &dst); - if (!esme) - return GSM411_RP_CAUSE_MO_NUM_UNASSIGNED; + rc = smpp_route(g_smsc, &dst, &esme); + if (!rc) + rc = deliver_to_esme(esme, sms, conn); - return deliver_to_esme(esme, sms, conn, deferred); + return rc; } struct smsc *smsc_from_vty(struct vty *v) diff --git a/src/libmsc/smpp_smsc.c b/src/libmsc/smpp_smsc.c index 48a1192..04afc49 100644 --- a/src/libmsc/smpp_smsc.c +++ b/src/libmsc/smpp_smsc.c @@ -270,8 +270,7 @@ } /*! \brief try to find a SMPP route (ESME) for given destination */ -struct osmo_esme * -smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest) +int smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest, struct osmo_esme **pesme) { struct osmo_smpp_route *r; struct osmo_smpp_acl *acl = NULL; @@ -314,15 +313,20 @@ struct osmo_esme *esme; DEBUGP(DSMPP, "ACL even has ESME, we can route to it!\n"); esme = acl->esme; - if (esme->bind_flags & ESME_BIND_RX) - return esme; - else + if (esme->bind_flags & ESME_BIND_RX) { + *pesme = esme; + return 0; + } else LOGP(DSMPP, LOGL_NOTICE, "[%s] is matching route, " "but not bound for Rx, discarding MO SMS\n", esme->system_id); } - return NULL; + *pesme = NULL; + if (acl) + return GSM48_CC_CAUSE_NETWORK_OOO; + else + return GSM48_CC_CAUSE_UNASSIGNED_NR; } @@ -654,6 +658,9 @@ { deliver->sequence_number = esme_inc_seq_nr(esme); + LOGP(DSMPP, LOGL_DEBUG, "[%s] Tx DELIVER-SM (from %s)\n", + esme->system_id, deliver->source_addr); + return PACK_AND_SEND(esme, deliver); } diff --git a/src/libmsc/smpp_smsc.h b/src/libmsc/smpp_smsc.h index 4bee59b..755e685 100644 --- a/src/libmsc/smpp_smsc.h +++ b/src/libmsc/smpp_smsc.h @@ -89,8 +89,10 @@ struct osmo_smpp_cmd { struct llist_head list; struct vlr_subscr *vsub; - struct gsm_sms *sms; uint32_t sequence_nr; + uint32_t gsm411_msg_ref; + uint8_t gsm411_trans_id; + bool is_report; struct osmo_timer_list response_timer; }; @@ -126,8 +128,7 @@ void smpp_esme_get(struct osmo_esme *esme); void smpp_esme_put(struct osmo_esme *esme); -struct osmo_esme * -smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest); +int smpp_route(const struct smsc *smsc, const struct osmo_smpp_addr *dest, struct osmo_esme **emse); struct osmo_smpp_acl *smpp_acl_alloc(struct smsc *smsc, const char *sys_id); struct osmo_smpp_acl *smpp_acl_by_system_id(struct smsc *smsc, @@ -162,5 +163,5 @@ int smpp_route_smpp_first(struct gsm_sms *sms, struct gsm_subscriber_connection *conn); int smpp_try_deliver(struct gsm_sms *sms, - struct gsm_subscriber_connection *conn, bool *deferred); + struct gsm_subscriber_connection *conn); #endif diff --git a/src/libmsc/transaction.c b/src/libmsc/transaction.c index 7289a8f..28e0914 100644 --- a/src/libmsc/transaction.c +++ b/src/libmsc/transaction.c @@ -88,6 +88,13 @@ DEBUGP(DCC, "subscr=%p, net=%p\n", vsub, net); + /* a valid subscriber is indispensable */ + if (vsub == NULL) { + LOGP(DCC, LOGL_NOTICE, + "unable to alloc transaction, invalid subscriber (NULL)\n"); + return NULL; + } + trans = talloc_zero(tall_trans_ctx, struct gsm_trans); if (!trans) return NULL; diff --git a/src/libmsc/vty_interface_layer3.c b/src/libmsc/vty_interface_layer3.c index d1bf6b3..864597d 100644 --- a/src/libmsc/vty_interface_layer3.c +++ b/src/libmsc/vty_interface_layer3.c @@ -46,6 +46,7 @@ #include <openbsc/debug.h> #include <openbsc/vty.h> #include <openbsc/gsm_04_80.h> +#include <openbsc/gsm_04_14.h> #include <openbsc/chan_alloc.h> #include <openbsc/sms_queue.h> #include <openbsc/mncc_int.h> @@ -473,6 +474,97 @@ return CMD_SUCCESS; } +static int loop_by_char(uint8_t ch) +{ + switch (ch) { + case 'a': + return GSM414_LOOP_A; + case 'b': + return GSM414_LOOP_B; + case 'c': + return GSM414_LOOP_C; + case 'd': + return GSM414_LOOP_D; + case 'e': + return GSM414_LOOP_E; + case 'f': + return GSM414_LOOP_F; + case 'i': + return GSM414_LOOP_I; + } + return -1; +} + +DEFUN(subscriber_mstest_close, + subscriber_mstest_close_cmd, + "subscriber " SUBSCR_TYPES " ID ms-test close-loop (a|b|c|d|e|f|i)", + SUBSCR_HELP "Send a TS 04.14 MS Test Command to subscriber\n" + "Close a TCH Loop inside the MS\n" + "Loop Type A\n" + "Loop Type B\n" + "Loop Type C\n" + "Loop Type D\n" + "Loop Type E\n" + "Loop Type F\n" + "Loop Type I\n") +{ + struct gsm_subscriber_connection *conn; + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]); + const char *loop_str; + int loop_mode; + + if (!vsub) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + loop_str = argv[2]; + loop_mode = loop_by_char(loop_str[0]); + + conn = connection_for_subscr(vsub); + if (!conn) { + vty_out(vty, "%% An active connection is required for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); + vlr_subscr_put(vsub); + return CMD_WARNING; + } + + gsm0414_tx_close_tch_loop_cmd(conn, loop_mode); + + return CMD_SUCCESS; +} + +DEFUN(subscriber_mstest_open, + subscriber_mstest_open_cmd, + "subscriber " SUBSCR_TYPES " ID ms-test open-loop", + SUBSCR_HELP "Send a TS 04.14 MS Test Command to subscriber\n" + "Open a TCH Loop inside the MS\n") +{ + struct gsm_subscriber_connection *conn; + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]); + + if (!vsub) { + vty_out(vty, "%% No subscriber found for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); + return CMD_WARNING; + } + + conn = connection_for_subscr(vsub); + if (!conn) { + vty_out(vty, "%% An active connection is required for %s %s%s", + argv[0], argv[1], VTY_NEWLINE); + vlr_subscr_put(vsub); + return CMD_WARNING; + } + + gsm0414_tx_open_loop_cmd(conn); + + return CMD_SUCCESS; +} + DEFUN(ena_subscr_expire, ena_subscr_expire_cmd, "subscriber " SUBSCR_TYPES " ID expire", @@ -570,11 +662,11 @@ VTY_NEWLINE); vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, " "%lu completed, %lu failed%s", - net->msc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, - net->msc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, - net->msc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, - net->msc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, - net->msc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, + net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_ATTEMPTED].current, + net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_NO_CHANNEL].current, + net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT].current, + net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_COMPLETED].current, + net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_FAILED].current, VTY_NEWLINE); vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s", net->msc_ctrs->ctr[MSC_CTR_SMS_SUBMITTED].current, @@ -851,6 +943,8 @@ install_element_ve(&subscriber_silent_call_start_cmd); install_element_ve(&subscriber_silent_call_stop_cmd); install_element_ve(&subscriber_ussd_notify_cmd); + install_element_ve(&subscriber_mstest_close_cmd); + install_element_ve(&subscriber_mstest_open_cmd); install_element_ve(&subscriber_update_cmd); install_element_ve(&show_stats_cmd); install_element_ve(&show_smsqueue_cmd); diff --git a/src/osmo-bsc/osmo_bsc_main.c b/src/osmo-bsc/osmo_bsc_main.c index ee094d6..90651b9 100644 --- a/src/osmo-bsc/osmo_bsc_main.c +++ b/src/osmo-bsc/osmo_bsc_main.c @@ -162,6 +162,7 @@ switch (signal) { case SIGINT: + case SIGTERM: bsc_shutdown_net(bsc_gsmnet); osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); sleep(3); @@ -280,6 +281,7 @@ } signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); diff --git a/src/osmo-msc/msc_main.c b/src/osmo-msc/msc_main.c index 4166159..723c0e6 100644 --- a/src/osmo-msc/msc_main.c +++ b/src/osmo-msc/msc_main.c @@ -140,7 +140,6 @@ printf(" -c --config-file filename The config file to use.\n"); printf(" -s --disable-color\n"); printf(" -l --database db-name The database to use.\n"); - printf(" -a --authorize-everyone Authorize every new subscriber. Dangerous!\n"); printf(" -T --timestamp Prefix every log line with a timestamp.\n"); printf(" -V --version Print the version of OpenBSC.\n"); printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC.\n"); @@ -163,7 +162,6 @@ {"config-file", 1, 0, 'c'}, {"disable-color", 0, 0, 's'}, {"database", 1, 0, 'l'}, - {"authorize-everyone", 0, 0, 'a'}, {"pcap", 1, 0, 'p'}, {"timestamp", 0, 0, 'T'}, {"version", 0, 0, 'V' }, @@ -268,6 +266,7 @@ switch (signal) { case SIGINT: + case SIGTERM: msc_network_shutdown(msc_network); osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL); sleep(3); @@ -474,6 +473,7 @@ osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL); signal(SIGINT, &signal_handler); + signal(SIGTERM, &signal_handler); signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); diff --git a/src/utils/smpp_mirror.c b/src/utils/smpp_mirror.c index 95df5f2..c570505 100644 --- a/src/utils/smpp_mirror.c +++ b/src/utils/smpp_mirror.c @@ -95,12 +95,23 @@ } /* FIXME: merge with smpp_smsc.c */ +static struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag) +{ + struct tlv_t *t; + + for (t = head; t != NULL; t = t->next) { + if (t->tag == tag) + return t; + } + return NULL; +} static int smpp_handle_deliver(struct esme *esme, struct msgb *msg) { struct deliver_sm_t deliver; struct deliver_sm_resp_t deliver_r; struct submit_sm_t submit; + tlv_t *t; int rc; memset(&deliver, 0, sizeof(deliver)); @@ -129,7 +140,15 @@ OSMO_MIN(sizeof(submit.source_addr), sizeof(deliver.destination_addr))); - submit.esm_class = deliver.esm_class; + /* Mirror delivery receipts as a delivery acknowledgements. */ + if (deliver.esm_class == 0x04) { + LOGP(DSMPP, LOGL_DEBUG, "%s\n", deliver.short_message); + submit.esm_class = 0x08; + } else { + submit.esm_class = deliver.esm_class; + } + + submit.registered_delivery = deliver.registered_delivery; submit.protocol_id = deliver.protocol_id; submit.priority_flag = deliver.priority_flag; memcpy(submit.schedule_delivery_time, deliver.schedule_delivery_time, @@ -146,7 +165,18 @@ memcpy(submit.short_message, deliver.short_message, OSMO_MIN(sizeof(submit.short_message), sizeof(deliver.short_message))); - /* FIXME: TLV? */ + + /* FIXME: More TLV? */ + t = find_tlv(deliver.tlv, TLVID_user_message_reference); + if (t) { + tlv_t tlv; + + memset(&tlv, 0, sizeof(tlv)); + tlv.tag = TLVID_user_message_reference; + tlv.length = 2; + tlv.value.val16 = t->value.val16; + build_tlv(&submit.tlv, &tlv); + } return PACK_AND_SEND(esme, &submit); } diff --git a/tests/channel/channel_test.c b/tests/channel/channel_test.c index f686969..beae658 100644 --- a/tests/channel/channel_test.c +++ b/tests/channel/channel_test.c @@ -31,6 +31,35 @@ #include <openbsc/gsm_subscriber.h> #include <openbsc/vlr.h> +void test_bts_debug_print(void) +{ + struct gsm_network *network; + struct gsm_bts *bts; + struct gsm_bts_trx *trx; + + printf("Testing the lchan printing:"); + + /* Create a dummy network */ + network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); + if (!network) + exit(1); + /* Add a BTS with some reasonanbly non-zero id */ + bts = gsm_bts_alloc(network, 45); + /* Add a second TRX to test on multiple TRXs */ + gsm_bts_trx_alloc(bts); + + llist_for_each_entry(trx, &bts->trx_list, list) { + char *name = gsm_lchan_name(&trx->ts[3].lchan[4]); + + if (name) + printf(" %s", name); + else + printf("NULL name"); + } + printf("\n"); +} + + void test_dyn_ts_subslots(void) { struct gsm_bts_trx_ts ts; @@ -66,6 +95,7 @@ osmo_init_logging(&log_info); test_dyn_ts_subslots(); + test_bts_debug_print(); return EXIT_SUCCESS; } diff --git a/tests/channel/channel_test.ok b/tests/channel/channel_test.ok index e4d625a..81d6569 100644 --- a/tests/channel/channel_test.ok +++ b/tests/channel/channel_test.ok @@ -1 +1,2 @@ Testing subslot numbers for pchan types +Testing the lchan printing: (bts=45,trx=0,ts=3,ss=4) (bts=45,trx=1,ts=3,ss=4) diff --git a/tests/db/db_test.err b/tests/db/db_test.err index fa9a54c..27e5703 100644 --- a/tests/db/db_test.err +++ b/tests/db/db_test.err @@ -1,2 +1,3 @@ Going to migrate from revision 3 +[0;mGoing to migrate from revision 4 [0;m \ No newline at end of file diff --git a/tests/gprs/gprs_test.c b/tests/gprs/gprs_test.c index ff77404..aac9bb8 100644 --- a/tests/gprs/gprs_test.c +++ b/tests/gprs/gprs_test.c @@ -48,101 +48,6 @@ ASSERT_FALSE(nu_is_retransmission(479, 511)); // wrapped } -static void apn_round_trip(const uint8_t *input, size_t len, const char *wanted_output) -{ - char output[len ? len : 1]; - uint8_t encoded[len + 50]; - char *out_str; - int enc_len; - - /* decode and verify we have what we want */ - out_str = gprs_apn_to_str(output, input, len); - OSMO_ASSERT(out_str); - OSMO_ASSERT(out_str == &output[0]); - OSMO_ASSERT(strlen(out_str) == strlen(wanted_output)); - OSMO_ASSERT(strcmp(out_str, wanted_output) == 0); - - /* encode and verify it */ - if (len != 0) { - enc_len = gprs_str_to_apn(encoded, ARRAY_SIZE(encoded), wanted_output); - OSMO_ASSERT(enc_len == len); - OSMO_ASSERT(memcmp(encoded, input, enc_len) == 0); - } else { - enc_len = gprs_str_to_apn(encoded, 0, wanted_output); - OSMO_ASSERT(enc_len == -1); - } -} - -static void test_gsm_03_03_apn(void) -{ - - { - /* test invalid writes */ - const uint8_t ref[10] = { 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF }; - uint8_t output[10]; - int enc_len; - - memcpy(output, ref, ARRAY_SIZE(output)); - enc_len = gprs_str_to_apn(output, 0, ""); - OSMO_ASSERT(enc_len == -1); - OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0); - - memcpy(output, ref, ARRAY_SIZE(output)); - enc_len = gprs_str_to_apn(output, 0, "foo"); - OSMO_ASSERT(enc_len == -1); - OSMO_ASSERT(memcmp(ref, output, ARRAY_SIZE(ref)) == 0); - - memcpy(output, ref, ARRAY_SIZE(output)); - enc_len = gprs_str_to_apn(output, 1, "foo"); - OSMO_ASSERT(enc_len == -1); - OSMO_ASSERT(memcmp(ref + 1, output + 1, ARRAY_SIZE(ref) - 1) == 0); - - memcpy(output, ref, ARRAY_SIZE(output)); - enc_len = gprs_str_to_apn(output, 2, "foo"); - OSMO_ASSERT(enc_len == -1); - OSMO_ASSERT(memcmp(ref + 2, output + 2, ARRAY_SIZE(ref) - 2) == 0); - - memcpy(output, ref, ARRAY_SIZE(output)); - enc_len = gprs_str_to_apn(output, 3, "foo"); - OSMO_ASSERT(enc_len == -1); - OSMO_ASSERT(memcmp(ref + 3, output + 3, ARRAY_SIZE(ref) - 3) == 0); - } - - { - /* single empty label */ - uint8_t input[] = { 0x0 }; - const char *output = ""; - apn_round_trip(input, ARRAY_SIZE(input), output); - } - - { - /* no label */ - uint8_t input[] = { }; - const char *output = ""; - apn_round_trip(input, ARRAY_SIZE(input), output); - } - - { - /* single label with A */ - uint8_t input[] = { 0x1, 65 }; - const char *output = "A"; - apn_round_trip(input, ARRAY_SIZE(input), output); - OSMO_ASSERT(gprs_apn_to_str(NULL, input, ARRAY_SIZE(input) - 1) == NULL); - } - - { - uint8_t input[] = { 0x3, 65, 66, 67, 0x2, 90, 122 }; - const char *output = "ABC.Zz"; - char tmp[strlen(output) + 1]; - apn_round_trip(input, ARRAY_SIZE(input), output); - OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 1) == NULL); - OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 2) == NULL); - OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 4) == NULL); - OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 5) == NULL); - OSMO_ASSERT(gprs_apn_to_str(tmp, input, ARRAY_SIZE(input) - 6) == NULL); - } -} - static void test_gprs_timer_enc_dec(void) { int i, u, secs, tmr; @@ -228,7 +133,6 @@ osmo_init_logging(&info); test_8_4_2(); - test_gsm_03_03_apn(); test_gprs_timer_enc_dec(); printf("Done.\n"); diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index 1b326ee..fcdc8f8 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -153,7 +153,7 @@ if (!network) exit(1); - bts = gsm_bts_alloc(network); + bts = gsm_bts_alloc(network, 0); _bts_uarfcn_add(bts, 10564, 319, 0); _bts_uarfcn_add(bts, 10612, 319, 0); @@ -168,7 +168,7 @@ if (!network) exit(1); - bts = gsm_bts_alloc(network); + bts = gsm_bts_alloc(network, 0); _bts_uarfcn_add(bts, 10564, 318, 0); _bts_uarfcn_add(bts, 10612, 319, 0); @@ -188,7 +188,7 @@ if (!network) exit(1); - bts = gsm_bts_alloc(network); + bts = gsm_bts_alloc(network, 0); /* first generate invalid SI as no UARFCN added */ gen(bts, __func__); @@ -216,7 +216,7 @@ if (!network) exit(1); - bts = gsm_bts_alloc(network); + bts = gsm_bts_alloc(network, 0); bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list; bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list; @@ -249,7 +249,7 @@ if (!network) exit(1); - bts = gsm_bts_alloc(network); + bts = gsm_bts_alloc(network, 0); bts->si_common.si2quater_neigh_list.arfcn = bts->si_common.data.earfcn_list; bts->si_common.si2quater_neigh_list.meas_bw = bts->si_common.data.meas_bw_list; diff --git a/tests/gtphub/Makefile.am b/tests/gtphub/Makefile.am index 5c834b7..f2a6b88 100644 --- a/tests/gtphub/Makefile.am +++ b/tests/gtphub/Makefile.am @@ -8,6 +8,7 @@ -ggdb3 \ $(LIBOSMOCORE_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) \ + $(LIBOSMOGSM_CFLAGS) \ $(LIBGTP_CFLAGS) \ $(NULL) @@ -37,6 +38,7 @@ $(top_builddir)/src/gprs/gtphub.o \ $(top_builddir)/src/gprs/gprs_utils.o \ $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ $(LIBGTP_LIBS) \ -lrt \ $(NULL) diff --git a/tests/sgsn/sgsn_test.c b/tests/sgsn/sgsn_test.c index 2f1513a..d66c5dd 100644 --- a/tests/sgsn/sgsn_test.c +++ b/tests/sgsn/sgsn_test.c @@ -139,12 +139,12 @@ }; /* override, requires '-Wl,--wrap=gprs_subscr_request_auth_info' */ -int __real_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx); -int (*subscr_request_auth_info_cb)(struct sgsn_mm_ctx *mmctx) = +int __real_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand); +int (*subscr_request_auth_info_cb)(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) = &__real_gprs_subscr_request_auth_info; -int __wrap_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx) { - return (*subscr_request_auth_info_cb)(mmctx); +int __wrap_gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) { + return (*subscr_request_auth_info_cb)(mmctx, auts, auts_rand); }; /* override, requires '-Wl,--wrap=gsup_client_send' */ @@ -1160,7 +1160,7 @@ cleanup_test(); } -int my_subscr_request_auth_info_real_auth(struct sgsn_mm_ctx *mmctx) +int my_subscr_request_auth_info_real_auth(struct sgsn_mm_ctx *mmctx, const uint8_t *auts, const uint8_t *auts_rand) { struct gsm_auth_tuple at = { .vec.sres = {0x51, 0xe5, 0x51, 0xe5}, -- To view, visit https://gerrit.osmocom.org/3695 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Id072aa07793aceca66bd74950bc40dd504982a55 Gerrit-PatchSet: 1 Gerrit-Project: osmo-msc Gerrit-Branch: master Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de> Gerrit-Reviewer: Pau Espin Pedrol <pespin at sysmocom.de>