aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2009-10-07 09:50:21 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2009-11-20 17:35:45 +0100
commit2281d1835f1fc95bb7a235ec04ff28d9b93781b8 (patch)
tree4f52e8713649eb26f28287e3aaf96afc695bfeab
parentfb4433a129ca7b0757baee834a1e5a6ba4c5bd85 (diff)
[bssap] Start to queue messages to the BTS and to the MSC
For the MSC we need to queue GSM04.08 messages until the SCCP connection is confirmed to be open and then can send the stored messages. The queue is limited to 10 messages at which point new ones will be dropped. Currently the only messages we get are measurement indication messages but it is better to be safe than sorry. The SCCP messages are sent as soon as the connection is considered established and then no queueing happens any more. While replacing sccp_connection_write calls various memory leaks has been fixed. For the MS we might have received a DTAP and need to do an operation that requires a roundtrip and want to send wait until this has happened. The two scenerios are sending a SMS to the phone that requires to do something special for the different SAPI. Currently it is assumed that only one SAPI=0 -> SAPI=3 change happen during the connection. For the first SAPI != 0 we will send the rll_ request and then wait for the timeout or confirmation. In case of timeout a SAPI "n" reject is sent and in case of success the queue is getting emptied.
-rw-r--r--openbsc/include/openbsc/bssap.h8
-rw-r--r--openbsc/include/openbsc/gsm_data.h7
-rw-r--r--openbsc/src/bsc_msc_ip.c21
-rw-r--r--openbsc/src/bssap.c173
4 files changed, 195 insertions, 14 deletions
diff --git a/openbsc/include/openbsc/bssap.h b/openbsc/include/openbsc/bssap.h
index 1db026525..d6553409a 100644
--- a/openbsc/include/openbsc/bssap.h
+++ b/openbsc/include/openbsc/bssap.h
@@ -278,4 +278,12 @@ struct msgb *bssmap_create_sapi_reject(u_int8_t link_id);
int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length);
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id);
+void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg);
+void bsc_free_queued(struct sccp_connection *conn);
+void bsc_send_queued(struct sccp_connection *conn);
+
+void bts_queue_send(struct msgb *msg, int link_id);
+void bts_send_queued(struct bss_sccp_connection_data*);
+void bts_free_queued(struct bss_sccp_connection_data*);
+
#endif
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 8a9446a5e..d01973e4b 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -121,6 +121,13 @@ struct bss_sccp_connection_data {
struct gsm_lchan *lchan;
struct sccp_connection *sccp;
int ciphering_handled : 1;
+
+ /* Queue SCCP and GSM0408 messages */
+ struct llist_head gsm_queue;
+ unsigned int gsm_queue_size;
+
+ struct llist_head sccp_queue;
+ unsigned int sccp_queue_size;
};
#define sccp_get_lchan(data_ctx) ((struct bss_sccp_connection_data *)data_ctx)->lchan
diff --git a/openbsc/src/bsc_msc_ip.c b/openbsc/src/bsc_msc_ip.c
index 9b726f89d..f3c85904e 100644
--- a/openbsc/src/bsc_msc_ip.c
+++ b/openbsc/src/bsc_msc_ip.c
@@ -59,13 +59,23 @@ extern int bsc_shutdown_net(struct gsm_network *net);
struct bss_sccp_connection_data *bss_sccp_create_data()
{
- return _talloc_zero(tall_bsc_ctx,
+ struct bss_sccp_connection_data *data;
+
+ data = _talloc_zero(tall_bsc_ctx,
sizeof(struct bss_sccp_connection_data),
"bsc<->msc");
+ if (!data)
+ return NULL;
+
+ INIT_LLIST_HEAD(&data->sccp_queue);
+ INIT_LLIST_HEAD(&data->gsm_queue);
+ return data;
}
void bss_sccp_free_data(struct bss_sccp_connection_data *data)
{
+ bsc_free_queued(data->sccp);
+ bts_free_queued(data);
talloc_free(data);
}
@@ -138,6 +148,8 @@ void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx);
sccp_connection_free(conn);
return;
+ } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
+ bsc_send_queued(conn);
}
}
@@ -204,7 +216,7 @@ static int send_dtap_or_open_connection(struct msgb *msg)
return -1;
}
- sccp_connection_write(lchan_get_sccp(msg->lchan), dtap);
+ bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
return 1;
} else {
return open_sccp_connection(msg);
@@ -251,8 +263,7 @@ static int handle_cipher_m_complete(struct msgb *msg)
/* handled this message */
- sccp_connection_write(lchan_get_sccp(msg->lchan), resp);
- msgb_free(resp);
+ bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp);
return 1;
}
@@ -328,7 +339,7 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
return -1;
}
- sccp_connection_write(lchan_get_sccp(msg->lchan), dtap);
+ bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
}
return rc;
diff --git a/openbsc/src/bssap.c b/openbsc/src/bssap.c
index 061d6cd50..9ecc28bfd 100644
--- a/openbsc/src/bssap.c
+++ b/openbsc/src/bssap.c
@@ -20,6 +20,7 @@
*/
#include <openbsc/bssap.h>
+#include <openbsc/bsc_rll.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
@@ -162,8 +163,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
return -1;
}
- sccp_connection_write(conn, resp);
- msgb_free(resp);
+ bsc_queue_connection_write(conn, resp);
return 0;
}
@@ -205,8 +205,7 @@ reject:
return -1;
}
- sccp_connection_write(conn, resp);
- msgb_free(resp);
+ bsc_queue_connection_write(conn, resp);
return -1;
}
@@ -260,7 +259,6 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
struct dtap_header *header;
struct msgb *gsm48;
u_int8_t *data;
- int ret = 0;
if (!lchan) {
DEBUGP(DMSC, "No lchan available\n");
@@ -294,9 +292,9 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
gsm48->l3h = gsm48->data;
data = msgb_put(gsm48, length - sizeof(*header));
memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header));
- ret = rsl_data_request(gsm48, header->link_id);
- return ret;
+ bts_queue_send(gsm48, header->link_id);
+ return 0;
}
/* Create messages */
@@ -505,12 +503,169 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
msg->l3h[5] = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE;
DEBUGP(DMSC, "Sending clear request on unexpected channel release.\n");
- sccp_connection_write(conn, msg);
- msgb_free(msg);
+ bsc_queue_connection_write(conn, msg);
return 0;
}
+/*
+ * queue handling for BSS AP
+ */
+void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg)
+{
+ struct bss_sccp_connection_data *data;
+
+ data = (struct bss_sccp_connection_data *)conn->data_ctx;
+
+ if (conn->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
+ DEBUGP(DMSC, "Connection closing, dropping packet on: %p\n", conn);
+ msgb_free(msg);
+ } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED
+ && data->sccp_queue_size == 0) {
+ sccp_connection_write(conn, msg);
+ msgb_free(msg);
+ } else if (data->sccp_queue_size > 10) {
+ DEBUGP(DMSC, "Dropping packet on %p due queue overflow\n", conn);
+ msgb_free(msg);
+ } else {
+ DEBUGP(DMSC, "Queuing packet on %p. Queue size: %d\n", conn, data->sccp_queue_size);
+ ++data->sccp_queue_size;
+ msgb_enqueue(&data->sccp_queue, msg);
+ }
+}
+
+void bsc_free_queued(struct sccp_connection *conn)
+{
+ struct bss_sccp_connection_data *data;
+ struct msgb *msg;
+
+ data = (struct bss_sccp_connection_data *)conn->data_ctx;
+ while (!llist_empty(&data->sccp_queue)) {
+ /* this is not allowed to fail */
+ msg = msgb_dequeue(&data->sccp_queue);
+ msgb_free(msg);
+ }
+
+ data->sccp_queue_size = 0;
+}
+
+void bsc_send_queued(struct sccp_connection *conn)
+{
+ struct bss_sccp_connection_data *data;
+ struct msgb *msg;
+
+ data = (struct bss_sccp_connection_data *)conn->data_ctx;
+
+ DEBUGP(DMSC, "Sending queued items\n");
+ while (!llist_empty(&data->sccp_queue)) {
+ /* this is not allowed to fail */
+ msg = msgb_dequeue(&data->sccp_queue);
+ sccp_connection_write(conn, msg);
+ msgb_free(msg);
+ --data->sccp_queue_size;
+ }
+}
+
+/* RLL callback */
+static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
+ void *_data, enum bsc_rllr_ind rllr_ind)
+{
+ struct sccp_source_reference ref = sccp_src_ref_from_int((u_int32_t) _data);
+ struct bss_sccp_connection_data *data = lchan->msc_data;
+
+ if (!data || !data->sccp) {
+ DEBUGP(DMSC, "Time-out/Establish after sccp release? Ind: %d lchan: %p\n",
+ rllr_ind, lchan);
+ return;
+ }
+
+ if (memcmp(&data->sccp->source_local_reference, &ref, sizeof(ref)) != 0) {
+ DEBUGP(DMSC, "Wrong SCCP connection. Not handling RLL callback: %u %u\n",
+ sccp_src_ref_to_int(&ref),
+ sccp_src_ref_to_int(&data->sccp->source_local_reference));
+ return;
+ }
+
+ switch (rllr_ind) {
+ case BSC_RLLR_IND_EST_CONF:
+ /* nothing to do */
+ bts_send_queued(data);
+ break;
+ case BSC_RLLR_IND_REL_IND:
+ case BSC_RLLR_IND_ERR_IND:
+ case BSC_RLLR_IND_TIMEOUT: {
+ /* reject queued messages */
+ struct msgb *sapi_reject;
+
+ bts_free_queued(data);
+ sapi_reject = bssmap_create_sapi_reject(link_id);
+ if (!sapi_reject){
+ DEBUGP(DMSC, "Failed to create SAPI reject\n");
+ return;
+ }
+
+ bsc_queue_connection_write(data->sccp, sapi_reject);
+ break;
+ }
+ }
+}
+
+/* decide if we need to queue because of SAPI != 0 */
+void bts_queue_send(struct msgb *msg, int link_id)
+{
+ struct bss_sccp_connection_data *data = msg->lchan->msc_data;
+
+ if (data->gsm_queue_size == 0) {
+ if (link_id == 0) {
+ rsl_data_request(msg, link_id);
+ } else {
+ msg->smsh = (unsigned char*) link_id;
+ msgb_enqueue(&data->gsm_queue, msg);
+ ++data->gsm_queue_size;
+
+ /* establish link */
+ rll_establish(msg->lchan, link_id & 0x7,
+ rll_ind_cb,
+ (void *)sccp_src_ref_to_int(&data->sccp->source_local_reference));
+ }
+ } else if (data->gsm_queue_size == 10) {
+ DEBUGP(DMSC, "Queue full on %p. Dropping GSM0408.\n", data->sccp);
+ } else {
+ DEBUGP(DMSC, "Queueing GSM0408 message on %p. Queue size: %d\n",
+ data->sccp, data->gsm_queue_size);
+
+ msg->smsh = (unsigned char*) link_id;
+ msgb_enqueue(&data->gsm_queue, msg);
+ ++data->gsm_queue_size;
+ }
+}
+
+void bts_free_queued(struct bss_sccp_connection_data *data)
+{
+ struct msgb *msg;
+
+ while (!llist_empty(&data->gsm_queue)) {
+ /* this is not allowed to fail */
+ msg = msgb_dequeue(&data->gsm_queue);
+ msgb_free(msg);
+ }
+
+ data->gsm_queue_size = 0;
+}
+
+void bts_send_queued(struct bss_sccp_connection_data *data)
+{
+ struct msgb *msg;
+
+ while (!llist_empty(&data->gsm_queue)) {
+ /* this is not allowed to fail */
+ msg = msgb_dequeue(&data->gsm_queue);
+ rsl_data_request(msg, (int) msg->smsh);
+ }
+
+ data->gsm_queue_size = 0;
+}
+
static __attribute__((constructor)) void on_dso_load_bssap(void)
{
register_signal_handler(SS_LCHAN, bssap_handle_lchan_signal, NULL);