diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 7184a85a5..57665386d 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -38,6 +38,13 @@ enum gsm_chan_t { GSM_LCHAN_UNKNOWN, }; +/* RRLP mode of operation */ +enum rrlp_mode { + RRLP_MODE_NONE, + RRLP_MODE_MS_BASED, + RRLP_MODE_MS_PREF, + RRLP_MODE_ASS_PREF, +}; /* Channel Request reason */ enum gsm_chreq_reason_t { @@ -449,6 +456,11 @@ struct gsm_network { int T3117; int T3119; int T3141; + + /* Radio Resource Location Protocol (TS 04.31) */ + struct { + enum rrlp_mode mode; + } rrlp; }; #define SMS_HDR_SIZE 128 @@ -533,6 +545,9 @@ 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); +enum rrlp_mode rrlp_mode_parse(const char *arg); +const char *rrlp_mode_name(enum rrlp_mode mode); + void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked); #endif diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c index fef1127eb..cdaba9e52 100644 --- a/openbsc/src/gsm_data.c +++ b/openbsc/src/gsm_data.c @@ -367,3 +367,26 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy) return gsm_auth_policy_names[policy]; } +static const char *rrlp_mode_names[] = { + [RRLP_MODE_NONE] = "none", + [RRLP_MODE_MS_BASED] = "ms-based", + [RRLP_MODE_MS_PREF] = "ms-preferred", + [RRLP_MODE_ASS_PREF] = "ass-preferred", +}; + +enum rrlp_mode rrlp_mode_parse(const char *arg) +{ + int i; + for (i = 0; i < ARRAY_SIZE(rrlp_mode_names); i++) { + if (!strcmp(arg, rrlp_mode_names[i])) + return i; + } + return RRLP_MODE_NONE; +} + +const char *rrlp_mode_name(enum rrlp_mode mode) +{ + if (mode > ARRAY_SIZE(rrlp_mode_names)) + return "none"; + return rrlp_mode_names[mode]; +} diff --git a/openbsc/src/rrlp.c b/openbsc/src/rrlp.c index 523b53f0b..60ce750ad 100644 --- a/openbsc/src/rrlp.c +++ b/openbsc/src/rrlp.c @@ -1,4 +1,4 @@ - +/* Radio Resource LCS (Location) Protocol, GMS TS 04.31 */ /* (C) 2009 by Harald Welte * @@ -28,9 +28,42 @@ #include #include -/* RRLP MS based position request */ +/* RRLP msPositionReq, nsBased, + * Accuracy=60, Method=gps, ResponseTime=2, oneSet */ static const u_int8_t ms_based_pos_req[] = { 0x40, 0x01, 0x78, 0xa8 }; +/* RRLP msPositionReq, msBasedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ms_pref_pos_req[] = { 0x40, 0x02, 0x79, 0x50 }; + +/* RRLP msPositionReq, msAssistedPref, + Accuracy=60, Method=gpsOrEOTD, ResponseTime=5, multipleSets */ +static const u_int8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 }; + +static int send_rrlp_req(struct gsm_lchan *lchan) +{ + struct gsm_network *net = lchan->ts->trx->bts->network; + const u_int8_t *req; + + switch (net->rrlp.mode) { + case RRLP_MODE_MS_BASED: + req = ms_based_pos_req; + break; + case RRLP_MODE_MS_PREF: + req = ms_pref_pos_req; + break; + case RRLP_MODE_ASS_PREF: + req = ass_pref_pos_req; + break; + case RRLP_MODE_NONE: + default: + return 0; + } + + return gsm48_send_rr_app_info(lchan, 0x00, + sizeof(ms_based_pos_req), req); +} + static int subscr_sig_cb(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { @@ -44,8 +77,7 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal, lchan = lchan_for_subscr(subscr); if (!lchan) break; - gsm48_send_rr_app_info(lchan, 0x00, sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(lchan); break; } return 0; @@ -59,9 +91,7 @@ static int paging_sig_cb(unsigned int subsys, unsigned int signal, switch (signal) { case S_PAGING_COMPLETED: /* A subscriber has attached. */ - gsm48_send_rr_app_info(psig_data->lchan, 0x00, - sizeof(ms_based_pos_req), - ms_based_pos_req); + send_rrlp_req(psig_data->lchan); break; } return 0; diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c index 529b0d481..adef1480a 100644 --- a/openbsc/src/vty_interface.c +++ b/openbsc/src/vty_interface.c @@ -91,6 +91,8 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net) VTY_NEWLINE); vty_out(vty, " NECI (TCH/H): %u%s", net->neci, VTY_NEWLINE); + vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode), + VTY_NEWLINE); } DEFUN(show_net, show_net_cmd, "show network", @@ -289,6 +291,8 @@ static int config_write_net(struct vty *vty) gsmnet->reject_cause, 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, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode), + 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); @@ -838,6 +842,15 @@ DEFUN(cfg_net_neci, return CMD_SUCCESS; } +DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd, + "rrlp mode (none|ms-based|ms-preferred|ass-preferred)", + "Set the Radio Resource Location Protocol Mode") +{ + gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]); + + return CMD_SUCCESS; +} + #define DECLARE_TIMER(number) \ DEFUN(cfg_net_T##number, \ cfg_net_T##number##_cmd, \ @@ -1344,6 +1357,7 @@ int bsc_vty_init(struct gsm_network *net) install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd); install_element(GSMNET_NODE, &cfg_net_encryption_cmd); install_element(GSMNET_NODE, &cfg_net_neci_cmd); + install_element(GSMNET_NODE, &cfg_net_rrlp_mode_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);