aboutsummaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-06-27 11:25:35 +0200
committerHarald Welte <laforge@gnumonks.org>2011-06-27 11:25:35 +0200
commitc6b4c87e5d57b91b29894835e7ac8e42f6e67f32 (patch)
tree2dfca5a61c881e88e6f29d03c29bb26e1c643332 /src/common
parent8e47fb89bfd0e2b54b714393ac2a80ca76df56a9 (diff)
re-work original osmo-bts with support for sysmocom femtobts
This code re-works osmo-bts to add support for the upcoming sysmocom BTS. It also tries to add some level of abstraction between the generic part of a BTS (A-bis, RSL, OML, data structures, paging scheduling, BCCH/AGCH scheduling, etc.) and the actual hardware-specific bits. The hardware-specific bits are currently only implemented for the sysmocom femtobts, but should be (re-)added for osmocom-bb, as well as a virtual BTS for simulation purpose later. The sysmocom bts specific parts require hardware-specific header files which are (at least currently) not publicly distributed.
Diffstat (limited to 'src/common')
-rw-r--r--src/common/Makefile.am4
-rw-r--r--src/common/abis.c144
-rw-r--r--src/common/bts.c145
-rw-r--r--src/common/gsm_data_shared.c1
-rw-r--r--src/common/load_indication.c69
-rw-r--r--src/common/logging.c122
-rw-r--r--src/common/oml.c900
-rw-r--r--src/common/paging.c440
-rw-r--r--src/common/rsl.c778
-rw-r--r--src/common/rtp.c18
-rw-r--r--src/common/support.c9
-rw-r--r--src/common/sysinfo.c66
-rw-r--r--src/common/vty.c61
13 files changed, 2132 insertions, 625 deletions
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 0c13b54a..70b94957 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -3,5 +3,5 @@ AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS)
LDADD = $(LIBOSMOCORE_LIBS)
noinst_LIBRARIES = libbts.a
-libbts_a_SOURCES = support.c bts.c abis.c rsl.c oml.c rtp.c
-# ../common/l1l2_interface.c ../common/lapdm.c ../common/logging.c
+libbts_a_SOURCES = gsm_data_shared.c sysinfo.c logging.c abis.c oml.c bts.c rsl.c vty.c paging.c
+#support.c rtp.c
diff --git a/src/common/abis.c b/src/common/abis.c
index f70eb843..c60f5443 100644
--- a/src/common/abis.c
+++ b/src/common/abis.c
@@ -1,10 +1,14 @@
+/* Minimalistic Abis/IP interface routines, soon to be replaced by
+ * libosmo-abis (Pablo) */
+
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2011 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -12,9 +16,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
@@ -27,16 +30,20 @@
#include <errno.h>
#include <string.h>
-#include <osmocore/select.h>
-#include <osmocore/timer.h>
-#include <osmocore/msgb.h>
-#include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/bts/abis.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/protocol/ipaccess.h>
+
+#include <osmo-bts/logging.h>
+#include <osmo-bts/gsm_data.h>
+#include <osmo-bts/abis.h>
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/oml.h>
+#if 0
#include <osmocom/bb/bts/rtp.h>
-#include <osmocom/bb/bts/bts.h>
-#include <osmocom/bb/bts/rsl.h>
-#include <osmocom/bb/bts/oml.h>
+#endif
extern char *software_version;
extern uint8_t abis_mac[6];
@@ -61,6 +68,23 @@ int abis_tx(struct ipabis_link *link, struct msgb *msg)
return 0;
}
+int abis_oml_sendmsg(struct msgb *msg)
+{
+ struct gsm_bts *bts = msg->trx->bts;
+
+ abis_push_ipa(msg, 0xff);
+
+ return abis_tx((struct ipabis_link *) bts->oml_link, msg);
+}
+
+int abis_rsl_sendmsg(struct msgb *msg)
+{
+ struct gsm_bts_trx *trx = msg->trx;
+
+ abis_push_ipa(msg, 0);
+
+ return abis_tx((struct ipabis_link *) trx->rsl_link, msg);
+}
struct msgb *abis_msgb_alloc(int headroom)
{
@@ -98,7 +122,7 @@ static int abis_tx_ipa_pingpong(struct ipabis_link *link, uint8_t pingpong)
if (!nmsg)
return -ENOMEM;
*msgb_put(nmsg, 1) = pingpong;
- abis_push_ipa(nmsg, IPA_PROTO_IPACCESS);
+ abis_push_ipa(nmsg, IPAC_PROTO_IPACCESS);
return abis_tx(link, nmsg);
}
@@ -106,16 +130,20 @@ static int abis_tx_ipa_pingpong(struct ipabis_link *link, uint8_t pingpong)
/* send ACK and ID RESP */
static int abis_rx_ipa_id_get(struct ipabis_link *link, uint8_t *data, int len)
{
+ struct gsm_bts *bts = link->bts;
struct msgb *nmsg, *nmsg2;
char str[64];
uint8_t *tag;
+ if (!link->bts)
+ bts = link->trx->bts;
+
LOGP(DABIS, LOGL_INFO, "Reply to ID_GET\n");
nmsg = abis_msgb_alloc(0);
if (!nmsg)
return -ENOMEM;
- *msgb_put(nmsg, 1) = IPA_MSGT_ID_RESP;
+ *msgb_put(nmsg, 1) = IPAC_MSGT_ID_RESP;
while (len) {
if (len < 2) {
LOGP(DABIS, LOGL_NOTICE,
@@ -124,32 +152,33 @@ static int abis_rx_ipa_id_get(struct ipabis_link *link, uint8_t *data, int len)
return -EIO;
}
switch (data[1]) {
- case IPA_IDTAG_UNIT:
- sprintf(str, "%s/%d", (link->trx) ? link->trx->bts->id
- : link->bts->id,
- (link->trx) ? link->trx->trx_nr : 0);
+ case IPAC_IDTAG_UNIT:
+ sprintf(str, "%u/%u/%u",
+ bts->ip_access.site_id,
+ bts->ip_access.bts_id,
+ (link->trx) ? link->trx->nr : 0);
break;
- case IPA_IDTAG_MACADDR:
+ case IPAC_IDTAG_MACADDR:
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
abis_mac[0], abis_mac[1], abis_mac[2],
abis_mac[3], abis_mac[4], abis_mac[5]);
break;
- case IPA_IDTAG_LOCATION1:
+ case IPAC_IDTAG_LOCATION1:
strcpy(str, "osmoBTS");
break;
- case IPA_IDTAG_LOCATION2:
+ case IPAC_IDTAG_LOCATION2:
strcpy(str, "osmoBTS");
break;
- case IPA_IDTAG_EQUIPVERS:
- case IPA_IDTAG_SWVERSION:
+ case IPAC_IDTAG_EQUIPVERS:
+ case IPAC_IDTAG_SWVERSION:
strcpy(str, software_version);
break;
- case IPA_IDTAG_UNITNAME:
+ case IPAC_IDTAG_UNITNAME:
sprintf(str, "osmoBTS-%02x-%02x-%02x-%02x-%02x-%02x",
abis_mac[0], abis_mac[1], abis_mac[2],
abis_mac[3], abis_mac[4], abis_mac[5]);
break;
- case IPA_IDTAG_SERNR:
+ case IPAC_IDTAG_SERNR:
strcpy(str, "");
break;
default:
@@ -167,15 +196,15 @@ static int abis_rx_ipa_id_get(struct ipabis_link *link, uint8_t *data, int len)
data += 2;
len -= 2;
}
- abis_push_ipa(nmsg, IPA_PROTO_IPACCESS);
+ abis_push_ipa(nmsg, IPAC_PROTO_IPACCESS);
nmsg2 = abis_msgb_alloc(0);
if (!nmsg2) {
msgb_free(nmsg);
return -ENOMEM;
}
- *msgb_put(nmsg2, 1) = IPA_MSGT_ID_ACK;
- abis_push_ipa(nmsg2, IPA_PROTO_IPACCESS);
+ *msgb_put(nmsg2, 1) = IPAC_MSGT_ID_ACK;
+ abis_push_ipa(nmsg2, IPAC_PROTO_IPACCESS);
link->id_resp = 1;
@@ -196,21 +225,23 @@ static int abis_rx_ipaccess(struct ipabis_link *link, struct msgb *msg)
}
switch (*data) {
- case IPA_MSGT_PONG:
+ case IPAC_MSGT_PONG:
+#if 0
#warning HACK
rsl_tx_chan_rqd(link->bts->trx[0]);
- LOGP(DABIS, LOGL_INFO, "PONG\n");
+#endif
+ LOGP(DABIS, LOGL_DEBUG, "PONG\n");
link->pong = 1;
break;
- case IPA_MSGT_PING:
- LOGP(DABIS, LOGL_INFO, "reply to ping request\n");
- ret = abis_tx_ipa_pingpong(link, IPA_MSGT_PONG);
+ case IPAC_MSGT_PING:
+ LOGP(DABIS, LOGL_DEBUG, "reply to ping request\n");
+ ret = abis_tx_ipa_pingpong(link, IPAC_MSGT_PONG);
break;
- case IPA_MSGT_ID_GET:
+ case IPAC_MSGT_ID_GET:
ret = abis_rx_ipa_id_get(link, data + 1, len - 1);
break;
- case IPA_MSGT_ID_ACK:
- LOGP(DABIS, LOGL_INFO, "ID ACK\n");
+ case IPAC_MSGT_ID_ACK:
+ LOGP(DABIS, LOGL_DEBUG, "ID ACK\n");
if (link->id_resp && link->bts)
ret = bts_link_estab(link->bts);
if (link->id_resp && link->trx)
@@ -240,7 +271,7 @@ static int abis_rx(struct ipabis_link *link, struct msgb *msg)
int ret = 0;
switch (hh->proto) {
- case IPA_PROTO_RSL:
+ case IPAC_PROTO_RSL:
if (!link->trx) {
LOGP(DABIS, LOGL_NOTICE,
"Received RSL message not on RSL link\n");
@@ -248,16 +279,17 @@ static int abis_rx(struct ipabis_link *link, struct msgb *msg)
ret = EIO;
break;
}
+ msg->trx = link->trx;
ret = down_rsl(link->trx, msg);
break;
- case IPA_PROTO_IPACCESS:
+ case IPAC_PROTO_IPACCESS:
ret = abis_rx_ipaccess(link, msg);
break;
- case IPA_PROTO_SCCP:
+ case IPAC_PROTO_SCCP:
LOGP(DABIS, LOGL_INFO, "Received SCCP message\n");
msgb_free(msg);
break;
- case IPA_PROTO_OML:
+ case IPAC_PROTO_OML:
if (!link->bts) {
LOGP(DABIS, LOGL_NOTICE,
"Received OML message not on OML link\n");
@@ -265,6 +297,7 @@ static int abis_rx(struct ipabis_link *link, struct msgb *msg)
ret = EIO;
break;
}
+ msg->trx = link->bts->c0;
ret = down_oml(link->bts, msg);
break;
default:
@@ -302,8 +335,8 @@ static void abis_timeout(void *arg)
}
link->ping = 1;
link->pong = 0;
- LOGP(DABIS, LOGL_INFO, "PING\n");
- abis_tx_ipa_pingpong(link, IPA_MSGT_PING);
+ LOGP(DABIS, LOGL_DEBUG, "PING\n");
+ abis_tx_ipa_pingpong(link, IPAC_MSGT_PING);
osmo_timer_schedule(&link->timer, OML_PING_TIMER, 0);
break;
}
@@ -348,7 +381,7 @@ static int abis_sock_cb(struct osmo_fd *bfd, unsigned int what)
return 0;
msg->l2h = msg->data + sizeof(*hh);
if (ntohs(hh->len) > msgb_tailroom(msg)) {
- LOGP(DABIS, LOGL_NOTICE, "Received packet from "
+ LOGP(DABIS, LOGL_DEBUG, "Received packet from "
"Abis socket too large.\n");
goto close;
}
@@ -363,13 +396,13 @@ static int abis_sock_cb(struct osmo_fd *bfd, unsigned int what)
if (ntohs(hh->len) + sizeof(*hh) > msg->len)
return 0;
link->rx_msg = NULL;
- LOGP(DABIS, LOGL_INFO, "Received messages from Abis socket.\n");
+ LOGP(DABIS, LOGL_DEBUG, "Received messages from Abis socket.\n");
ret = abis_rx(link, msg);
}
if ((what & BSC_FD_WRITE)) {
msg = msgb_dequeue(&link->tx_queue);
if (msg) {
- LOGP(DABIS, LOGL_INFO, "Sending messages to Abis socket.\n");
+ LOGP(DABIS, LOGL_DEBUG, "Sending messages to Abis socket.\n");
ret = send(link->bfd.fd, msg->data, msg->len, 0);
if (ret < 0)
goto close;
@@ -377,7 +410,7 @@ static int abis_sock_cb(struct osmo_fd *bfd, unsigned int what)
link->bfd.when &= ~BSC_FD_WRITE;
}
if ((what & BSC_FD_EXCEPT)) {
- LOGP(DABIS, LOGL_INFO, "Abis socket received exception\n");
+ LOGP(DABIS, LOGL_NOTICE, "Abis socket received exception\n");
goto close;
}
@@ -388,11 +421,11 @@ close:
/* RSL link will just close and BSC is notified */
if (link->trx) {
- LOGP(DABIS, LOGL_INFO, "Connection to BSC failed\n");
+ LOGP(DABIS, LOGL_NOTICE, "Connection to BSC failed\n");
return trx_link_estab(link->trx);
}
- LOGP(DABIS, LOGL_INFO, "Connection to BSC failed, retrying in %d "
+ LOGP(DABIS, LOGL_NOTICE, "Connection to BSC failed, retrying in %d "
"seconds.\n", OML_RETRY_TIMER);
osmo_timer_schedule(&link->timer, OML_RETRY_TIMER, 0);
link->state = LINK_STATE_RETRYING;
@@ -407,6 +440,8 @@ int abis_open(struct ipabis_link *link, uint32_t ip)
int sock;
int ret;
+ oml_init();
+
if (link->bfd.fd > 0)
return -EBUSY;
@@ -455,18 +490,11 @@ int abis_open(struct ipabis_link *link, uint32_t ip)
void abis_close(struct ipabis_link *link)
{
struct msgb *msg;
- int i;
if (link->bfd.fd <= 0)
return;
- LOGP(DABIS, LOGL_INFO, "Abis socket closed.\n");
-
-#warning if any link fails, shutdown all links
- if (link->trx) {
- for (i = 0; i < 8; i++)
- bts_setup_slot(&link->trx->slot[i], 0xff);
- }
+ LOGP(DABIS, LOGL_NOTICE, "Abis socket closed.\n");
if (link->rx_msg) {
msgb_free(link->rx_msg);
diff --git a/src/common/bts.c b/src/common/bts.c
index 1c912f03..02cb0fe1 100644
--- a/src/common/bts.c
+++ b/src/common/bts.c
@@ -1,10 +1,13 @@
+/* BTS support code common to all supported BTS models */
+
/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2011 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -12,9 +15,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
@@ -29,23 +31,30 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
+#include <osmocom/gsm/lapdm.h>
+
#include <osmo-bts/logging.h>
-//#include <osmocom/bb/common/osmocom_data.h>
-//#include <osmocom/bb/common/l1l2_interface.h>
#include <osmo-bts/abis.h>
-#include <osmo-bts/rtp.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
-extern void *l23_ctx;
-extern uint8_t cr_loc2rem_cmd;
-extern uint8_t cr_loc2rem_resp;
-extern uint8_t cr_rem2loc_cmd;
-extern uint8_t cr_rem2loc_resp;
+void *tall_bts_ctx;
+
+int bts_init(struct gsm_bts *bts)
+{
+ struct gsm_bts_role_bts *btsb;
+
+ bts->role = btsb = talloc_zero(bts, struct gsm_bts_role_bts);
+
+ INIT_LLIST_HEAD(&btsb->agch_queue);
-BTS_SI_NAME;
+ /* FIXME: make those parameters configurable */
+ btsb->paging_state = paging_init(btsb, 200, 0);
+
+ return bts_model_init(bts);
+}
#if 0
struct osmobts_lchan *lchan_by_channelnr(struct osmobts_trx *trx,
@@ -88,7 +97,6 @@ struct osmobts_lchan *lchan_by_channelnr(struct osmobts_trx *trx,
return NULL;
}
-#endif
struct osmocom_bts *create_bts(uint8_t num_trx, char *id)
{
@@ -267,45 +275,33 @@ void destroy_bts(struct osmocom_bts *bts)
abis_close(&bts->link);
talloc_free(bts);
}
+#endif
/* main link is established, send status report */
-int bts_link_estab(struct osmocom_bts *bts)
+int bts_link_estab(struct gsm_bts *bts)
{
int i, j;
uint8_t radio_state;
LOGP(DSUM, LOGL_INFO, "Main link established, sending Status'.\n");
- /* site-manager status */
- oml_tx_state_changed(&bts->link, NM_OPSTATE_ENABLED, NM_AVSTATE_OK,
- NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
- /* bts status */
- oml_tx_state_changed(&bts->link, NM_OPSTATE_ENABLED, NM_AVSTATE_OK,
- NM_OC_BTS, 0, 0xff, 0xff);
- /* trx */
+ oml_mo_state_chg(&bts->site_mgr.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
+ oml_mo_state_chg(&bts->mo, NM_OPSTATE_ENABLED, NM_AVSTATE_DEPENDENCY);
+
for (i = 0; i < bts->num_trx; i++) {
- radio_state = (bts->trx[i]->link.state == LINK_STATE_CONNECT) ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
- oml_tx_state_changed(&bts->link, radio_state,
- NM_AVSTATE_OK, NM_OC_RADIO_CARRIER, 0,
- bts->trx[i]->trx_nr, 0xff);
- oml_tx_sw_act_rep(&bts->link, NM_OC_RADIO_CARRIER, 0, bts->trx[i]->trx_nr, 0xff);
- oml_tx_state_changed(&bts->link, NM_OPSTATE_ENABLED,
- NM_AVSTATE_OK, NM_OC_BASEB_TRANSC, 0,
- bts->trx[i]->trx_nr, 0xff);
- oml_tx_sw_act_rep(&bts->link, NM_OC_BASEB_TRANSC, 0, bts->trx[i]->trx_nr, 0xff);
- /* channel */
- for (j = 0; j < 8; j++) {
- if (bts->trx[i]->slot[j].tx_ms)
- oml_tx_state_changed(&bts->link,
- NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY,
- NM_OC_CHANNEL, 0, bts->trx[i]->trx_nr,
- bts->trx[i]->slot[j].slot_nr);
- else
- oml_tx_state_changed(&bts->link,
- NM_OPSTATE_DISABLED,
- NM_AVSTATE_NOT_INSTALLED,
- NM_OC_CHANNEL, 0, bts->trx[i]->trx_nr,
- bts->trx[i]->slot[j].slot_nr);
+ struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, i);
+ struct ipabis_link *link = (struct ipabis_link *) trx->rsl_link;
+
+ radio_state = (link && link->state == LINK_STATE_CONNECT) ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
+ oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK);
+ oml_mo_tx_sw_act_rep(&trx->mo);
+ oml_mo_state_chg(&trx->bb_transc.mo, NM_OPSTATE_ENABLED, NM_AVSTATE_OK);
+ oml_mo_tx_sw_act_rep(&trx->bb_transc.mo);
+
+ for (j = 0; j < ARRAY_SIZE(trx->ts); j++) {
+ struct gsm_bts_trx_ts *ts = &trx->ts[j];
+
+ oml_mo_state_chg(&ts->mo, NM_OPSTATE_DISABLED, NM_AVSTATE_DEPENDENCY);
}
}
@@ -313,15 +309,17 @@ int bts_link_estab(struct osmocom_bts *bts)
}
/* RSL link is established, send status report */
-int trx_link_estab(struct osmobts_trx *trx)
+int trx_link_estab(struct gsm_bts_trx *trx)
{
- uint8_t radio_state = (trx->link.state == LINK_STATE_CONNECT) ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
+ struct ipabis_link *link = (struct ipabis_link *) trx->rsl_link;
+ uint8_t radio_state = (link->state == LINK_STATE_CONNECT) ? NM_OPSTATE_ENABLED : NM_OPSTATE_DISABLED;
- LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n", trx->trx_nr, (trx->link.state == LINK_STATE_CONNECT) ? "up" : "down");
+ LOGP(DSUM, LOGL_INFO, "RSL link (TRX %02x) state changed to %s, sending Status'.\n",
+ trx->nr, (link->state == LINK_STATE_CONNECT) ? "up" : "down");
- oml_tx_state_changed(&trx->bts->link, radio_state, NM_AVSTATE_OK, NM_OC_RADIO_CARRIER, 0, trx->trx_nr, 0xff);
+ oml_mo_state_chg(&trx->mo, radio_state, NM_AVSTATE_OK);
- if (trx->link.state == LINK_STATE_CONNECT)
+ if (link->state == LINK_STATE_CONNECT)
rsl_tx_rf_res(trx);
return 0;
@@ -332,6 +330,7 @@ void bts_new_si(void *arg)
struct osmobts_trx *trx = arg;
int i;
+#if 0
if (osmo_timer_pending(&trx->si.timer))
return;
@@ -354,25 +353,41 @@ void bts_new_si(void *arg)
trx->si.timer.cb = bts_new_si;
trx->si.timer.data = trx;
osmo_timer_schedule(&trx->si.timer, 0, 200000);
+#endif
}
-/* handle bts instance (including MS instances) */
-int work_bts(struct osmocom_bts *bts)
+int lchan_init_lapdm(struct gsm_lchan *lchan)
{
- int work = 0, w;
-
- do {
- w = 0;
-// w |= xxx_dequeue(ms);
- if (w)
- work = 1;
- } while (w);
- return work;
+ struct lapdm_channel *lc = &lchan->lapdm_ch;
+
+ lapdm_channel_init(lc, LAPDM_MODE_BTS);
+ lapdm_channel_set_flags(lc, LAPDM_ENT_F_POLLING_ONLY);
+ lapdm_channel_set_l1(lc, NULL, lchan);
+ lapdm_channel_set_l3(lc, lapdm_rll_tx_cb, lchan);
+
+ return 0;
}
-#if 0
-int create_chan(struct osmocom_bts *slot, uint8_t type)
+
+int bts_agch_enqueue(struct gsm_bts *bts, struct msgb *msg)
{
- welcher type?:
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);;
+
+ /* FIXME: implement max queue length */
+ llist_add_tail(&msg->list, &btsb->agch_queue);
+
+ return 0;
}
-#endif
+struct msgb *bts_agch_dequeue(struct gsm_bts *bts)
+{
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);;
+ struct msgb *msg;
+
+ if (llist_empty(&btsb->agch_queue))
+ return NULL;
+
+ msg = llist_entry(btsb->agch_queue.next, struct msgb, list);
+ llist_del(&msg->list);
+
+ return msg;
+}
diff --git a/src/common/gsm_data_shared.c b/src/common/gsm_data_shared.c
new file mode 100644
index 00000000..706892db
--- /dev/null
+++ b/src/common/gsm_data_shared.c
@@ -0,0 +1 @@
+#include "../../../openbsc/openbsc/src/libcommon/gsm_data_shared.c"
diff --git a/src/common/load_indication.c b/src/common/load_indication.c
new file mode 100644
index 00000000..12e41e43
--- /dev/null
+++ b/src/common/load_indication.c
@@ -0,0 +1,69 @@
+/* Support for generating RSL Load Indication */
+
+/* (C) 2011 by Harald Welte <laforge@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 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 <rsl.h>
+
+#include <osmocom/core/timer.h>
+
+static void reset_load_counters(void)
+{
+ /* re-set the counters */
+ btsb->load.ccch.pch_used = btsb->load.ccch.pch_total = 0;
+}
+
+static void load_timer_cb(void *data)
+{
+ struct gsm_bts *bts = data;
+ struct gsm_bts_role_bts *btsb = FIXME;
+ unsigned int pch_percent;
+
+ /* compute percentages */
+ pch_percent = (btsb->load.ccch.pch_used * 100) / btsb->load.ccch.pch_total;
+
+ if (pch_percent >= btsb->load.ccch.load_ind_thresh) {
+ /* send RSL load indication message to BSC */
+ uint16_t paging_buffer_space = FIXME;
+ rsl_tx_ccch_load_ind_pch(bts, paging_buffer_space);
+ }
+
+ reset_load_counters();
+
+ /* re-schedule the timer */
+ osmo_timer_schedule(&btsb->load.ccch.timer,
+ btsb->load.ccch.load_ind_period, 0);
+}
+
+static void load_timer_start(struct gsm_bts *bts)
+{
+ struct gsm_bts_role_bts *btsb = FIXME;
+
+ btsb->load.ccch.timer.data = bts;
+ reset_load_counters();
+ osmo_timer_schedule(&btsb->load.ccch.timer,
+ btsb->load.ccch.load_ind_period, 0);
+
+ return 0
+}
+
+static void load_timer_stop(struct gsm_bts *bts)
+{
+ osmo_timer_del(&btsb->load.ccch.timer);
+}
diff --git a/src/common/logging.c b/src/common/logging.c
new file mode 100644
index 00000000..362e30cd
--- /dev/null
+++ b/src/common/logging.c
@@ -0,0 +1,122 @@
+/* libosmocore logging support */
+
+/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2011 by Harald Welte <laforge@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 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 <errno.h>
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/application.h>
+#include <osmocom/core/utils.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/logging.h>
+
+static const struct log_info_cat bts_log_info_cat[] = {
+ [DRSL] = {
+ .name = "DRSL",
+ .description = "A-bis Radio Siganlling Link (RSL)",
+ .color = "\033[1;35m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DOML] = {
+ .name = "DOML",
+ .description = "A-bis Network Management / O&M (NM/OML)",
+ .color = "\033[1;36m",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+ [DRLL] = {
+ .name = "DRLL",
+ .description = "A-bis Radio Link Layer (RLL)",
+ .color = "\033[1;31m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DRR] = {
+ .name = "DRR",
+ .description = "Layer3 Radio Resource (RR)",
+ .color = "\033[1;34m",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+ [DMEAS] = {
+ .name = "DMEAS",
+ .description = "Radio Measurement Processing",
+ .enabled = 0, .loglevel = LOGL_NOTICE,
+ },
+ [DPAG] = {
+ .name = "DPAG",
+ .description = "Paging Subsystem",
+ .color = "\033[1;38m",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+ [DL1C] = {
+ .name = "DL1C",
+ .description = "Layer 1",
+ .loglevel = LOGL_DEBUG,
+ .enabled = 1,
+ },
+ [DL1P] = {
+ .name = "DL1P",
+ .description = "Layer 1 Primitives",
+ .loglevel = LOGL_DEBUG,
+ .enabled = 0,
+ },
+ [DABIS] = {
+ .name = "DABIS",
+ .description = "A-bis Intput Subsystem",
+ .enabled = 1, .loglevel = LOGL_NOTICE,
+ },
+#if 0
+ [DNS] = {
+ .name = "DNS",
+ .description = "GPRS Network Service (NS)",
+ .enabled = 1, .loglevel = LOGL_INFO,
+ },
+ [DBSSGP] = {
+ .name = "DBSSGP",
+ .description = "GPRS BSS Gateway Protocol (BSSGP)",
+ .enabled = 1, .loglevel = LOGL_DEBUG,
+ },
+ [DLLC] = {
+ .name = "DLLC",
+ .description = "GPRS Logical Link Control Protocol (LLC)",
+ .enabled = 1, .loglevel = LOGL_DEBUG,
+ },
+#endif
+};
+
+const struct log_info bts_log_info = {
+ .cat = bts_log_info_cat,
+ .num_cat = ARRAY_SIZE(bts_log_info_cat),
+};
+
+#define DEFAULT_MASK "DL1C:DOML:DRSL:DPAG"
+
+int bts_log_init(const char *category_mask)
+{
+ if (!category_mask)
+ category_mask = DEFAULT_MASK;
+
+ osmo_init_logging(&bts_log_info);
+
+ log_parse_category_mask(osmo_stderr_target, category_mask);
+
+ return 0;
+}
diff --git a/src/common/oml.c b/src/common/oml.c
index 9af09395..92c7848d 100644
--- a/src/common/oml.c
+++ b/src/common/oml.c
@@ -1,12 +1,13 @@
-/*
- * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+/* GSM TS 12.21 O&M / OML, BTS side */
+
+/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -14,9 +15,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
@@ -28,95 +28,294 @@
#include <sys/types.h>
#include <arpa/inet.h>
+#include <osmocom/core/talloc.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/gsm/abis_nm.h>
+
#include <osmo-bts/logging.h>
-//#include <osmocom/bb/common/osmocom_data.h>
-#include <osmo-bts/support.h>
+#include <osmo-bts/gsm_data.h>
#include <osmo-bts/abis.h>
-#include <osmo-bts/rtp.h>
-#include <osmo-bts/bts.h>
-#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
+#include <osmo-bts/bts_model.h>
+
+/* FIXME: move this to libosmocore */
+static struct tlv_definition abis_nm_att_tlvdef_ipa = {
+ .def = {
+ /* ip.access specifics */
+ [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
+ [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
+ [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
+ [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
+ [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
+ [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
+ [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
+ [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
+ [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
+ [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
+ [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
+ },
+};
+
+/* ip.access nanoBTS specific commands */
+static const char ipaccess_magic[] = "com.ipaccess";
/*
* support
*/
-struct osmobts_trx *get_trx_by_nr(struct osmocom_bts *bts, uint8_t trx_nr)
+struct tlv_parsed *tlvp_copy(const struct tlv_parsed *tp_orig, void *ctx)
{
- int max = sizeof(bts->trx) / sizeof(bts->trx[0]);
- struct osmobts_trx *trx;
+ struct tlv_parsed *tp_out;
+ unsigned int i;
- if (trx_nr >= max) {
- LOGP(DOML, LOGL_NOTICE, "Indicated TRX #%d is out of range. (max #%d)\n", trx_nr, max - 1);
+ tp_out = talloc_zero(ctx, struct tlv_parsed);
+ if (!tp_out)
return NULL;
+
+ /* if the original is NULL, return empty tlvp */
+ if (!tp_orig)
+ return tp_out;
+
+ for (i = 0; i < ARRAY_SIZE(tp_orig->lv); i++) {
+ unsigned int len = tp_orig->lv[i].len;
+ tp_out->lv[i].len = len;
+ if (len && tp_out->lv[i].val) {
+ tp_out->lv[i].val = talloc_zero_size(tp_out, len);
+ if (!tp_out->lv[i].val) {
+ talloc_free(tp_out);
+ return NULL;
+ }
+ memcpy((uint8_t *)tp_out->lv[i].val, tp_orig->lv[i].val, len);
+ }
}
- trx = bts->trx[trx_nr];
- if (!trx) {
- LOGP(DOML, LOGL_NOTICE, "Indicated TRX #%d does not exist.\n", trx_nr);
- return NULL;
+ return tp_out;
+}
+
+/* merge all attributes of 'new' into 'out' */
+int tlvp_merge(struct tlv_parsed *out, const struct tlv_parsed *new)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(out->lv); i++) {
+ unsigned int len = new->lv[i].len;
+ if (len == 0 || new->lv[i].val == NULL)
+ continue;
+ if (out->lv[i].val) {
+ talloc_free((uint8_t *) out->lv[i].val);
+ out->lv[i].len = 0;
+ }
+ out->lv[i].val = talloc_zero_size(out, len);
+ if (!out->lv[i].val)
+ return -ENOMEM;
+ memcpy((uint8_t *) out->lv[i].val, new->lv[i].val, len);
}
+ return 0;
+}
- return trx;
+static int oml_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len)
+{
+ return tlv_parse(tp, &abis_nm_att_tlvdef_ipa, buf, len, 0, 0);
}
-struct osmobts_slot *get_slot_by_nr(struct osmobts_trx *trx, uint8_t slot_nr)
+struct msgb *oml_msgb_alloc(void)
{
- struct osmobts_slot *slot;
+ return msgb_alloc_headroom(1024, 128, "OML");
+}
- if (slot_nr >= 8) {
- LOGP(DOML, LOGL_NOTICE, "Indicated Slot #%d is out of range. (max #8)\n", slot_nr);
- return NULL;
+int oml_send_msg(struct msgb *msg, int is_manuf)
+{
+ struct abis_om_hdr *omh;
+
+ if (is_manuf) {
+ /* length byte, string + 0 termination */
+ uint8_t *manuf = msgb_push(msg, 1 + sizeof(ipaccess_magic));
+ manuf[0] = strlen(ipaccess_magic)+1;
+ memcpy(manuf+1, ipaccess_magic, strlen(ipaccess_magic));
}
- slot = &trx->slot[slot_nr];
+ /* Push the main OML header and send it off */
+ omh = (struct abis_om_hdr *) msgb_push(msg, sizeof(*omh));
+ if (is_manuf)
+ omh->mdisc = ABIS_OM_MDISC_MANUF;
+ else
+ omh->mdisc = ABIS_OM_MDISC_FOM;
+ omh->placement = ABIS_OM_PLACEMENT_ONLY;
+ omh->sequence = 0;
+ omh->length = msgb_l3len(msg);
+
+ msg->l2h = (uint8_t *)omh;
+
+ return abis_oml_sendmsg(msg);
+}
+
+int oml_mo_send_msg(struct gsm_abis_mo *mo, struct msgb *msg, uint8_t msg_type)
+{
+ struct abis_om_fom_hdr *foh;
+
+ msg->l3h = msgb_push(msg, sizeof(*foh));
+ foh = (struct abis_om_fom_hdr *) msg->l3h;
+ foh->msg_type = msg_type;
+ foh->obj_class = mo->obj_class;
+ memcpy(&foh->obj_inst, &mo->obj_inst, sizeof(foh->obj_inst));
+
+ /* FIXME: This assumption may not always be correct */
+ msg->trx = mo->bts->c0;
- return slot;
+ return oml_send_msg(msg, 0);
}
-static struct msgb *fom_msgb_alloc(void)
+/* FIXME: move to gsm_data_shared */
+static char mo_buf[128];
+char *gsm_abis_mo_name(const struct gsm_abis_mo *mo)
+{
+ snprintf(mo_buf, sizeof(mo_buf), "OC=%s INST=(%02x,%02x,%02x)",
+ get_value_string(abis_nm_obj_class_names, mo->obj_class),
+ mo->obj_inst.bts_nr, mo->obj_inst.trx_nr, mo->obj_inst.ts_nr);
+ return mo_buf;
+}
+
+/* 8.8.1 sending State Changed Event Report */
+int oml_tx_state_changed(struct gsm_abis_mo *mo,
+ uint8_t op_state, uint8_t avail_status)
{
struct msgb *nmsg;
- nmsg = abis_msgb_alloc(sizeof(struct abis_om_hdr));
+ LOGP(DOML, LOGL_INFO, "%s Tx STATE CHG REP\n", gsm_abis_mo_name(mo));
+
+ nmsg = oml_msgb_alloc();
if (!nmsg)
- return NULL;
- return nmsg;
+ return -ENOMEM;
+
+ /* 9.4.38 Operational State */
+ msgb_tv_put(nmsg, NM_ATT_OPER_STATE, op_state);
+
+ /* 9.4.7 Availability Status */
+ msgb_tl16v_put(nmsg, NM_ATT_AVAIL_STATUS, 1, &avail_status);
+
+ return oml_mo_send_msg(mo, nmsg, NM_MT_STATECHG_EVENT_REP);
}
-static void fom_push_om(struct msgb *msg, uint8_t mdisc, uint8_t placement, uint8_t sequence)
+int oml_mo_state_chg(struct gsm_abis_mo *mo, int op_state, int avail_state)
{
- struct abis_om_hdr *noh;
-
- msg->l3h = msg->data;
- noh = (struct abis_om_hdr *) msgb_push(msg, sizeof(*noh));
- noh->mdisc = mdisc;
- noh->placement = placement;
- noh->sequence = sequence;
- noh->length = msgb_l3len(msg);
+ int rc = 0;
+
+ if ((op_state != -1 && mo->nm_state.operational != op_state) ||
+ (avail_state != -1 && mo->nm_state.availability != avail_state)) {
+ if (avail_state != -1) {
+ LOGP(DOML, LOGL_INFO, "%s AVAIL STATE %s -> %s\n",
+ gsm_abis_mo_name(mo),
+ abis_nm_avail_name(mo->nm_state.availability),
+ abis_nm_avail_name(avail_state));
+ mo->nm_state.availability = avail_state;
+ }
+ if (op_state != -1) {
+ LOGP(DOML, LOGL_INFO, "%s OPER STATE %s -> %s\n",
+ gsm_abis_mo_name(mo),
+ abis_nm_opstate_name(mo->nm_state.operational),
+ abis_nm_opstate_name(op_state));
+ mo->nm_state.operational = op_state;
+ }
+
+ /* send state change report */
+ rc = oml_tx_state_changed(mo, op_state, avail_state);
+ }
+ return rc;
}
-static int fom_ack_nack(struct ipabis_link *link, struct msgb *msg, uint8_t cause)
+int oml_mo_fom_ack_nack(struct gsm_abis_mo *mo, uint8_t orig_msg_type,
+ uint8_t cause)
{
- struct abis_om_fom_hdr *foh = msgb_l3(msg);
- uint8_t *ie;
+ struct msgb *msg;
+ uint8_t new_msg_type;
+
+ msg = oml_msgb_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (cause) {
+ new_msg_type = orig_msg_type + 2;
+ msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause);
+ } else {
+ new_msg_type = orig_msg_type + 1;
+ }
+
+ return oml_mo_send_msg(mo, msg, new_msg_type);
+}
+
+int oml_mo_opstart_ack(struct gsm_abis_mo *mo)
+{
+ return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, 0);
+}
+
+int oml_mo_opstart_nack(struct gsm_abis_mo *mo, uint8_t nack_cause)
+{
+ return oml_mo_fom_ack_nack(mo, NM_MT_OPSTART, nack_cause);
+}
+
+int oml_fom_ack_nack(struct msgb *old_msg, uint8_t cause)
+{
+ struct abis_om_hdr *old_oh = msgb_l2(old_msg);
+ struct abis_om_fom_hdr *old_foh = msgb_l3(old_msg);
+ struct msgb *msg = oml_msgb_alloc();
+ struct abis_om_fom_hdr *foh;
+ int is_manuf = 0;
+
+ /* make sure to respond with MANUF if request was MANUF */
+ if (old_oh->mdisc == ABIS_OM_MDISC_MANUF)
+ is_manuf = 1;
+
+ msg->trx = old_msg->trx;
+
+ /* copy over old FOM-Header and later only change the msg_type */
+ msg->l3h = msgb_push(msg, sizeof(*foh));
+ foh = (struct abis_om_fom_hdr *) msg->l3h;
+ memcpy(foh, old_foh, sizeof(*foh));
/* alter message type */
if (cause) {
- LOGP(DOML, LOGL_NOTICE, "Sending FOM NACK with cause %d.\n", cause);
+ LOGP(DOML, LOGL_NOTICE, "Sending FOM NACK with cause %s.\n",
+ abis_nm_nack_cause_name(cause));
foh->msg_type += 2; /* nack */
/* add cause */
- ie = msgb_put(msg, 2);
- ie[0] = NM_ATT_NACK_CAUSES;
- ie[1] = cause;
+ msgb_tv_put(msg, NM_ATT_NACK_CAUSES, cause);
} else {
LOGP(DOML, LOGL_NOTICE, "Sending FOM ACK.\n");
foh->msg_type++; /* ack */
}
- return abis_tx(link, msg);
+ return oml_send_msg(msg, is_manuf);
}
/*
@@ -124,246 +323,396 @@ static int fom_ack_nack(struct ipabis_link *link, struct msgb *msg, uint8_t caus
*/
/* 8.3.7 sending SW Activated Report */
-int oml_tx_sw_act_rep(struct ipabis_link *link, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
+int oml_mo_tx_sw_act_rep(struct gsm_abis_mo *mo)
{
struct msgb *nmsg;
struct abis_om_fom_hdr *nofh;
- LOGP(DOML, LOGL_INFO, "Sending SW Activated Report (%02x,%02x,%02x).\n", bts_nr, trx_nr, ts_nr);
+ LOGP(DOML, LOGL_INFO, "%s Tx SW ACT REP\n", gsm_abis_mo_name(mo));
- nmsg = fom_msgb_alloc();
+ nmsg = oml_msgb_alloc();
if (!nmsg)
return -ENOMEM;
- nofh = (struct abis_om_fom_hdr *) msgb_put(nmsg, sizeof(*nofh));
- nofh->msg_type = NM_MT_SW_ACTIVATED_REP;
- nofh->obj_class = obj_class;
- nofh->obj_inst.bts_nr = bts_nr;
- nofh->obj_inst.trx_nr = trx_nr;
- nofh->obj_inst.ts_nr = ts_nr;
- fom_push_om(nmsg, ABIS_OM_MDISC_FOM, ABIS_OM_PLACEMENT_ONLY, 0);
- abis_push_ipa(nmsg, IPA_PROTO_OML);
-
- return abis_tx(link, nmsg);
-}
-/* 8.8.1 sending State Changed Event Report */
-int oml_tx_state_changed(struct ipabis_link *link, uint8_t op_state, uint8_t avail_status, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr)
-{
- struct msgb *nmsg;
- struct abis_om_fom_hdr *nofh;
- uint8_t *ie;
-
- LOGP(DOML, LOGL_INFO, "Sending state change (bts=%02x trx=%02x ts=%02x).\n", bts_nr, trx_nr, ts_nr);
-
- nmsg = fom_msgb_alloc();
- if (!nmsg)
- return -ENOMEM;
nofh = (struct abis_om_fom_hdr *) msgb_put(nmsg, sizeof(*nofh));
- nofh->msg_type = NM_MT_STATECHG_EVENT_REP;
- nofh->obj_class = obj_class;
- nofh->obj_inst.bts_nr = bts_nr;
- nofh->obj_inst.trx_nr = trx_nr;
- nofh->obj_inst.ts_nr = ts_nr;
- /* 9.4.38 Operational State */
- ie = msgb_put(nmsg, 2);
- ie[0] = NM_ATT_OPER_STATE;
- ie[1] = op_state;
- /* 9.4.7 Availability Status */
- ie = msgb_put(nmsg, 4);
- ie[0] = NM_ATT_AVAIL_STATUS;
- ie[1] = 0;
- ie[2] = 1;
- ie[3] = avail_status;
- fom_push_om(nmsg, ABIS_OM_MDISC_FOM, ABIS_OM_PLACEMENT_ONLY, 0);
- abis_push_ipa(nmsg, IPA_PROTO_OML);
-
- return abis_tx(link, nmsg);
+
+ return oml_mo_send_msg(mo, nmsg, NM_MT_SW_ACTIVATED_REP);
}
-/* 8.6.1 Set BTS Attributes is received */
-int oml_rx_set_bts_attr(struct osmocom_bts *bts, struct msgb *msg)
+/* TS 12.21 9.4.53 */
+enum abis_nm_t200_idx {
+ T200_SDCCH = 0,
+ T200_FACCH_F = 1,
+ T200_FACCH_H = 2,
+ T200_SACCH_TCH_SAPI0 = 3,
+ T200_SACCH_SDCCH = 4,
+ T200_SDCCH_SAPI3 = 5,
+ T200_SACCH_TCH_SAPI3 = 6
+};
+
+/* TS 12.21 9.4.53 */
+static const uint8_t abis_nm_t200_mult[] = {
+ [T200_SDCCH] = 5,
+ [T200_FACCH_F] = 5,
+ [T200_FACCH_H] = 5,
+ [T200_SACCH_TCH_SAPI0] = 10,
+ [T200_SACCH_SDCCH] = 10,
+ [T200_SDCCH_SAPI3] = 5,
+ [T200_SACCH_TCH_SAPI3] = 10
+};
+
+/* 8.6.1 Set BTS Attributes has been received */
+static int oml_rx_set_bts_attr(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- struct tlv_parsed tp;
- struct bts_support *sup = &bts_support;
+ struct tlv_parsed tp, *tp_merged;
+ struct gsm_bts_role_bts *btsb = bts_role_bts(bts);
+ int rc, i;
+ const uint8_t *payload;
- LOGP(DOML, LOGL_INFO, "BSC is setting BTS attributes:\n");
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "Rx SET BTS ATTR\n");
- tlv_parse(&tp, &abis_nm_att_tlvdef, foh->data, msgb_l3len(msg) - sizeof(*foh), 0, 0);
- /* 9.4.31 Maximum Timing Advance */
- if (TLVP_PRESENT(&tp, NM_ATT_MAX_TA)) {
- uint16_t *fn = (uint16_t *) TLVP_VAL(&tp, NM_ATT_START_TIME);
- bts->max_ta = ntohs(*fn);
- LOGP(DOML, LOGL_INFO, " Maximum TA = %d\n", bts->max_ta);
- }
- /* 9.4.8 BCCH ARFCN */
+ rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+
+ /* Test for globally unsupported stuff here */
if (TLVP_PRESENT(&tp, NM_ATT_BCCH_ARFCN)) {
- uint16_t *value = (uint16_t *) TLVP_VAL(&tp, NM_ATT_BCCH_ARFCN);
+ const uint16_t *value = (uint16_t *) TLVP_VAL(&tp, NM_ATT_BCCH_ARFCN);
uint16_t arfcn = ntohs(*value);
- LOGP(DOML, LOGL_INFO, " ARFCN = %d", bts->bcch_arfcn);
- if (arfcn > 1023 || !(sup->freq_map[arfcn >> 3] & (1 << (arfcn & 0x7)))) {
+ if (arfcn > 1024) {
LOGP(DOML, LOGL_NOTICE, "Given ARFCN %d is not supported.\n", arfcn);
- return fom_ack_nack(&bts->link, msg, NM_NACK_FREQ_NOTAVAIL);
+ return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL);
}
- bts->bcch_arfcn = arfcn;
- }
- /* 9.4.9 BSIC */
- if (TLVP_PRESENT(&tp, NM_ATT_BSIC)) {
- uint8_t *bsic = (uint8_t *) TLVP_VAL(&tp, NM_ATT_BSIC);
- bts->bcc = *bsic & 0x7;
- bts->ncc = (*bsic >> 3) & 0x7;
- LOGP(DOML, LOGL_INFO, " BCC = %d\n", bts->bcc);
- LOGP(DOML, LOGL_INFO, " NCC = %d\n", bts->ncc);
}
/* 9.4.52 Starting Time */
if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) {
- uint16_t *fn = (uint16_t *) TLVP_VAL(&tp, NM_ATT_START_TIME);
- bts->start_time = ntohs(*fn);
- LOGP(DOML, LOGL_INFO, " Starting Time = %d\n", bts->start_time);
+ return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
}
- return fom_ack_nack(&bts->link, msg, 0);
+ /* merge existing BTS attributes with new attributes */
+ tp_merged = tlvp_copy(bts->mo.nm_attr, bts);
+ tlvp_merge(tp_merged, &tp);
+
+ /* Ask BTS driver to validate new merged attributes */
+ rc = bts_model_check_oml(bts, foh->msg_type, bts->mo.nm_attr, tp_merged, bts);
+ if (rc < 0) {
+ talloc_free(tp_merged);
+ /* FIXME: send nack? */
+ return rc;
+ }
+
+ /* Success: replace old BTS attributes with new */
+ talloc_free(bts->mo.nm_attr);
+ bts->mo.nm_attr = tp_merged;
+
+ /* ... and actually still parse them */
+
+ /* 9.4.25 Interference Level Boundaries */
+ if (TLVP_PRESENT(&tp, NM_ATT_INTERF_BOUND)) {
+ payload = TLVP_VAL(&tp, NM_ATT_INTERF_BOUND);
+ for (i = 0; i < 6; i++) {
+ int16_t boundary = *payload;
+ btsb->interference.boundary[i] = -1 * boundary;
+ }
+ /* 9.4.24 Intave Parameter */
+ if (TLVP_PRESENT(&tp, NM_ATT_INTAVE_PARAM))
+ btsb->interference.intave = *TLVP_VAL(&tp, NM_ATT_INTAVE_PARAM);
+
+ /* 9.4.14 Connection Failure Criterion */
+ /* ... can be 'operator dependent' and needs to be parsed by bts driver */
+
+ /* 9.4.53 T200 */
+ if (TLVP_PRESENT(&tp, NM_ATT_T200)) {
+ payload = TLVP_VAL(&tp, NM_ATT_T200);
+ for (i = 0; i < ARRAY_SIZE(btsb->t200_ms); i++)
+ btsb->t200_ms[i] = payload[i] * abis_nm_t200_mult[i];
+ }
+
+ /* 9.4.31 Maximum Timing Advance */
+ if (TLVP_PRESENT(&tp, NM_ATT_MAX_TA)) {
+ uint16_t *fn = (uint16_t *) TLVP_VAL(&tp, NM_ATT_MAX_TA);
+ btsb->max_ta = ntohs(*fn);
+ }
+
+ /* 9.4.39 Overload Period */
+ if (TLVP_PRESENT(&tp, NM_ATT_OVERL_PERIOD))
+ btsb->load.overload_period = *TLVP_VAL(&tp, NM_ATT_OVERL_PERIOD);
+
+ /* 9.4.12 CCCH Load Threshold */
+ if (TLVP_PRESENT(&tp, NM_ATT_CCCH_L_T))
+ btsb->load.ccch.load_ind_thresh = *TLVP_VAL(&tp, NM_ATT_CCCH_L_T);
+
+ /* 9.4.11 CCCH Load Indication Period */
+ if (TLVP_PRESENT(&tp, NM_ATT_CCCH_L_I_P))
+ btsb->load.ccch.load_ind_period = *TLVP_VAL(&tp, NM_ATT_CCCH_L_I_P);
+
+ /* 9.4.44 RACH Busy Threshold */
+ if (TLVP_PRESENT(&tp, NM_ATT_RACH_B_THRESH)) {
+ int16_t thresh = *TLVP_VAL(&tp, NM_ATT_RACH_B_THRESH);
+ btsb->load.rach.busy_thresh = -1 * thresh;
+ }
+
+ /* 9.4.45 RACH Load Averaging Slots */
+ if (TLVP_PRESENT(&tp, NM_ATT_LDAVG_SLOTS))
+ payload = TLVP_VAL(&tp, NM_ATT_LDAVG_SLOTS);
+ btsb->load.rach.averaging_slots = ntohs(*(uint16_t *)payload);
+ }
+
+ /* 9.4.10 BTS Air Timer */
+ if (TLVP_PRESENT(&tp, NM_ATT_BTS_AIR_TIMER))
+ btsb->t3105_ms = *TLVP_VAL(&tp, NM_ATT_BTS_AIR_TIMER) * 10;
+
+ /* 9.4.37 NY1 */
+ if (TLVP_PRESENT(&tp, NM_ATT_NY1))
+ btsb->ny1 = *TLVP_VAL(&tp, NM_ATT_NY1);
+
+ /* 9.4.8 BCCH ARFCN */
+ if (TLVP_PRESENT(&tp, NM_ATT_BCCH_ARFCN)) {
+ const uint16_t *value = (uint16_t *) TLVP_VAL(&tp, NM_ATT_BCCH_ARFCN);
+ bts->c0->arfcn = ntohs(*value);
+ }
+ /* 9.4.9 BSIC */
+ if (TLVP_PRESENT(&tp, NM_ATT_BSIC))
+ bts->bsic = *TLVP_VAL(&tp, NM_ATT_BSIC);
+
+ /* call into BTS driver to apply new attributes to hardware */
+ return bts_model_apply_oml(bts, msg, tp_merged, bts);
}
-/* 8.6.2 Set Radio Attributes is received */
-int oml_rx_set_radio_attr(struct osmocom_bts *bts, struct msgb *msg)
+/* 8.6.2 Set Radio Attributes has been received */
+static int oml_rx_set_radio_attr(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- struct tlv_parsed tp;
- struct osmobts_trx *trx;
- struct bts_support *sup = &bts_support;
+ struct tlv_parsed tp, *tp_merged;
+ int rc;
+
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "Rx SET RADIO CARRIER ATTR\n");
+
+ rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+
+ /* merge existing BTS attributes with new attributes */
+ tp_merged = tlvp_copy(trx->mo.nm_attr, trx->bts);
+ tlvp_merge(tp_merged, &tp);
+
+ /* Ask BTS driver to validate new merged attributes */
+ rc = bts_model_check_oml(trx->bts, foh->msg_type, trx->mo.nm_attr, tp_merged, trx);
+ if (rc < 0) {
+ talloc_free(tp_merged);
+ /* FIXME: send NACK */
+ return rc;
+ }
- trx = get_trx_by_nr(bts, foh->obj_inst.trx_nr);
- if (!trx)
- return fom_ack_nack(&bts->link, msg, NM_NACK_TRXNR_UNKN);
+ /* Success: replace old BTS attributes with new */
+ talloc_free(trx->mo.nm_attr);
+ trx->mo.nm_attr = tp_merged;
- LOGP(DOML, LOGL_INFO, "BSC is setting radio attributes:\n");
+ /* ... and actually still parse them */
- tlv_parse(&tp, &abis_nm_att_tlvdef, foh->data, msgb_l3len(msg) - sizeof(*foh), 0, 0);
/* 9.4.47 RF Max Power Reduction */
if (TLVP_PRESENT(&tp, NM_ATT_RF_MAXPOWR_R)) {
- trx->rf_red = *TLVP_VAL(&tp, NM_ATT_RF_MAXPOWR_R);
- LOGP(DOML, LOGL_INFO, " RF Max Power Reduction = %d\n", trx->rf_red);
- } else
- trx->rf_red = 0;
+ trx->max_power_red = *TLVP_VAL(&tp, NM_ATT_RF_MAXPOWR_R);
+ LOGP(DOML, LOGL_INFO, " RF Max Power Reduction = %d\n", trx->max_power_red);
+ }
/* 9.4.5 ARFCN List */
+#if 0
if (TLVP_PRESENT(&tp, NM_ATT_ARFCN_LIST)) {
uint16_t *value = (uint16_t *) TLVP_VAL(&tp, NM_ATT_ARFCN_LIST);
- uint16_t length = *(TLVP_VAL(&tp, NM_ATT_ARFCN_LIST) - 1);
+ uint16_t length = TLVP_LEN(&tp, NM_ATT_ARFCN_LIST);
uint16_t arfcn;
- int max = (sizeof(trx->arfcn_list) / sizeof(trx->arfcn_list[0]));
int i;
- if (length > max) {
- LOGP(DOML, LOGL_NOTICE, "Too many ARFCN given. (max #%d)\n", max);
- return fom_ack_nack(&bts->link, msg, NM_NACK_PARAM_RANGE);
- }
for (i = 0; i < length; i++) {
arfcn = ntohs(*value++);
- if (arfcn > 1023 || !(sup->freq_map[arfcn >> 3] & (1 << (arfcn & 0x7))))
- return fom_ack_nack(&bts->link, msg, NM_NACK_FREQ_NOTAVAIL);
+ if (arfcn > 1024)
+ return oml_fom_ack_nack(msg, NM_NACK_FREQ_NOTAVAIL);
trx->arfcn_list[i] = arfcn;
LOGP(DOML, LOGL_INFO, " ARFCN list = %d\n", trx->arfcn_list[i]);
}
trx->arfcn_num = length;
} else
trx->arfcn_num = 0;
+#endif
+ /* call into BTS driver to apply new attributes to hardware */
+ return bts_model_apply_oml(trx->bts, msg, tp_merged, trx);
+}
- return fom_ack_nack(&bts->link, msg, 0);
+static int conf_lchans_for_pchan(struct gsm_bts_trx_ts *ts)
+{
+ struct gsm_lchan *lchan;
+ unsigned int i;
+
+ switch (ts->pchan) {
+ case GSM_PCHAN_CCCH_SDCCH4:
+ for (i = 0; i < 4; i++) {
+ lchan = &ts->lchan[i+1];
+ lchan->type = GSM_LCHAN_SDCCH;
+ }
+ /* fallthrough */
+ case GSM_PCHAN_CCCH:
+ lchan = &ts->lchan[0];
+ lchan->type = GSM_LCHAN_CCCH;
+ break;
+ case GSM_PCHAN_TCH_F:
+ lchan = &ts->lchan[0];
+ lchan->type = GSM_LCHAN_TCH_F;
+ break;
+ case GSM_PCHAN_TCH_H:
+ for (i = 0; i < 2; i++) {
+ lchan = &ts->lchan[i];
+ lchan->type = GSM_LCHAN_TCH_H;
+ }
+ break;
+ case GSM_PCHAN_SDCCH8_SACCH8C:
+ for (i = 0; i < 8; i++) {
+ lchan = &ts->lchan[i];
+ lchan->type = GSM_LCHAN_SDCCH;
+ }
+ break;
+ default:
+ /* FIXME */
+ break;
+ }
+ return 0;
}
-/* 8.6.3 Set Channel Attributes is received */
-int oml_rx_set_chan_attr(struct osmocom_bts *bts, struct msgb *msg)
+/* 8.6.3 Set Channel Attributes has been received */
+static int oml_rx_set_chan_attr(struct gsm_bts_trx_ts *ts, struct msgb *msg)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- struct tlv_parsed tp;
- struct osmobts_trx *trx;
- struct osmobts_slot *slot;
- struct bts_support *sup = &bts_support;
+ struct gsm_bts *bts = ts->trx->bts;
+ struct tlv_parsed tp, *tp_merged;
+ int rc;
+
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "Rx SET CHAN ATTR\n");
- trx = get_trx_by_nr(bts, foh->obj_inst.trx_nr);
- if (!trx)
- return fom_ack_nack(&bts->link, msg, NM_NACK_TRXNR_UNKN);
- slot = get_slot_by_nr(trx, foh->obj_inst.ts_nr);
- if (!slot)
- return fom_ack_nack(&bts->link, msg, NM_NACK_OBJINST_UNKN);
+ rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
+ if (rc < 0)
+ return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
- LOGP(DOML, LOGL_INFO, "BSC is setting channel attributes:\n");
+ /* 9.4.21 HSN... */
+ /* 9.4.27 MAIO */
+ if (TLVP_PRESENT(&tp, NM_ATT_HSN) || TLVP_PRESENT(&tp, NM_ATT_MAIO)) {
+ LOGP(DOML, LOGL_NOTICE, "SET CHAN ATTR: Frequency hopping not supported.\n");
+ return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
+ }
+
+ /* 9.4.52 Starting Time */
+ if (TLVP_PRESENT(&tp, NM_ATT_START_TIME)) {
+ LOGP(DOML, LOGL_NOTICE, "SET CHAN ATTR: Starting time not supported.\n");
+ return oml_fom_ack_nack(msg, NM_NACK_SPEC_IMPL_NOTSUPP);
+ }
+
+ /* merge existing BTS attributes with new attributes */
+ tp_merged = tlvp_copy(bts->mo.nm_attr, bts);
+ tlvp_merge(tp_merged, &tp);
+
+ /* Call into BTS driver to check attribute values */
+ rc = bts_model_check_oml(bts, foh->msg_type, ts->mo.nm_attr, tp_merged, ts);
+ if (rc < 0) {
+ talloc_free(&tp_merged);
+ /* FIXME: Send NACK */
+ return rc;
+ }
- tlv_parse(&tp, &abis_nm_att_tlvdef, foh->data, msgb_l3len(msg) - sizeof(*foh), 0, 0);
/* 9.4.13 Channel Combination */
if (TLVP_PRESENT(&tp, NM_ATT_CHAN_COMB)) {
uint8_t comb = *TLVP_VAL(&tp, NM_ATT_CHAN_COMB);
- if (!sup->chan_comb[comb]) {
- LOGP(DOML, LOGL_NOTICE, " channel combination %d (not supported).\n", comb);
- return fom_ack_nack(&bts->link, msg, NM_NACK_SPEC_IMPL_NOTSUPP);
- }
- LOGP(DOML, LOGL_INFO, " channel combination = %s\n", bts_support_comb_name(comb));
- bts_setup_slot(slot, comb);
- slot->chan_comb = comb;
+ ts->pchan = abis_nm_pchan4chcomb(comb);
+ conf_lchans_for_pchan(ts);
}
- /* 9.4.21 HSN... */
- if (TLVP_PRESENT(&tp, NM_ATT_HSN)) {
- LOGP(DOML, LOGL_NOTICE, "Frequency hopping not supported.\n");
- return fom_ack_nack(&bts->link, msg, NM_NACK_SPEC_IMPL_NOTSUPP);
+
+ /* 9.4.5 ARFCN List */
+
+ /* 9.4.60 TSC */
+ if (TLVP_PRESENT(&tp, NM_ATT_TSC) && TLVP_LEN(&tp, NM_ATT_TSC) >= 1) {
+ ts->tsc = *TLVP_VAL(&tp, NM_ATT_TSC);
+ } else {
+ /* If there is no TSC specified, use the BCC */
+ ts->tsc = bts->bsic & 0x3;
}
+ DEBUGP(DOML, "TS %u, settig TSC = %u\n", ts->nr, ts->tsc);
- return fom_ack_nack(&bts->link, msg, 0);
+ /* call into BTS driver to apply new attributes to hardware */
+ return bts_model_apply_oml(bts, msg, tp_merged, ts);
}
-/* 8.9.2 Opstart is received */
-int oml_rx_opstart(struct osmocom_bts *bts, struct msgb *msg)
+/* 8.9.2 Opstart has been received */
+static int oml_rx_opstart(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
- struct osmobts_trx *trx;
- struct osmobts_slot *slot;
-
-
- /* site manager */
- if (foh->obj_inst.bts_nr == 0xff) {
- LOGP(DOML, LOGL_INFO, "BSC is sending Opstart. (Site Manager)\n");
- oml_tx_state_changed(&bts->link, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, NM_OC_SITE_MANAGER, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
- return fom_ack_nack(&bts->link, msg, 0);
- }
-
-#warning todo: change state
- /* BTS */
- if (foh->obj_inst.trx_nr == 0xff) {
- LOGP(DOML, LOGL_INFO, "BSC is sending Opstart. (BTS)\n");
- return fom_ack_nack(&bts->link, msg, 0);
- }
-
- /* TRX */
- trx = get_trx_by_nr(bts, foh->obj_inst.trx_nr);
- if (!trx)
- return fom_ack_nack(&bts->link, msg, NM_NACK_TRXNR_UNKN);
- if (foh->obj_inst.ts_nr == 0xff) {
- LOGP(DOML, LOGL_INFO, "BSC is sending Opstart. (TRX %d)\n", trx->trx_nr);
- if (trx->link.state == LINK_STATE_IDLE) {
- int ret;
-
- /* connecting TRX */
- ret = abis_open(&trx->link, bts->link.ip);
- if (ret <= 0) {
- LOGP(DOML, LOGL_ERROR, "Failed to connect TRX.\n");
- return fom_ack_nack(&bts->link, msg, NM_NACK_CANT_PERFORM);
- }
- }
- return fom_ack_nack(&bts->link, msg, 0);
+ struct gsm_abis_mo *mo;
+ void *obj;
+
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "Rx OPSTART\n");
+
+ /* Step 1: Resolve MO by obj_class/obj_inst */
+ mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
+ obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
+ if (!mo || !obj)
+ return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+
+ /* Step 2: Do some global dependency/consistency checking */
+ if (mo->nm_state.operational == NM_OPSTATE_ENABLED) {
+ DEBUGP(DOML, "... automatic ACK, OP state already was Enabled\n");
+ return oml_mo_opstart_ack(mo);
+ }
+
+ /* Step 3: Ask BTS driver to apply the opstart */
+ return bts_model_opstart(bts, mo, obj);
+}
+
+static int oml_rx_chg_adm_state(struct gsm_bts *bts, struct msgb *msg)
+{
+ struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct tlv_parsed tp;
+ struct gsm_abis_mo *mo;
+ uint8_t adm_state;
+ void *obj;
+ int rc;
+
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "Rx CHG ADM STATE\n");
+
+ rc = oml_tlv_parse(&tp, foh->data, msgb_l3len(msg) - sizeof(*foh));
+ if (rc < 0) {
+ LOGP(DOML, LOGL_ERROR, "Rx CHG ADM STATE: error during TLV parse\n");
+ return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
}
- /* slot */
- slot = get_slot_by_nr(trx, foh->obj_inst.ts_nr);
- if (!slot)
- return fom_ack_nack(&bts->link, msg, NM_NACK_OBJINST_UNKN);
+ if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
+ LOGP(DOML, LOGL_ERROR, "Rx CHG ADM STATE: no ADM state attribute\n");
+ return oml_fom_ack_nack(msg, NM_NACK_INCORR_STRUCT);
+ }
+
+ adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
+
+ /* Step 1: Resolve MO by obj_class/obj_inst */
+ mo = gsm_objclass2mo(bts, foh->obj_class, &foh->obj_inst);
+ obj = gsm_objclass2obj(bts, foh->obj_class, &foh->obj_inst);
+ if (!mo || !obj)
+ return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
- LOGP(DOML, LOGL_INFO, "BSC is sending Opstart. (trx=%d ts=%d)\n", trx->trx_nr, slot->slot_nr);
- oml_tx_state_changed(&bts->link, NM_OPSTATE_ENABLED, NM_AVSTATE_OK, NM_OC_CHANNEL, foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
- return fom_ack_nack(&bts->link, msg, 0);
+ /* Step 2: Do some global dependency/consistency checking */
+ if (mo->nm_state.administrative == adm_state) {
+ DEBUGP(DOML, "... automatic ACK, ADM state already was %s\n",
+ get_value_string(abis_nm_adm_state_names, adm_state));
+ return oml_fom_ack_nack(msg, 0);
+ }
+
+ /* Step 3: Ask BTS driver to apply the state chg */
+ return bts_model_chg_adm_state(bts, mo, obj, adm_state);
}
-static int down_fom(struct osmocom_bts *bts, struct msgb *msg)
+static int down_fom(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct gsm_bts_trx *trx;
int ret;
if (msgb_l2len(msg) < sizeof(*foh)) {
@@ -374,7 +723,7 @@ static int down_fom(struct osmocom_bts *bts, struct msgb *msg)
if (foh->obj_inst.bts_nr != 0 && foh->obj_inst.bts_nr != 0xff) {
LOGP(DOML, LOGL_INFO, "Formatted O&M with BTS %d out of range.\n", foh->obj_inst.bts_nr);
- return fom_ack_nack(&bts->link, msg, NM_NACK_BTSNR_UNKN);
+ return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN);
}
switch (foh->msg_type) {
@@ -382,22 +731,29 @@ static int down_fom(struct osmocom_bts *bts, struct msgb *msg)
ret = oml_rx_set_bts_attr(bts, msg);
break;
case NM_MT_SET_RADIO_ATTR:
- ret = oml_rx_set_radio_attr(bts, msg);
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (!trx)
+ return oml_fom_ack_nack(msg, NM_NACK_TRXNR_UNKN);
+ ret = oml_rx_set_radio_attr(trx, msg);
break;
case NM_MT_SET_CHAN_ATTR:
- ret = oml_rx_set_chan_attr(bts, msg);
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ if (!trx)
+ return oml_fom_ack_nack(msg, NM_NACK_TRXNR_UNKN);
+ if (foh->obj_inst.ts_nr >= ARRAY_SIZE(trx->ts))
+ return oml_fom_ack_nack(msg, NM_NACK_OBJINST_UNKN);
+ ret = oml_rx_set_chan_attr(&trx->ts[foh->obj_inst.ts_nr], msg);
break;
case NM_MT_OPSTART:
ret = oml_rx_opstart(bts, msg);
break;
case NM_MT_CHG_ADM_STATE:
- LOGP(DOML, LOGL_INFO, "BSC is changing ADM state.\n");
- ret = fom_ack_nack(&bts->link, msg, 0);
+ ret = oml_rx_chg_adm_state(bts, msg);
break;
default:
LOGP(DOML, LOGL_INFO, "unknown Formatted O&M msg_type 0x%02x\n",
foh->msg_type);
- ret = fom_ack_nack(&bts->link, msg, NM_NACK_MSGTYPE_INVAL);
+ ret = oml_fom_ack_nack(msg, NM_NACK_MSGTYPE_INVAL);
}
return ret;
@@ -407,37 +763,107 @@ static int down_fom(struct osmocom_bts *bts, struct msgb *msg)
* manufacturer related messages
*/
-static int down_mom(struct osmocom_bts *bts, struct msgb *msg)
+
+static int rx_oml_ipa_rsl_connect(struct gsm_bts_trx *trx, struct msgb *msg,
+ struct tlv_parsed *tp)
{
- struct abis_om_fom_hdr *foh = msgb_l3(msg);
+ struct ipabis_link *oml_link = (struct ipabis_link *) trx->bts->oml_link;
+ uint16_t port = IPA_TCP_PORT_RSL;
+ uint32_t ip = oml_link->ip;
+ struct in_addr in;
+ int rc;
+
+ uint8_t stream_id = 0;
+
+ DEBUGP(DOML, "Rx IPA RSL CONNECT ");
+
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP)) {
+ const uint8_t *ptr = TLVP_VAL(tp, NM_ATT_IPACC_DST_IP);
+ ip = ntohl(*(uint32_t *)ptr);
+ }
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_DST_IP_PORT)) {
+ const uint8_t *ptr = TLVP_VAL(tp, NM_ATT_IPACC_DST_IP_PORT);
+ port = ntohs(*(uint16_t *)ptr);
+ }
+ if (TLVP_PRESENT(tp, NM_ATT_IPACC_STREAM_ID)) {
+ stream_id = *TLVP_VAL(tp, NM_ATT_IPACC_STREAM_ID);
+ }
+
+ in.s_addr = htonl(ip);
+ DEBUGPC(DOML, "IP=%s PORT=%u STREAM=0x%02x\n", inet_ntoa(in),
+ port, stream_id);
+
+ if (!trx->rsl_link) {
+ struct ipabis_link *rsl_link = talloc_zero(trx, struct ipabis_link);
+ rsl_link->trx = trx;
+ trx->rsl_link = rsl_link;
+ }
+
+ /* FIXME: we cannot even use a non-standard port here */
+ rc = abis_open(trx->rsl_link, ip);
+ if (rc < 0) {
+ LOGP(DOML, LOGL_ERROR, "Error in abis_open(RSL): %d\n", rc);
+ return oml_fom_ack_nack(msg, NM_NACK_CANT_PERFORM);
+ }
+
+ return oml_fom_ack_nack(msg, 0);
+}
+
+static int down_mom(struct gsm_bts *bts, struct msgb *msg)
+{
+ struct abis_om_hdr *oh = msgb_l2(msg);
+ struct abis_om_fom_hdr *foh;
+ struct gsm_bts_trx *trx;
+ uint8_t idstrlen = oh->data[0];
+ struct tlv_parsed tp;
int ret;
+ DEBUGP(DOML, "Manufacturer OML message\n");
+
if (msgb_l2len(msg) < sizeof(*foh)) {
LOGP(DOML, LOGL_NOTICE, "Manufacturer O&M message too short\n");
msgb_free(msg);
return -EIO;
}
+ if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
+ LOGP(DOML, LOGL_ERROR, "Manufacturer OML message != ipaccess not supported\n");
+ return -EINVAL;
+ }
+
+ msg->l3h = oh->data + 1 + idstrlen;
+ foh = (struct abis_om_fom_hdr *) msg->l3h;
+
if (foh->obj_inst.bts_nr != 0 && foh->obj_inst.bts_nr != 0xff) {
LOGP(DOML, LOGL_INFO, "Manufacturer O&M with BTS %d out of range.\n", foh->obj_inst.bts_nr);
- return fom_ack_nack(&bts->link, msg, NM_NACK_BTSNR_UNKN);
+ return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN);
+ }
+
+ ret = oml_tlv_parse(&tp, foh->data, oh->length - sizeof(*foh));
+ if (ret < 0) {
+ LOGP(DOML, LOGL_ERROR, "TLV parse error %d\n", ret);
+ return oml_fom_ack_nack(msg, NM_NACK_BTSNR_UNKN);
}
+ abis_nm_debugp_foh(DOML, foh);
+ DEBUGPC(DOML, "IPACCESS(0x%02x): ", foh->msg_type);
+
switch (foh->msg_type) {
+ case NM_MT_IPACC_RSL_CONNECT:
+ trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
+ ret = rx_oml_ipa_rsl_connect(trx, msg, &tp);
+ break;
default:
LOGP(DOML, LOGL_INFO, "Manufacturer Formatted O&M msg_type 0x%02x\n",
foh->msg_type);
- ret = fom_ack_nack(&bts->link, msg, NM_NACK_MSGTYPE_INVAL);
+ ret = oml_fom_ack_nack(msg, NM_NACK_MSGTYPE_INVAL);
}
return ret;
}
-/*
- * selecting messages
- */
-
-int down_oml(struct osmocom_bts *bts, struct msgb *msg)
+/* incoming OML message from BSC */
+int down_oml(struct gsm_bts *bts, struct msgb *msg)
{
struct abis_om_hdr *oh = msgb_l2(msg);
int ret = 0;
@@ -478,4 +904,10 @@ int down_oml(struct osmocom_bts *bts, struct msgb *msg)
return ret;
}
+int oml_init(void)
+{
+ DEBUGP(DOML, "Initializing OML attribute definitions\n");
+ tlv_def_patch(&abis_nm_att_tlvdef_ipa, &abis_nm_att_tlvdef);
+ return 0;
+}
diff --git a/src/common/paging.c b/src/common/paging.c
new file mode 100644
index 00000000..0f51d753
--- /dev/null
+++ b/src/common/paging.c
@@ -0,0 +1,440 @@
+/* Paging message encoding + queue management */
+
+/* (C) 2011 by Harald Welte <laforge@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 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/>.
+ *
+ */
+
+/* TODO:
+ * eMLPP priprity
+ * add P1/P2/P3 rest octets
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/linuxlist.h>
+
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+#include <osmocom/gsm/gsm0502.h>
+
+#include <osmo-bts/bts.h>
+#include <osmo-bts/rsl.h>
+#include <osmo-bts/logging.h>
+#include <osmo-bts/paging.h>
+#include <osmo-bts/signal.h>
+
+#define MAX_PAGING_BLOCKS_CCCH 9
+#define MAX_BS_PA_MFRMS 9
+
+struct paging_record {
+ struct llist_head list;
+ time_t expiration_time;
+ uint8_t chan_needed;
+ uint8_t identity_lv[9];
+};
+
+struct paging_state {
+ /* parameters taken / interpreted from BCCH/CCCH configuration */
+ struct gsm48_control_channel_descr chan_desc;
+
+ /* configured otherwise */
+ unsigned int paging_lifetime; /* in seconds */
+ unsigned int num_paging_max;
+
+ /* total number of currently active paging records in queue */
+ unsigned int num_paging;
+ struct llist_head paging_queue[MAX_PAGING_BLOCKS_CCCH*MAX_BS_PA_MFRMS];
+};
+
+static int tmsi_mi_to_uint(uint32_t *out, const uint8_t *tmsi_lv)
+{
+ if (tmsi_lv[0] < 5)
+ return -EINVAL;
+ if ((tmsi_lv[1] & 7) != GSM_MI_TYPE_TMSI)
+ return -EINVAL;
+
+ *out = *((uint32_t *)(tmsi_lv+2));
+
+ return 0;
+}
+
+/* paging block numbers in a simple non-combined CCCH */
+static const uint8_t block_by_tdma51[51] = {
+ 255, 255, /* FCCH, SCH */
+ 255, 255, 255, 255, /* BCCH */
+ 0, 0, 0, 0, /* B0(6..9) */
+ 255, 255, /* FCCH, SCH */
+ 1, 1, 1, 1, /* B1(12..15) */
+ 2, 2, 2, 2, /* B2(16..19) */
+ 255, 255, /* FCCH, SCH */
+ 3, 3, 3, 3, /* B3(22..25) */
+ 4, 4, 4, 4, /* B3(26..29) */
+ 255, 255, /* FCCH, SCH */
+ 5, 5, 5, 5, /* B3(32..35) */
+ 6, 6, 6, 6, /* B3(36..39) */
+ 255, 255, /* FCCH, SCH */
+ 7, 7, 7, 7, /* B3(42..45) */
+ 8, 8, 8, 8, /* B3(46..49) */
+ 255, /* empty */
+};
+
+/* get the paging block number _within_ current 51 multiframe */
+static int get_pag_idx_n(struct paging_state *ps, struct gsm_time *gt)
+{
+ int blk_n = block_by_tdma51[gt->t3];
+ int blk_idx;
+
+ if (blk_n == 255)
+ return -EINVAL;
+
+ blk_idx = blk_n - ps->chan_desc.bs_ag_blks_res;
+ if (blk_idx < 0)
+ return -EINVAL;
+
+ return blk_idx;
+}
+
+/* get paging block index over multiple 51 multiframes */
+static int get_pag_subch_nr(struct paging_state *ps, struct gsm_time *gt)
+{
+ int pag_idx = get_pag_idx_n(ps, gt);
+ unsigned int n_pag_blks_51 = gsm0502_get_n_pag_blocks(&ps->chan_desc);
+ unsigned int mfrm_part;
+
+ if (pag_idx < 0)
+ return pag_idx;
+
+ mfrm_part = ((gt->fn / 51) % (ps->chan_desc.bs_pa_mfrms+2)) * n_pag_blks_51;
+
+ return pag_idx + mfrm_part;
+}
+
+
+/* Add an identity to the paging queue */
+int paging_add_identity(struct paging_state *ps, uint8_t paging_group,
+ const uint8_t *identity_lv, uint8_t chan_needed)
+{
+ struct llist_head *group_q = &ps->paging_queue[paging_group];
+ struct paging_record *pr;
+
+ if (ps->num_paging >= ps->num_paging_max) {
+ LOGP(DPAG, LOGL_NOTICE, "Dropping paging, queue full (%u)\n",
+ ps->num_paging);
+ return -ENOSPC;
+ }
+
+ /* Check if we already have this identity */
+ llist_for_each_entry(pr, group_q, list) {
+ if (identity_lv[0] == pr->identity_lv[0] &&
+ !memcmp(identity_lv+1, pr->identity_lv+1, identity_lv[0])) {
+ LOGP(DPAG, LOGL_INFO, "Ignoring duplicate paging\n");
+ pr->expiration_time = time(NULL) + ps->paging_lifetime;
+ return -EEXIST;
+ }
+ }
+
+ pr = talloc_zero(ps, struct paging_record);
+ if (!pr)
+ return -ENOMEM;
+
+ if (*identity_lv + 1 > sizeof(pr->identity_lv)) {
+ talloc_free(pr);
+ return -E2BIG;
+ }
+
+ LOGP(DPAG, LOGL_INFO, "Add paging to queue (group=%u, queue_len=%u)\n",
+ paging_group, ps->num_paging+1);
+
+ pr->expiration_time = time(NULL) + ps->paging_lifetime;
+ pr->chan_needed = chan_needed;
+ memcpy(&pr->identity_lv, identity_lv, identity_lv[0]+1);
+
+ /* enqueue the new identity to the HEAD of the queue,
+ * to ensure it will be paged quickly at least once. */
+ llist_add(&pr->list, group_q);
+ ps->num_paging++;
+
+ return 0;
+}
+
+static int fill_paging_type_1(uint8_t *out_buf, const uint8_t *identity1_lv,
+ uint8_t chan1, const uint8_t *identity2_lv,
+ uint8_t chan2)
+{
+ struct gsm48_paging1 *pt1 = (struct gsm48_paging1 *) out_buf;
+ uint8_t *cur;
+
+ memset(out_buf, 0, sizeof(*pt1));
+
+ pt1->proto_discr = GSM48_PDISC_RR;
+ pt1->msg_type = GSM48_MT_RR_PAG_REQ_1;
+ pt1->pag_mode = GSM48_PM_NORMAL;
+ pt1->cneed1 = chan1 & 3;
+ pt1->cneed2 = chan2 & 3;
+ cur = lv_put(pt1->data, identity1_lv[0], identity1_lv+1);
+ if (identity2_lv)
+ cur = lv_put(cur, identity2_lv[0], identity2_lv+1);
+
+ pt1->l2_plen = cur - out_buf - 1;
+
+ return cur - out_buf;
+}
+
+static int fill_paging_type_2(uint8_t *out_buf, const uint8_t *tmsi1_lv,
+ uint8_t cneed1, const uint8_t *tmsi2_lv,
+ uint8_t cneed2, const uint8_t *identity3_lv)
+{
+ struct gsm48_paging2 *pt2 = (struct gsm48_paging2 *) out_buf;
+ uint8_t *cur;
+
+ memset(out_buf, 0, sizeof(*pt2));
+
+ pt2->proto_discr = GSM48_PDISC_RR;
+ pt2->msg_type = GSM48_MT_RR_PAG_REQ_2;
+ pt2->pag_mode = GSM48_PM_NORMAL;
+ pt2->cneed1 = cneed1;
+ pt2->cneed2 = cneed2;
+ tmsi_mi_to_uint(&pt2->tmsi1, tmsi1_lv);
+ tmsi_mi_to_uint(&pt2->tmsi2, tmsi2_lv);
+ cur = out_buf + sizeof(*pt2);
+
+ if (identity3_lv)
+ cur = lv_put(pt2->data, identity3_lv[0], identity3_lv+1);
+
+ pt2->l2_plen = cur - out_buf -1;
+
+ return cur - out_buf;
+}
+
+static int fill_paging_type_3(uint8_t *out_buf, const uint8_t *tmsi1_lv,
+ uint8_t cneed1, const uint8_t *tmsi2_lv,
+ uint8_t cneed2, const uint8_t *tmsi3_lv,
+ const uint8_t *tmsi4_lv)
+{
+ struct gsm48_paging3 *pt3 = (struct gsm48_paging3 *) out_buf;
+ uint8_t *cur;
+
+ memset(out_buf, 0, sizeof(*pt3));
+
+ pt3->proto_discr = GSM48_PDISC_RR;
+ pt3->msg_type = GSM48_MT_RR_PAG_REQ_3;
+ pt3->pag_mode = GSM48_PM_NORMAL;
+ pt3->cneed1 = cneed1;
+ pt3->cneed2 = cneed2;
+ tmsi_mi_to_uint(&pt3->tmsi1, tmsi1_lv);
+ tmsi_mi_to_uint(&pt3->tmsi2, tmsi2_lv);
+ tmsi_mi_to_uint(&pt3->tmsi3, tmsi3_lv);
+ tmsi_mi_to_uint(&pt3->tmsi4, tmsi4_lv);
+
+ cur = out_buf + sizeof(*pt3);
+
+ return cur - out_buf;
+}
+
+static const uint8_t empty_id_lv[] = { 0x01, 0x00 };
+
+static struct paging_record *dequeue_pr(struct llist_head *group_q)
+{
+ struct paging_record *pr;
+
+ pr = llist_entry(group_q->next, struct paging_record, list);
+ llist_del(&pr->list);
+
+ return pr;
+}
+
+static int pr_is_imsi(struct paging_record *pr)
+{
+ if ((pr->identity_lv[1] & 7) == GSM_MI_TYPE_IMSI)
+ return 1;
+ else
+ return 0;
+}
+
+static void sort_pr_tmsi_imsi(struct paging_record *pr[], unsigned int n)
+{
+ int i, j;
+ struct paging_record *t;
+
+ if (n < 2)
+ return;
+
+ /* simple bubble sort */
+ for (i = n-2; i >= 0; i--) {
+ for (j=0; j<=i ; j++) {
+ if (pr_is_imsi(pr[j]) > pr_is_imsi(pr[j+1])) {
+ t = pr[j];
+ pr[j] = pr[j+1];
+ pr[j+1] = t;
+ }
+ }
+ }
+}
+
+/* generate paging message for given gsm time */
+int paging_gen_msg(struct paging_state *ps, uint8_t *out_buf, struct gsm_time *gt)
+{
+ unsigned int group = get_pag_subch_nr(ps, gt);
+ struct llist_head *group_q = &ps->paging_queue[group];
+ int len;
+
+ /* There is nobody to be paged, send Type1 with two empty ID */
+ if (llist_empty(group_q)) {
+ //DEBUGP(DPAG, "Tx PAGING TYPE 1 (empty)\n");
+ len = fill_paging_type_1(out_buf, empty_id_lv, 0,
+ NULL, 0);
+ } else {
+ struct paging_record *pr[4];
+ unsigned int num_pr = 0;
+ time_t now = time(NULL);
+ unsigned int i, num_imsi = 0;
+
+ /* get (if we have) up to four paging records */
+ for (i = 0; i < ARRAY_SIZE(pr); i++) {
+ if (llist_empty(group_q))
+ break;
+ pr[i] = dequeue_pr(group_q);
+ num_pr++;
+
+ /* count how many IMSIs are among them */
+ if (pr_is_imsi(pr[i]))
+ num_imsi++;
+ }
+
+ /* make sure the TMSIs are ahead of the IMSIs in the array */
+ sort_pr_tmsi_imsi(pr, num_pr);
+
+ if (num_pr == 4 && num_imsi == 0) {
+ /* No IMSI: easy case, can use TYPE 3 */
+ DEBUGP(DPAG, "Tx PAGING TYPE 3 (4 TMSI)\n");
+ len = fill_paging_type_3(out_buf, pr[0]->identity_lv,
+ pr[0]->chan_needed,
+ pr[1]->identity_lv,
+ pr[1]->chan_needed,
+ pr[2]->identity_lv,
+ pr[3]->identity_lv);
+ } else if (num_pr >= 3 && num_imsi <= 1) {
+ /* 3 or 4, of which only up to 1 is IMSI */
+ DEBUGP(DPAG, "Tx PAGING TYPE 2 (2 TMSI,1 xMSI)\n");
+ len = fill_paging_type_2(out_buf,
+ pr[0]->identity_lv,
+ pr[0]->chan_needed,
+ pr[1]->identity_lv,
+ pr[1]->chan_needed,
+ pr[2]->identity_lv);
+ if (num_pr == 4) {
+ /* re-add #4 for next time */
+ llist_add(&pr[3]->list, group_q);
+ pr[3] = NULL;
+ }
+ } else if (num_pr == 1) {
+ DEBUGP(DPAG, "Tx PAGING TYPE 1 (1 xMSI,1 empty)\n");
+ len = fill_paging_type_1(out_buf, pr[0]->identity_lv,
+ pr[0]->chan_needed, NULL, 0);
+ } else {
+ /* 2 (any type) or
+ * 3 or 4, of which only 2 will be sent */
+ DEBUGP(DPAG, "Tx PAGING TYPE 1 (2 xMSI)\n");
+ len = fill_paging_type_1(out_buf, pr[0]->identity_lv,
+ pr[0]->chan_needed,
+ pr[1]->identity_lv,
+ pr[1]->chan_needed);
+ if (num_pr >= 3) {
+ /* re-add #4 for next time */
+ llist_add(&pr[2]->list, group_q);
+ pr[2] = NULL;
+ }
+ if (num_pr == 4) {
+ /* re-add #4 for next time */
+ llist_add(&pr[3]->list, group_q);
+ pr[3] = NULL;
+ }
+ }
+
+ for (i = 0; i < num_pr; i++) {
+ /* skip those that we might have re-added above */
+ if (pr[i] == NULL)
+ continue;
+ /* check if we can expire the paging record,
+ * or if we need to re-queue it */
+ if (pr[i]->expiration_time >= now) {
+ talloc_free(pr[i]);
+ ps->num_paging--;
+ LOGP(DPAG, LOGL_INFO, "Removed paging record, queue_len=%u\n",
+ ps->num_paging);
+ } else
+ llist_add_tail(&pr[i]->list, group_q);
+ }
+ }
+ memset(out_buf+len, 0x2B, GSM_MACBLOCK_LEN-len);
+ return len;
+}
+
+int paging_si_update(struct paging_state *ps, struct gsm48_control_channel_descr *chan_desc)
+{
+ LOGP(DPAG, LOGL_INFO, "Paging SI update\n");
+
+ memcpy(&ps->chan_desc, chan_desc, sizeof(chan_desc));
+
+ /* FIXME: do we need to re-sort the old paging_records? */
+
+ return 0;
+}
+
+static int paging_signal_cbfn(unsigned int subsys, unsigned int signal, void *hdlr_data,
+ void *signal_data)
+{
+ if (subsys == SS_GLOBAL && signal == S_NEW_SYSINFO) {
+ struct gsm_bts *bts = signal_data;
+ struct gsm_bts_role_bts *btsb = bts->role;
+ struct paging_state *ps = btsb->paging_state;
+ struct gsm48_system_information_type_3 *si3 = (void *) bts->si_buf[SYSINFO_TYPE_3];
+
+ paging_si_update(ps, &si3->control_channel_desc);
+ }
+ return 0;
+}
+
+static int initialized = 0;
+
+struct paging_state *paging_init(void *ctx, unsigned int num_paging_max,
+ unsigned int paging_lifetime)
+{
+ struct paging_state *ps;
+ unsigned int i;
+
+ ps = talloc_zero(ctx, struct paging_state);
+ if (!ps)
+ return NULL;
+
+ ps->paging_lifetime = paging_lifetime;
+ ps->num_paging_max = num_paging_max;
+
+ for (i = 0; i < ARRAY_SIZE(ps->paging_queue); i++)
+ INIT_LLIST_HEAD(&ps->paging_queue[i]);
+
+ if (!initialized) {
+ osmo_signal_register_handler(SS_GLOBAL, paging_signal_cbfn, NULL);
+ initialized = 1;
+ }
+ return ps;
+}
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 2f6fbfdb..650db245 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -1,11 +1,13 @@
-/*
- * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+/* GSM TS 08.58 RSL, BTS Side */
+
+/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+ * (C) 2011 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -13,105 +15,120 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
-/*
- * Radio Link Layer Messages
- */
-
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
-#include <osmocore/msgb.h>
-#include <osmocore/rsl.h>
-#include <osmocore/protocol/gsm_12_21.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/rsl.h>
+#include <osmocom/gsm/lapdm.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+
#include <osmo-bts/logging.h>
-//#include <osmocom/bb/common/osmocom_data.h>
+#include <osmo-bts/gsm_data.h>
#include <osmo-bts/abis.h>
#include <osmo-bts/rtp.h>
#include <osmo-bts/bts.h>
#include <osmo-bts/rsl.h>
#include <osmo-bts/oml.h>
-#include <osmo-bts/support.h>
+#include <osmo-bts/signal.h>
+#include <osmo-bts/bts_model.h>
+
+static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause);
+
+/* list of RSL SI types that can occur on the SACCH */
+static const unsigned int rsl_sacch_sitypes[] = {
+ RSL_SYSTEM_INFO_5,
+ RSL_SYSTEM_INFO_6,
+ RSL_SYSTEM_INFO_5bis,
+ RSL_SYSTEM_INFO_5ter,
+ RSL_EXT_MEAS_ORDER,
+ RSL_MEAS_INFO,
+};
+
+/* FIXME: move this to libosmocore */
+int osmo_in_array(unsigned int search, const unsigned int *arr, unsigned int size)
+{
+ unsigned int i;
+ for (i = 0; i < size; i++) {
+ if (arr[i] == search)
+ return 1;
+ }
+ return 0;
+}
+#define OSMO_IN_ARRAY(search, arr) osmo_in_array(search, arr, ARRAY_SIZE(arr))
+
+/* FIXME: move this to libosmocore */
+void gsm48_gen_starting_time(uint8_t *out, struct gsm_time *gtime)
+{
+ uint8_t t1p = gtime->t1 % 32;
+ out[0] = (t1p << 3) | (gtime->t3 >> 3);
+ out[1] = (gtime->t3 << 5) | gtime->t2;
+}
+
-static int rsl_tx_error_report(struct osmobts_trx *trx, uint8_t cause);
/*
* support
*/
-static uint8_t bts_si_list[BTS_SI_NUM] = BTS_SI_LIST;
-struct osmobts_lchan *rsl_get_chan(struct osmobts_trx *trx, uint8_t chan_nr)
+#warning merge lchan_lookup with OpenBSC
+/* determine logical channel based on TRX and channel number IE */
+struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr)
{
+ struct gsm_lchan *lchan;
uint8_t ts_nr = chan_nr & 0x07;
uint8_t cbits = chan_nr >> 3;
- struct bts_support *sup = &bts_support;
- struct osmobts_slot *slot = &trx->slot[ts_nr];
- struct osmobts_lchan *lchan = NULL;
-
- if (!slot->tx_ms) {
- LOGP(DRSL, LOGL_NOTICE, "Given slot not available: %d\n", ts_nr);
- return NULL;
- }
+ uint8_t lch_idx;
+ struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
if (cbits == 0x01) {
- /* TCH/F */
- if (!sup->chan_comb[NM_CHANC_TCHFull]) {
- LOGP(DRSL, LOGL_NOTICE, "TCH/F not not supported on slot: %d\n", ts_nr);
- return NULL;
- }
- if (slot->chan_comb != NM_CHANC_TCHFull) {
- LOGP(DRSL, LOGL_NOTICE, "Given channel type not TCH/F: %d\n", ts_nr);
- return NULL;
- }
- lchan = slot->lchan[0];
+ lch_idx = 0; /* TCH/F */
+ if (ts->pchan != GSM_PCHAN_TCH_F &&
+ ts->pchan != GSM_PCHAN_PDCH &&
+ ts->pchan != GSM_PCHAN_TCH_F_PDCH)
+ LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
+ chan_nr, ts->pchan);
} else if ((cbits & 0x1e) == 0x02) {
- /* TCH/H */
- if (!sup->chan_comb[NM_CHANC_TCHHalf]) {
- LOGP(DRSL, LOGL_NOTICE, "TCH/H not not supported on slot: %d\n", ts_nr);
- return NULL;
- }
- if (slot->chan_comb != NM_CHANC_TCHHalf) {
- LOGP(DRSL, LOGL_NOTICE, "Given channel type not TCH/H: %d\n", ts_nr);
- return NULL;
- }
- lchan = slot->lchan[cbits & 0x01];;
+ lch_idx = cbits & 0x1; /* TCH/H */
+ if (ts->pchan != GSM_PCHAN_TCH_H)
+ LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
+ chan_nr, ts->pchan);
} else if ((cbits & 0x1c) == 0x04) {
- /* BCCH+SDCCH4 */
- if (!sup->chan_comb[NM_CHANC_BCCHComb]) {
- LOGP(DRSL, LOGL_NOTICE, "Combined BCCH+SDCCH/4 not not supported on slot: %d\n", ts_nr);
- return NULL;
- }
- if (slot->chan_comb != NM_CHANC_BCCHComb) {
- LOGP(DRSL, LOGL_NOTICE, "Given channel type not Combined BCCH+SDCCH/4: %d\n", ts_nr);
- return NULL;
- }
- lchan = slot->lchan[cbits & 0x03];;
+ lch_idx = cbits & 0x3; /* SDCCH/4 */
+ if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
+ LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
+ chan_nr, ts->pchan);
} else if ((cbits & 0x18) == 0x08) {
- /* SDCCH8 */
- if (!sup->chan_comb[NM_CHANC_SDCCH]) {
- LOGP(DRSL, LOGL_NOTICE, "SDCCH/8 not not supported on slot: %d\n", ts_nr);
- return NULL;
- }
- if (slot->chan_comb != NM_CHANC_SDCCH) {
- LOGP(DRSL, LOGL_NOTICE, "Given channel type not SDCCH/8: %d\n", ts_nr);
- return NULL;
- }
- lchan = slot->lchan[cbits & 0x07];
+ lch_idx = cbits & 0x7; /* SDCCH/8 */
+ if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C)
+ LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
+ chan_nr, ts->pchan);
+ } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
+ lch_idx = 0;
+ if (ts->pchan != GSM_PCHAN_CCCH &&
+ ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
+ LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
+ chan_nr, ts->pchan);
+ /* FIXME: we should not return first sdcch4 !!! */
} else {
- LOGP(DRSL, LOGL_NOTICE, "Given chan_nr unknown: %d\n", chan_nr);
+ LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr);
return NULL;
}
- if (!lchan)
- LOGP(DRSL, LOGL_ERROR, "Lchan not created.\n");
+ lchan = &ts->lchan[lch_idx];
+#if 0
+ log_set_context(BSC_CTX_LCHAN, lchan);
+ if (lchan->conn)
+ log_set_context(BSC_CTX_SUBSCR, lchan->conn->subscr);
+#endif
return lchan;
}
@@ -153,6 +170,7 @@ static void rsl_dch_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr
dch = (struct abis_rsl_dchan_hdr *) msgb_push(msg, sizeof(*dch));
dch->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
dch->c.msg_type = msg_type;
+ dch->ie_chan = RSL_IE_CHAN_NR;
dch->chan_nr = chan_nr;
}
@@ -162,41 +180,37 @@ static void rsl_dch_push_hdr(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr
*/
/* 8.6.4 sending ERROR REPORT */
-static int rsl_tx_error_report(struct osmobts_trx *trx, uint8_t cause)
+static int rsl_tx_error_report(struct gsm_bts_trx *trx, uint8_t cause)
{
struct msgb *nmsg;
- uint8_t *ie;
- LOGP(DRSL, LOGL_NOTICE, "Sending Error Report: cause = 0x%02x\n", cause);
+ LOGP(DRSL, LOGL_NOTICE, "Tx RSL Error Report: cause = 0x%02x\n", cause);
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
- ie = msgb_put(nmsg, 3);
- ie[0] = RSL_IE_CAUSE;
- ie[1] = 1;
- ie[2] = cause;
+ msgb_tlv_put(nmsg, RSL_IE_CAUSE, 1, &cause);
rsl_trx_push_hdr(nmsg, RSL_MT_ERROR_REPORT);
- abis_push_ipa(nmsg, IPA_PROTO_RSL);
+ nmsg->trx = trx;
- return abis_tx(&trx->link, nmsg);
+ return abis_rsl_sendmsg(nmsg);
}
/* 8.6.1 sending RF RESOURCE INDICATION */
-int rsl_tx_rf_res(struct osmobts_trx *trx)
+int rsl_tx_rf_res(struct gsm_bts_trx *trx)
{
struct msgb *nmsg;
- LOGP(DRSL, LOGL_INFO, "Sending RF RESource INDication\n");
+ LOGP(DRSL, LOGL_INFO, "Tx RSL RF RESource INDication\n");
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
// FIXME: add interference levels of TRX
rsl_trx_push_hdr(nmsg, RSL_MT_RF_RES_IND);
- abis_push_ipa(nmsg, IPA_PROTO_RSL);
+ nmsg->trx = trx;
- return abis_tx(&trx->link, nmsg);
+ return abis_rsl_sendmsg(nmsg);
}
/*
@@ -204,87 +218,191 @@ int rsl_tx_rf_res(struct osmobts_trx *trx)
*/
/* 8.5.1 BCCH INFOrmation is received */
-static int rsl_rx_bcch_info(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_bcch_info(struct gsm_bts_trx *trx, struct msgb *msg)
{
+ struct gsm_bts *bts = trx->bts;
struct tlv_parsed tp;
- uint8_t si;
- int i;
-
- LOGP(DRSL, LOGL_INFO, "RSL BCCH Information:\n");
+ uint8_t rsl_si;
+ enum osmo_sysinfo_type osmo_si;
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.30 System Info Type */
- if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE)) {
+ if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE))
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
- }
- si = *TLVP_VAL(&tp, RSL_IE_SYSINFO_TYPE);
- i = 0;
- while(i < BTS_SI_NUM) {
- if (bts_si_list[i] == si)
- break;
- i++;
- }
- if (i == BTS_SI_NUM) {
- LOGP(DRSL, LOGL_NOTICE, " SI 0x%02x not supported.\n", si);
+
+ rsl_si = *TLVP_VAL(&tp, RSL_IE_SYSINFO_TYPE);
+ if (OSMO_IN_ARRAY(rsl_si, rsl_sacch_sitypes))
+ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT);
+
+ osmo_si = osmo_rsl2sitype(rsl_si);
+ if (osmo_si == SYSINFO_TYPE_NONE) {
+ LOGP(DRSL, LOGL_NOTICE, " Rx RSL SI 0x%02x not supported.\n", rsl_si);
return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT);
}
/* 9.3.39 Full BCCH Information */
if (TLVP_PRESENT(&tp, RSL_IE_FULL_BCCH_INFO)) {
- trx->si.flags[i] |= BTS_SI_USE;
- memcpy(trx->si.si[i], TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), 23);
- LOGP(DRSL, LOGL_INFO, " Got new SYSTEM INFORMATION 0x%02x.\n",si);
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_FULL_BCCH_INFO);
+ if (len > sizeof(sysinfo_buf_t))
+ len = sizeof(sysinfo_buf_t);
+ bts->si_valid |= (1 << osmo_si);
+ memcpy(bts->si_buf[osmo_si],
+ TLVP_VAL(&tp, RSL_IE_FULL_BCCH_INFO), len);
+ LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s)\n",
+ get_value_string(osmo_sitype_strs, osmo_si));
} else if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
- trx->si.flags[i] |= BTS_SI_USE;
- memcpy(trx->si.si[i], TLVP_VAL(&tp, RSL_IE_L3_INFO), 23);
- LOGP(DRSL, LOGL_INFO, " Got new SYSTEM INFORMATION 0x%02x.\n",si);
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_L3_INFO);
+ if (len > sizeof(sysinfo_buf_t))
+ len = sizeof(sysinfo_buf_t);
+ bts->si_valid |= (1 << osmo_si);
+ memcpy(bts->si_buf[osmo_si],
+ TLVP_VAL(&tp, RSL_IE_L3_INFO), len);
+ LOGP(DRSL, LOGL_INFO, " Rx RSL BCCH INFO (SI%s)\n",
+ get_value_string(osmo_sitype_strs, osmo_si));
} else {
- trx->si.flags[i] &= ~BTS_SI_USE;
- LOGP(DRSL, LOGL_INFO, " Removing SYSTEM INFORMATION 0x%02x.\n",si);
+ bts->si_valid &= (1 << osmo_si);
+ LOGP(DRSL, LOGL_INFO, " RX RSL Disabling BCCH INFO (SI%s)\n",
+ get_value_string(osmo_sitype_strs, osmo_si));
}
- trx->si.flags[i] |= BTS_SI_NEW;
- bts_new_si(trx);
+ osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts);
return 0;
}
-/* 8.5.6 IMMEDIATE ASSIGN COMMAND is received */
-static int rsl_rx_imm_ass(struct osmobts_trx *trx, struct msgb *msg)
+/* 8.5.2 CCCH Load Indication (PCH) */
+int rsl_tx_ccch_load_ind_pch(struct gsm_bts *bts, uint16_t paging_avail)
+{
+ struct msgb *msg;
+
+ msg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
+ if (!msg)
+ return -ENOMEM;
+ rsl_trx_push_hdr(msg, RSL_MT_CCCH_LOAD_IND);
+ msgb_tv16_put(msg, RSL_IE_PAGING_LOAD, paging_avail);
+ msg->trx = bts->c0;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* 8.5.5 PAGING COMMAND */
+static int rsl_rx_paging_cmd(struct gsm_bts_trx *trx, struct msgb *msg)
{
+ struct gsm_bts_role_bts *btsb = trx->bts->role;
struct tlv_parsed tp;
- uint8_t *data;
+ uint8_t chan_needed = 0, paging_group;
+ const uint8_t *identity_lv;
+ int rc;
- LOGP(DRSL, LOGL_INFO, "Immidiate Assignment Command:\n");
+ rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
+
+ if (!TLVP_PRESENT(&tp, RSL_IE_PAGING_GROUP) ||
+ !TLVP_PRESENT(&tp, RSL_IE_MS_IDENTITY))
+ return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
+
+ paging_group = *TLVP_VAL(&tp, RSL_IE_PAGING_GROUP);
+ identity_lv = TLVP_VAL(&tp, RSL_IE_MS_IDENTITY)-1;
+
+ if (TLVP_PRESENT(&tp, RSL_IE_CHAN_NEEDED))
+ chan_needed = *TLVP_VAL(&tp, RSL_IE_CHAN_NEEDED);
+
+ rc = paging_add_identity(btsb->paging_state, paging_group,
+ identity_lv, chan_needed);
+ if (rc < 0) {
+ /* FIXME: notfiy the BSC somehow ?*/
+ }
+
+ return 0;
+}
+
+int rsl_tx_ccch_load_ind_rach(struct gsm_bts *bts, uint16_t rach_slots,
+ uint16_t rach_busy, uint16_t rach_access)
+{
+ struct msgb *msg;
+ uint16_t payload[3];
+
+ payload[0] = htons(rach_slots);
+ payload[1] = htons(rach_busy);
+ payload[2] = htons(rach_access);
+
+ msg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
+ if (!msg)
+ return -ENOMEM;
+
+ msgb_tlv_put(msg, RSL_IE_RACH_LOAD, 6, (uint8_t *)payload);
+ rsl_trx_push_hdr(msg, RSL_MT_CCCH_LOAD_IND);
+ msg->trx = bts->c0;
+
+ return abis_rsl_sendmsg(msg);
+}
+
+/* 8.6.2 SACCH FILLING */
+static int rsl_rx_sacch_fill(struct gsm_bts_trx *trx, struct msgb *msg)
+{
+ struct gsm_bts *bts = trx->bts;
+ struct tlv_parsed tp;
+ uint8_t rsl_si;
+ enum osmo_sysinfo_type osmo_si;
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
/* 9.3.30 System Info Type */
- if (!TLVP_PRESENT(&tp, RSL_IE_FULL_IMM_ASS_INFO)) {
+ if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE))
return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
+
+ rsl_si = *TLVP_VAL(&tp, RSL_IE_SYSINFO_TYPE);
+ if (!OSMO_IN_ARRAY(rsl_si, rsl_sacch_sitypes))
+ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT);
+
+ osmo_si = osmo_rsl2sitype(rsl_si);
+ if (osmo_si == SYSINFO_TYPE_NONE) {
+ LOGP(DRSL, LOGL_NOTICE, " Rx SACCH SI 0x%02x not supported.\n", rsl_si);
+ return rsl_tx_error_report(trx, RSL_ERR_IE_CONTENT);
+ }
+ if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_L3_INFO);
+ /* We have to pre-fix with the two-byte LAPDM UI header */
+ if (len > sizeof(sysinfo_buf_t)-2)
+ len = sizeof(sysinfo_buf_t)-2;
+ bts->si_valid |= (1 << osmo_si);
+ bts->si_buf[osmo_si][0] = 0x00;
+ bts->si_buf[osmo_si][1] = 0x03;
+ memcpy(bts->si_buf[osmo_si]+2,
+ TLVP_VAL(&tp, RSL_IE_L3_INFO), len);
+ LOGP(DRSL, LOGL_INFO, " Rx RSL SACCH FILLING (SI%s)\n",
+ get_value_string(osmo_sitype_strs, osmo_si));
+ } else {
+ bts->si_valid &= (1 << osmo_si);
+ LOGP(DRSL, LOGL_INFO, " Rx RSL Disabling SACCH FILLING (SI%s)\n",
+ get_value_string(osmo_sitype_strs, osmo_si));
}
- data = (uint8_t *) TLVP_VAL(&tp, RSL_IE_FULL_IMM_ASS_INFO);
- LOGP(DRSL, LOGL_INFO, " length = %d\n", data[-1]);
+ osmo_signal_dispatch(SS_GLOBAL, S_NEW_SYSINFO, bts);
+
+ return 0;
+
+}
-#warning HACK
- {
- struct msgb *nmsg = rsl_msgb_alloc(64);
- struct l1ctl_info_dl *dl;
- uint8_t lupd[23] = {0x01,0x03f,0x3d,
- 0x05,0x08,0x12,0x62,0xf2,0x10,0x31,0x04,0x33,0x05,0xf4,0x87,0x16,0xb3,0xf0,
- 0x2b, 0x2b, 0x2b, 0x2b, 0x2b};
+/* 8.5.6 IMMEDIATE ASSIGN COMMAND is received */
+static int rsl_rx_imm_ass(struct gsm_bts_trx *trx, struct msgb *msg)
+{
+ struct tlv_parsed tp;
+
+ rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
- memcpy(msgb_put(nmsg, sizeof(lupd)), lupd, sizeof(lupd));
+ if (!TLVP_PRESENT(&tp, RSL_IE_FULL_IMM_ASS_INFO))
+ return rsl_tx_error_report(trx, RSL_ERR_MAND_IE_ERROR);
+
+ /* cut down msg to the 04.08 RR part */
+ msg->data = (uint8_t *) TLVP_VAL(&tp, RSL_IE_FULL_IMM_ASS_INFO);
+ msg->len = TLVP_LEN(&tp, RSL_IE_FULL_IMM_ASS_INFO);
- nmsg->l3h = nmsg->data;
- dl = (struct l1ctl_info_dl *)(nmsg->l1h = msgb_push(nmsg, sizeof(*dl)));
- dl->chan_nr = trx->slot[2].lchan[0]->chan_nr;
- dl->link_id = 0x00;
- msgb_push(nmsg, sizeof(struct l1ctl_hdr));
- printf("%p '%s'\n", trx->slot[2].tx_ms, trx->slot[2].tx_ms->ms.name);
- rx_ph_data_ind(&trx->slot[2].tx_ms->ms, nmsg);
+ /* put into the AGCH queue of the BTS */
+ if (bts_agch_enqueue(trx->bts, msg) < 0) {
+ /* if there is no space in the queue: send DELETE IND */
+ msgb_free(msg);
}
- return 0;
+ /* return 1 means: don't msgb_free() the msg */
+ return 1;
}
/*
@@ -292,49 +410,40 @@ static int rsl_rx_imm_ass(struct osmobts_trx *trx, struct msgb *msg)
*/
/* 8.4.19 sebdubg RF CHANnel RELease ACKnowledge */
-static int rsl_tx_rf_rel_ack(struct osmobts_trx *trx, struct msgb *msg, uint8_t t1, uint8_t t2, uint8_t t3)
+int rsl_tx_rf_rel_ack(struct gsm_lchan *lchan)
{
- struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
- uint8_t chan_nr = dch->chan_nr;
-
- LOGP(DRSL, LOGL_NOTICE, "Sending Channel Release ACK\n");
+ struct msgb *msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
+ uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
- msg->len = 0;
- msg->data = msg->tail = msg->l3h;
+ LOGP(DRSL, LOGL_NOTICE, "%s Tx RF CHAN REL ACK\n", gsm_lchan_name(lchan));
rsl_dch_push_hdr(msg, RSL_MT_RF_CHAN_REL_ACK, chan_nr);
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = lchan->ts->trx;
- return abis_tx(&trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
/* 8.4.2 sending CHANnel ACTIVation ACKnowledge */
-static int rsl_tx_chan_ack(struct osmobts_trx *trx, struct msgb *msg, uint8_t t1, uint8_t t2, uint8_t t3)
+int rsl_tx_chan_act_ack(struct gsm_lchan *lchan, struct gsm_time *gtime)
{
- struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
- uint8_t *ie;
- uint8_t chan_nr = dch->chan_nr;
+ struct msgb *msg = rsl_msgb_alloc(sizeof(struct abis_rsl_dchan_hdr));
+ uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
+ uint8_t ie[2];
- LOGP(DRSL, LOGL_NOTICE, "Sending Channel Activated ACK\n");
+ LOGP(DRSL, LOGL_NOTICE, "(%s) Tx CHAN ACT ACK\n", gsm_lchan_name(lchan));
- msg->len = 0;
- msg->data = msg->tail = msg->l3h;
-
- ie = msgb_put(msg, 3);
- ie[0] = RSL_IE_FRAME_NUMBER;
- ie[1] = (t1 << 3) | (t3 >> 3);
- ie[2] = (t3 & 0x07) | (t2 & 0x1f);
+ gsm48_gen_starting_time(ie, gtime);
+ msgb_tv_fixed_put(msg, RSL_IE_FRAME_NUMBER, 2, ie);
rsl_dch_push_hdr(msg, RSL_MT_CHAN_ACTIV_ACK, chan_nr);
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = lchan->ts->trx;
- return abis_tx(&trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
/* 8.4.3 sending CHANnel ACTIVation Negative ACK */
-static int rsl_tx_chan_nack(struct osmobts_trx *trx, struct msgb *msg, uint8_t cause)
+static int rsl_tx_chan_nack(struct gsm_bts_trx *trx, struct msgb *msg, uint8_t cause)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
- uint8_t *ie;
uint8_t chan_nr = dch->chan_nr;
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Activated NACK: cause = 0x%02x\n", cause);
@@ -342,57 +451,71 @@ static int rsl_tx_chan_nack(struct osmobts_trx *trx, struct msgb *msg, uint8_t c
msg->len = 0;
msg->data = msg->tail = msg->l3h;
- ie = msgb_put(msg, 3);
/* 9.3.26 Cause */
- ie[0] = RSL_IE_CAUSE;
- ie[1] = 1;
- ie[2] = cause;
+ msgb_tlv_put(msg, RSL_IE_CAUSE, 1, &cause);
rsl_dch_push_hdr(msg, RSL_MT_CHAN_ACTIV_NACK, chan_nr);
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = trx;
- return abis_tx(&trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
/* 8.5.3 sending CHANnel ReQuireD */
-int rsl_tx_chan_rqd(struct osmobts_trx *trx)
+int rsl_tx_chan_rqd(struct gsm_bts_trx *trx, struct gsm_time *gtime,
+ uint8_t ra, uint8_t acc_delay)
{
struct msgb *nmsg;
- uint8_t *ie;
+ uint8_t payload[3];
LOGP(DRSL, LOGL_NOTICE, "Sending Channel Required\n");
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_cchan_hdr));
if (!nmsg)
return -ENOMEM;
- ie = msgb_put(nmsg, 4);
+
/* 9.3.19 Request Reference */
- ie[0] = RSL_IE_REQ_REFERENCE;
- ie[1] = 0xe0; // FIXME
- ie[2] = 0x00;
- ie[3] = 0x00;
+ payload[0] = ra;
+ gsm48_gen_starting_time(payload+1, gtime);
+ msgb_tv_fixed_put(nmsg, RSL_IE_REQ_REFERENCE, 3, payload);
+
/* 9.3.17 Access Delay */
- ie = msgb_put(nmsg, 2);
- ie[0] = RSL_IE_ACCESS_DELAY;
- ie[1] = 0x00; // FIXME
+ msgb_tv_put(nmsg, RSL_IE_ACCESS_DELAY, acc_delay);
+
rsl_cch_push_hdr(nmsg, RSL_MT_CHAN_RQD, 0x88); // FIXME
- abis_push_ipa(nmsg, IPA_PROTO_RSL);
+ nmsg->trx = trx;
+
+ return abis_rsl_sendmsg(nmsg);
+}
- return abis_tx(&trx->link, nmsg);
+/* copy the SACCH related sysinfo from BTS global buffer to lchan specific buffer */
+static void copy_sacch_si_to_lchan(struct gsm_lchan *lchan)
+{
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rsl_sacch_sitypes); i++) {
+ uint8_t rsl_si = rsl_sacch_sitypes[i];
+ uint8_t osmo_si = osmo_rsl2sitype(rsl_si);
+ uint8_t osmo_si_shifted = (1 << osmo_si);
+ if (osmo_si == SYSINFO_TYPE_NONE)
+ continue;
+ if (!(bts->si_valid & osmo_si_shifted)) {
+ lchan->si.valid &= ~osmo_si_shifted;
+ continue;
+ }
+ lchan->si.valid |= osmo_si_shifted;
+ memcpy(lchan->si.buf[osmo_si], bts->si_buf[osmo_si],
+ sizeof(sysinfo_buf_t));
+ }
}
+
/* 8.4.1 CHANnel ACTIVation is received */
-static int rsl_rx_chan_activ(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_chan_activ(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
+ struct gsm_lchan *lchan = msg->lchan;
struct tlv_parsed tp;
uint8_t type, mode;
- struct osmobts_lchan *lchan;
-
- LOGP(DRSL, LOGL_INFO, "Channel Activation:\n");
-
- lchan = rsl_get_chan(trx, dch->chan_nr);
- if (!lchan)
- return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
@@ -400,48 +523,157 @@ static int rsl_rx_chan_activ(struct osmobts_trx *trx, struct msgb *msg)
if (!TLVP_PRESENT(&tp, RSL_IE_ACT_TYPE)) {
LOGP(DRSL, LOGL_NOTICE, "missing Activation Type\n");
msgb_free(msg);
- return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
+ return rsl_tx_chan_nack(msg->trx, msg, RSL_ERR_MAND_IE_ERROR);
}
type = *TLVP_VAL(&tp, RSL_IE_ACT_TYPE);
+
/* 9.3.6 Channel Mode */
if (!TLVP_PRESENT(&tp, RSL_IE_CHAN_MODE)) {
LOGP(DRSL, LOGL_NOTICE, "missing Channel Mode\n");
msgb_free(msg);
- return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
+ return rsl_tx_chan_nack(msg->trx, msg, RSL_ERR_MAND_IE_ERROR);
}
mode = *TLVP_VAL(&tp, RSL_IE_CHAN_MODE);
+ /* 9.3.7 Encryption Information */
+ if (TLVP_PRESENT(&tp, RSL_IE_ENCR_INFO)) {
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_ENCR_INFO);
+ const uint8_t *val = TLVP_VAL(&tp, RSL_IE_ENCR_INFO);
+ lchan->encr.alg_id = *val++;
+ lchan->encr.key_len = len -1;
+ if (lchan->encr.key_len > sizeof(lchan->encr.key))
+ lchan->encr.key_len = sizeof(lchan->encr.key);
+ memcpy(lchan->encr.key, val, lchan->encr.key_len);
+ }
+
+ /* 9.3.9 Handover Reference */
+
+ /* 9.3.4 BS Power */
+ if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER))
+ lchan->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER);
+ /* 9.3.13 MS Power */
+ if (TLVP_PRESENT(&tp, RSL_IE_MS_POWER))
+ lchan->bs_power = *TLVP_VAL(&tp, RSL_IE_MS_POWER);
+ /* 9.3.24 Timing Advance */
+ if (TLVP_PRESENT(&tp, RSL_IE_TIMING_ADVANCE))
+ lchan->rqd_ta = *TLVP_VAL(&tp, RSL_IE_TIMING_ADVANCE);
+
+ /* 9.3.32 BS Power Parameters */
+ /* 9.3.31 MS Power Parameters */
+ /* 9.3.16 Physical Context */
+
+ /* 9.3.29 SACCH Information */
+ if (TLVP_PRESENT(&tp, RSL_IE_SACCH_INFO)) {
+ uint8_t tot_len = TLVP_LEN(&tp, RSL_IE_SACCH_INFO);
+ const uint8_t *val = TLVP_VAL(&tp, RSL_IE_SACCH_INFO);
+ uint8_t num_msgs = *val++;
+ unsigned int i;
+ for (i = 0; i < num_msgs; i++) {
+ uint8_t rsl_si = *val++;
+ uint8_t si_len = *val++;
+ uint8_t osmo_si;
+ uint8_t copy_len;
+
+ if (!OSMO_IN_ARRAY(rsl_si, rsl_sacch_sitypes))
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+
+ osmo_si = osmo_rsl2sitype(rsl_si);
+ if (osmo_si == SYSINFO_TYPE_NONE) {
+ LOGP(DRSL, LOGL_NOTICE, " Rx SACCH SI 0x%02x not supported.\n", rsl_si);
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+ }
+
+ copy_len = si_len;
+ /* We have to pre-fix with the two-byte LAPDM UI header */
+ if (copy_len > sizeof(sysinfo_buf_t)-2)
+ copy_len = sizeof(sysinfo_buf_t)-2;
+ lchan->si.valid |= (1 << osmo_si);
+ lchan->si.buf[osmo_si][0] = 0x00;
+ lchan->si.buf[osmo_si][1] = 0x03;
+ memcpy(lchan->si.buf[osmo_si]+2, val, copy_len);
+
+ val += si_len;
+ }
+ } else {
+ /* use standard SACCH filling of the BTS */
+ copy_sacch_si_to_lchan(lchan);
+ }
+ /* 9.3.52 MultiRate Configuration */
+ /* 9.3.53 MultiRate Control */
+ /* 9.3.54 Supported Codec Types */
+
LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x type=0x%02x mode=0x%02x\n", dch->chan_nr, type, mode);
- return rsl_tx_chan_ack(trx, msg, 0, 0, 0);
+ /* actually activate the channel in the BTS */
+ return bts_model_rsl_chan_act(msg->lchan, &tp);
}
/* 8.4.14 RF CHANnel RELease is received */
-static int rsl_rx_rf_chan_rel(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_rf_chan_rel(struct msgb *msg)
{
- struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
- struct osmobts_lchan *lchan;
- int rc;
+#if 0
+ lapdm_reset(&lchan->l2_entity.lapdm_dcch);
+ lapdm_reset(&lchan->l2_entity.lapdm_acch);
- LOGP(DRSL, LOGL_INFO, "Channel Release:\n");
+ if (lchan->rtp.socket_created)
+ rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
+#endif
- lchan = rsl_get_chan(trx, dch->chan_nr);
- if (!lchan)
- return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
+ return bts_model_rsl_chan_rel(msg->lchan);
+}
- LOGP(DRSL, LOGL_INFO, " chan_nr=0x%02x\n", dch->chan_nr);
+/* 8.4.20 SACCH INFO MODify */
+static int rsl_rx_sacch_inf_mod(struct msgb *msg)
+{
+ struct gsm_lchan *lchan = msg->lchan;
+ struct tlv_parsed tp;
+ uint8_t rsl_si, osmo_si;
- lapdm_reset(&lchan->l2_entity.lapdm_dcch);
- lapdm_reset(&lchan->l2_entity.lapdm_acch);
+ rsl_tlv_parse(&tp, msgb_l3(msg), msgb_l3len(msg));
- rc = rsl_tx_rf_rel_ack(trx, msg, 0, 0, 0);
+ if (TLVP_PRESENT(&tp, RSL_IE_STARTNG_TIME)) {
+ LOGP(DRSL, LOGL_NOTICE, "Starting time not supported\n");
+ return rsl_tx_error_report(msg->trx, RSL_ERR_SERV_OPT_UNIMPL);
+ }
- if (lchan->rtp.socket_created)
- rsl_tx_ipac_dlcx_ind(lchan, RSL_ERR_NORMAL_UNSPEC);
+ /* 9.3.30 System Info Type */
+ if (!TLVP_PRESENT(&tp, RSL_IE_SYSINFO_TYPE))
+ return rsl_tx_error_report(msg->trx, RSL_ERR_MAND_IE_ERROR);
+
+ rsl_si = *TLVP_VAL(&tp, RSL_IE_SYSINFO_TYPE);
+ if (!OSMO_IN_ARRAY(rsl_si, rsl_sacch_sitypes))
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+
+ osmo_si = osmo_rsl2sitype(rsl_si);
+ if (osmo_si == SYSINFO_TYPE_NONE) {
+ LOGP(DRSL, LOGL_NOTICE, "%s Rx SACCH SI 0x%02x not supported.\n",
+ gsm_lchan_name(lchan), rsl_si);
+ return rsl_tx_error_report(msg->trx, RSL_ERR_IE_CONTENT);
+ }
+ if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
+ uint8_t len = TLVP_LEN(&tp, RSL_IE_L3_INFO);
+ /* We have to pre-fix with the two-byte LAPDM UI header */
+ if (len > sizeof(sysinfo_buf_t)-2)
+ len = sizeof(sysinfo_buf_t)-2;
+ lchan->si.valid |= (1 << osmo_si);
+ lchan->si.buf[osmo_si][0] = 0x00;
+ lchan->si.buf[osmo_si][1] = 0x03;
+ memcpy(lchan->si.buf[osmo_si]+2,
+ TLVP_VAL(&tp, RSL_IE_L3_INFO), len);
+ LOGP(DRSL, LOGL_INFO, "%s Rx RSL SACCH FILLING (SI%s)\n",
+ gsm_lchan_name(lchan),
+ get_value_string(osmo_sitype_strs, osmo_si));
+ } else {
+ lchan->si.valid &= (1 << osmo_si);
+ LOGP(DRSL, LOGL_INFO, "%s Rx RSL Disabling SACCH FILLING (SI%s)\n",
+ gsm_lchan_name(lchan),
+ get_value_string(osmo_sitype_strs, osmo_si));
+ }
- return rc;
+ return 0;
}
+#if 0
/*
* ip.access related messages
*/
@@ -449,25 +681,21 @@ static int rsl_rx_rf_chan_rel(struct osmobts_trx *trx, struct msgb *msg)
int rsl_tx_ipac_dlcx_ind(struct osmobts_lchan *lchan, uint8_t cause)
{
struct msgb *nmsg;
- struct osmobts_trx *trx = lchan->slot->trx;
- uint8_t *ie;
+ struct gsm_bts_trx *trx = lchan->slot->trx;
LOGP(DRSL, LOGL_NOTICE, "Sending RTP delete indication: cause=%d\n", cause);
nmsg = rsl_msgb_alloc(sizeof(struct abis_rsl_common_hdr));
if (!nmsg)
return -ENOMEM;
- ie = msgb_put(nmsg, 3);
- ie[0] = RSL_IE_CAUSE;
- ie[1] = 1;
- ie[2] = cause;
+ msgb_tlv_put(nmsg, RSL_IE_CAUSE, 1, &cause);
rsl_trx_push_hdr(nmsg, RSL_MT_IPAC_DLCX_IND);
- abis_push_ipa(nmsg, IPA_PROTO_RSL);
+ msg->trx = trx;
- return abis_tx(&trx->link, nmsg);
+ return abis_rsl_sendmsg(nmsg);
}
-static int rsl_tx_ipac_cx_ack(struct osmobts_trx *trx, struct msgb *msg, uint32_t ip, uint16_t port, uint16_t *conn_id)
+static int rsl_tx_ipac_cx_ack(struct gsm_bts_trx *trx, struct msgb *msg, uint32_t ip, uint16_t port, uint16_t *conn_id)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t chan_nr = dch->chan_nr;
@@ -487,35 +715,31 @@ static int rsl_tx_ipac_cx_ack(struct osmobts_trx *trx, struct msgb *msg, uint32_
msgb_tv16_put(msg, RSL_IE_IPAC_LOCAL_PORT, htons(port));
rsl_dch_push_hdr(msg, msg_type + 1, chan_nr);
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = trx;
- return abis_tx(&trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
-static int rsl_tx_ipac_cx_nack(struct osmobts_trx *trx, struct msgb *msg, uint8_t cause)
+static int rsl_tx_ipac_cx_nack(struct gsm_bts_trx *trx, struct msgb *msg, uint8_t cause)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
uint8_t chan_nr = dch->chan_nr;
uint8_t msg_type = dch->c.msg_type;
- uint8_t *ie;
LOGP(DRSL, LOGL_NOTICE, "Sending RTP connection request NACK: cause=%d\n", cause);
msg->len = 0;
msg->data = msg->tail = msg->l3h;
- ie = msgb_put(msg, 3);
/* 9.3.26 Cause */
- ie[0] = RSL_IE_CAUSE;
- ie[1] = 1;
- ie[2] = cause;
+ msgb_tlv_put(msg, RSL_IE_CAUSE, 1, &cause);
rsl_dch_push_hdr(msg, msg_type + 2, chan_nr);
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = trx;
- return abis_tx(&trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
-static int rsl_rx_ipac_crcx_mdcx(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_ipac_crcx_mdcx(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
@@ -531,7 +755,7 @@ static int rsl_rx_ipac_crcx_mdcx(struct osmobts_trx *trx, struct msgb *msg)
else
LOGP(DRSL, LOGL_INFO, "Request of modding RTP connection:\n");
- lchan = rsl_get_chan(trx, dch->chan_nr);
+ lchan = rsl_lchan_lookup(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
@@ -584,7 +808,7 @@ static int rsl_rx_ipac_crcx_mdcx(struct osmobts_trx *trx, struct msgb *msg)
return rsl_tx_ipac_cx_ack(trx, msg, ntohl(lchan->rtp.rtp_udp.sin_local.sin_addr.s_addr), ntohs(lchan->rtp.rtp_udp.sin_local.sin_port), &conn_id);
}
-static int rsl_rx_ipac_dlcx(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_ipac_dlcx(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
struct tlv_parsed tp;
@@ -592,7 +816,7 @@ static int rsl_rx_ipac_dlcx(struct osmobts_trx *trx, struct msgb *msg)
LOGP(DRSL, LOGL_INFO, "Request of deleting RTP connection:\n");
- lchan = rsl_get_chan(trx, dch->chan_nr);
+ lchan = rsl_lchan_lookup(trx, dch->chan_nr);
if (!lchan)
return rsl_tx_ipac_cx_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
@@ -602,15 +826,16 @@ static int rsl_rx_ipac_dlcx(struct osmobts_trx *trx, struct msgb *msg)
return rsl_tx_ipac_cx_ack(trx, msg, ntohl(lchan->rtp.rtp_udp.sin_local.sin_addr.s_addr), ntohs(lchan->rtp.rtp_udp.sin_local.sin_port), NULL);
}
+#endif
/*
* selecting message
*/
-static int rsl_rx_rll(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_rll(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_rll_hdr *rh = msgb_l2(msg);
- struct osmobts_lchan *lchan;
+ struct gsm_lchan *lchan;
if (msgb_l2len(msg) < sizeof(*rh)) {
LOGP(DRSL, LOGL_NOTICE, "RSL Radio Link Layer message too short\n");
@@ -619,26 +844,28 @@ static int rsl_rx_rll(struct osmobts_trx *trx, struct msgb *msg)
}
msg->l3h = (unsigned char *)rh + sizeof(*rh);
- lchan = rsl_get_chan(trx, rh->chan_nr);
+ lchan = rsl_lchan_lookup(trx, rh->chan_nr);
if (!lchan)
return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
- return rslms_recvmsg(msg, &lchan->l2_entity);
+ return lapdm_rslms_recvmsg(msg, &lchan->lapdm_ch);
}
-int rsl_tx_rll(struct msgb *msg, struct osmol2_entity *l2_entity)
+/* call-back for LAPDm code, called when it wants to send msgs UP */
+int lapdm_rll_tx_cb(struct msgb *msg, struct lapdm_entity *le, void *ctx)
{
- struct osmobts_lchan *lchan = container_of(l2_entity, struct osmobts_lchan, l2_entity);
+ struct gsm_lchan *lchan = ctx;
struct abis_rsl_common_hdr *rh = msgb_l2(msg);
- LOGP(DRSL, LOGL_INFO, "Got '%s' message from L2.\n", get_rsl_name(rh->msg_type));
+ LOGP(DRSL, LOGL_INFO, "%s Fwd RLL msg %s from LAPDm to A-bis\n",
+ gsm_lchan_name(lchan), rsl_msg_name(rh->msg_type));
- abis_push_ipa(msg, IPA_PROTO_RSL);
+ msg->trx = lchan->ts->trx;
- return abis_tx(&lchan->slot->trx->link, msg);
+ return abis_rsl_sendmsg(msg);
}
-static int rsl_rx_cchan(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_cchan(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_cchan_hdr *cch = msgb_l2(msg);
int ret = 0;
@@ -650,6 +877,16 @@ static int rsl_rx_cchan(struct osmobts_trx *trx, struct msgb *msg)
}
msg->l3h = (unsigned char *)cch + sizeof(*cch);
+ msg->lchan = rsl_lchan_lookup(trx, cch->chan_nr);
+ if (!msg->lchan) {
+ LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknow lchan\n",
+ rsl_msg_name(cch->c.msg_type));
+ //return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
+ }
+
+ LOGP(DRSL, LOGL_INFO, "%s Rx RSL %s\n", gsm_lchan_name(msg->lchan),
+ rsl_msg_name(cch->c.msg_type));
+
switch (cch->c.msg_type) {
case RSL_MT_BCCH_INFO:
ret = rsl_rx_bcch_info(trx, msg);
@@ -657,17 +894,29 @@ static int rsl_rx_cchan(struct osmobts_trx *trx, struct msgb *msg)
case RSL_MT_IMMEDIATE_ASSIGN_CMD:
ret = rsl_rx_imm_ass(trx, msg);
break;
+ case RSL_MT_PAGING_CMD:
+ ret = rsl_rx_paging_cmd(trx, msg);
+ break;
+ case RSL_MT_SMS_BC_REQ:
+ case RSL_MT_SMS_BC_CMD:
+ case RSL_MT_NOT_CMD:
+ LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL cchan msg_type %s\n",
+ rsl_msg_name(cch->c.msg_type));
+ break;
default:
- LOGP(DRSL, LOGL_NOTICE, "unsupported RSL cchan msg_type 0x%02x\n",
+ LOGP(DRSL, LOGL_NOTICE, "undefined RSL cchan msg_type 0x%02x\n",
cch->c.msg_type);
ret = -EINVAL;
+ break;
}
- msgb_free(msg);
+ if (ret != 1)
+ msgb_free(msg);
+
return ret;
}
-static int rsl_rx_dchan(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_dchan(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
int ret = 0;
@@ -679,22 +928,48 @@ static int rsl_rx_dchan(struct osmobts_trx *trx, struct msgb *msg)
}
msg->l3h = (unsigned char *)dch + sizeof(*dch);
+ msg->lchan = rsl_lchan_lookup(trx, dch->chan_nr);
+ if (!msg->lchan) {
+ LOGP(DRSL, LOGL_ERROR, "Rx RSL %s for unknow lchan\n",
+ rsl_msg_name(dch->c.msg_type));
+ //return rsl_tx_chan_nack(trx, msg, RSL_ERR_MAND_IE_ERROR);
+ }
+
+ LOGP(DRSL, LOGL_INFO, "%s Rx RSL %s\n", gsm_lchan_name(msg->lchan),
+ rsl_msg_name(dch->c.msg_type));
+
switch (dch->c.msg_type) {
case RSL_MT_CHAN_ACTIV:
- return rsl_rx_chan_activ(trx, msg);
+ return rsl_rx_chan_activ(msg);
case RSL_MT_RF_CHAN_REL:
- return rsl_rx_rf_chan_rel(trx, msg);
+ return rsl_rx_rf_chan_rel(msg);
+ case RSL_MT_SACCH_INFO_MODIFY:
+ return rsl_rx_sacch_inf_mod(msg);
+ case RSL_MT_DEACTIVATE_SACCH:
+ case RSL_MT_ENCR_CMD:
+ case RSL_MT_MODE_MODIFY_REQ:
+ case RSL_MT_PHY_CONTEXT_REQ:
+ case RSL_MT_PREPROC_CONFIG:
+ case RSL_MT_RTD_REP:
+ case RSL_MT_PRE_HANDO_NOTIF:
+ case RSL_MT_MR_CODEC_MOD_REQ:
+ case RSL_MT_TFO_MOD_REQ:
+ LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL dchan msg_type %s\n",
+ rsl_msg_name(dch->c.msg_type));
+ break;
default:
- LOGP(DRSL, LOGL_NOTICE, "unsupported RSL dchan msg_type 0x%02x\n",
+ LOGP(DRSL, LOGL_NOTICE, "undefined RSL dchan msg_type 0x%02x\n",
dch->c.msg_type);
ret = -EINVAL;
}
- msgb_free(msg);
+ if (ret != 1)
+ msgb_free(msg);
+
return ret;
}
-static int rsl_rx_trx(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_trx(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *th = msgb_l2(msg);
int ret = 0;
@@ -708,19 +983,21 @@ static int rsl_rx_trx(struct osmobts_trx *trx, struct msgb *msg)
switch (th->msg_type) {
case RSL_MT_SACCH_FILL:
- ret = rsl_rx_bcch_info(trx, msg);
+ ret = rsl_rx_sacch_fill(trx, msg);
break;
default:
- LOGP(DRSL, LOGL_NOTICE, "unsupported RSL TRX msg_type 0x%02x\n",
+ LOGP(DRSL, LOGL_NOTICE, "undefined RSL TRX msg_type 0x%02x\n",
th->msg_type);
ret = -EINVAL;
}
- msgb_free(msg);
+ if (ret != 1)
+ msgb_free(msg);
+
return ret;
}
-static int rsl_rx_ipaccess(struct osmobts_trx *trx, struct msgb *msg)
+static int rsl_rx_ipaccess(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dch = msgb_l2(msg);
int ret = 0;
@@ -733,22 +1010,25 @@ static int rsl_rx_ipaccess(struct osmobts_trx *trx, struct msgb *msg)
msg->l3h = (unsigned char *)dch + sizeof(*dch);
switch (dch->c.msg_type) {
+#if 0
case RSL_MT_IPAC_CRCX:
case RSL_MT_IPAC_MDCX:
return rsl_rx_ipac_crcx_mdcx(trx, msg);
case RSL_MT_IPAC_DLCX:
return rsl_rx_ipac_dlcx(trx, msg);
+#endif
default:
LOGP(DRSL, LOGL_NOTICE, "unsupported RSL ip.access msg_type 0x%02x\n",
dch->c.msg_type);
ret = -EINVAL;
}
- msgb_free(msg);
+ if (ret != 1)
+ msgb_free(msg);
return ret;
}
-int down_rsl(struct osmobts_trx *trx, struct msgb *msg)
+int down_rsl(struct gsm_bts_trx *trx, struct msgb *msg)
{
struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
int ret = 0;
@@ -784,5 +1064,3 @@ int down_rsl(struct osmobts_trx *trx, struct msgb *msg)
return ret;
}
-
-
diff --git a/src/common/rtp.c b/src/common/rtp.c
index e8a7e7fc..99be75b0 100644
--- a/src/common/rtp.c
+++ b/src/common/rtp.c
@@ -1,11 +1,12 @@
-/*
- * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
+/* RTP code for BTS side */
+
+/* (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -13,16 +14,11 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
-/*
- * RTP peer
- */
-
#include <errno.h>
#include <sys/types.h>
#include <arpa/inet.h>
diff --git a/src/common/support.c b/src/common/support.c
index 36fc5ca3..e271b957 100644
--- a/src/common/support.c
+++ b/src/common/support.c
@@ -3,8 +3,8 @@
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * 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,
@@ -12,9 +12,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 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/>.
*
*/
diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c
new file mode 100644
index 00000000..90141d5b
--- /dev/null
+++ b/src/common/sysinfo.c
@@ -0,0 +1,66 @@
+/* (C) 2011 by Harald Welte <laforge@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 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 <stdint.h>
+
+#include <osmocom/gsm/gsm_utils.h>
+#include <osmocom/gsm/sysinfo.h>
+
+#include <osmo-bts/gsm_data.h>
+
+uint8_t *bts_sysinfo_get(struct gsm_bts *bts, struct gsm_time *g_time)
+{
+ /* Apply the rules from 05.02 6.3.1.3 Mapping of BCCH Data */
+ switch (g_time->tc) {
+ case 0:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_1);
+ case 1:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_2);
+ case 2:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+ case 3:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_4);
+ case 4:
+ /* 2ter, 2quater, 9, 13 */
+ break;
+ case 5:
+ /* 2ter, 2quater */
+ break;
+ case 6:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_3);
+ case 7:
+ return GSM_BTS_SI(bts, SYSINFO_TYPE_4);
+ }
+
+ return NULL;
+}
+
+uint8_t *lchan_sacch_get(struct gsm_lchan *lchan, struct gsm_time *g_time)
+{
+ uint32_t tmp;
+
+ for (tmp = lchan->si.last + 1; tmp != lchan->si.last; tmp = (tmp + 1) % 32) {
+ if (lchan->si.valid & (1 << tmp)) {
+ lchan->si.last = tmp;
+ printf("returning SACCH SI type %u\n", tmp);
+ return lchan->si.buf[tmp];
+ }
+ }
+ return NULL;
+}
diff --git a/src/common/vty.c b/src/common/vty.c
new file mode 100644
index 00000000..d2cda2fb
--- /dev/null
+++ b/src/common/vty.c
@@ -0,0 +1,61 @@
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/vty/vty.h>
+
+#include <osmo-bts/vty.h>
+
+enum node_type bts_vty_go_parent(struct vty *vty)
+{
+ switch (vty->node) {
+ default:
+ vty->node = CONFIG_NODE;
+ }
+ return vty->node;
+}
+
+int bts_vty_is_config_node(struct vty *vty, int node)
+{
+ switch (node) {
+ default:
+ return 0;
+ }
+}
+
+gDEFUN(ournode_exit, ournode_exit_cmd, "exit",
+ "Exit current node, go down to provious node")
+{
+ switch (vty->node) {
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+gDEFUN(ournode_end, ournode_end_cmd, "end",
+ "End current mode and change to enable mode")
+{
+ switch (vty->node) {
+ default:
+ vty_config_unlock(vty);
+ vty->node = ENABLE_NODE;
+ vty->index = NULL;
+ vty->index_sub = NULL;
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+struct vty_app_info bts_vty_info = {
+ .name = "OsmoBTS",
+ .version = PACKAGE_VERSION,
+ .go_parent_cb = bts_vty_go_parent,
+ .is_config_node = bts_vty_is_config_node,
+};
+
+const char *osmobts_copyright =
+ "Copyright (C) 2010, 2011 by Harald Welte and Andreas Eversberg\r\n"
+ "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
+ "This is free software: you are free to change and redistribute it.\r\n"
+ "There is NO WARRANTY, to the extent permitted by law.\r\n";