aboutsummaryrefslogtreecommitdiffstats
path: root/libosmocore/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2010-04-30 14:29:56 +0200
committerHarald Welte <laforge@gnumonks.org>2010-04-30 14:29:56 +0200
commite562502e8d35356f3183a39ff6aad200d11a77bb (patch)
tree31d24174740b1b104a7c13b0086cbee4fecb90c5 /libosmocore/src
parente9dd9b047590064eec1c618475ece7f9627e0312 (diff)
parent074c9f904cb5e4f6ab014d76e4abc079c16fc5d7 (diff)
Merge commit '074c9f904cb5e4f6ab014d76e4abc079c16fc5d7'
Diffstat (limited to 'libosmocore/src')
-rw-r--r--libosmocore/src/Makefile.am2
-rw-r--r--libosmocore/src/gsm0808.c295
-rw-r--r--libosmocore/src/gsm48.c48
-rw-r--r--libosmocore/src/gsm48_ie.c2
-rw-r--r--libosmocore/src/logging.c27
-rw-r--r--libosmocore/src/msgb.c3
-rw-r--r--libosmocore/src/select.c3
-rw-r--r--libosmocore/src/write_queue.c3
8 files changed, 374 insertions, 9 deletions
diff --git a/libosmocore/src/Makefile.am b/libosmocore/src/Makefile.am
index 16978074a..20e99db30 100644
--- a/libosmocore/src/Makefile.am
+++ b/libosmocore/src/Makefile.am
@@ -10,7 +10,7 @@ lib_LTLIBRARIES = libosmocore.la
libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c rxlev_stat.c \
tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \
write_queue.c utils.c rsl.c gsm48.c gsm48_ie.c \
- logging.c
+ logging.c gsm0808.c
if ENABLE_TALLOC
libosmocore_la_SOURCES += talloc.c
diff --git a/libosmocore/src/gsm0808.c b/libosmocore/src/gsm0808.c
new file mode 100644
index 000000000..7a7eb3a08
--- /dev/null
+++ b/libosmocore/src/gsm0808.c
@@ -0,0 +1,295 @@
+/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009,2010 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocore/gsm0808.h>
+#include <osmocore/protocol/gsm_08_08.h>
+#include <osmocore/gsm48.h>
+
+#include <arpa/inet.h>
+
+#define BSSMAP_MSG_SIZE 512
+#define BSSMAP_MSG_HEADROOM 128
+
+struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci)
+{
+ uint8_t *data;
+ uint16_t *ci;
+ struct msgb* msg;
+ struct gsm48_loc_area_id *lai;
+
+ msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap cmpl l3");
+ if (!msg)
+ return NULL;
+
+ /* create the bssmap header */
+ msg->l3h = msgb_put(msg, 2);
+ msg->l3h[0] = 0x0;
+
+ /* create layer 3 header */
+ data = msgb_put(msg, 1);
+ data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
+
+ /* create the cell header */
+ data = msgb_put(msg, 3);
+ data[0] = GSM0808_IE_CELL_IDENTIFIER;
+ data[1] = 1 + sizeof(*lai) + 2;
+ data[2] = CELL_IDENT_WHOLE_GLOBAL;
+
+ lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
+ gsm48_generate_lai(lai, cc, nc, lac);
+
+ ci = (uint16_t *) msgb_put(msg, 2);
+ *ci = htons(_ci);
+
+ /* copy the layer3 data */
+ data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
+ data[0] = GSM0808_IE_LAYER_3_INFORMATION;
+ data[1] = msgb_l3len(msg_l3);
+ memcpy(&data[2], msg_l3->l3h, data[1]);
+
+ /* update the size */
+ msg->l3h[1] = msgb_l3len(msg) - 2;
+
+ return msg;
+}
+
+struct msgb *gsm0808_create_reset(void)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap: reset");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 6);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 0x04;
+ msg->l3h[2] = 0x30;
+ msg->l3h[3] = 0x04;
+ msg->l3h[4] = 0x01;
+ msg->l3h[5] = 0x20;
+ return msg;
+}
+
+struct msgb *gsm0808_create_clear_complete(void)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap: clear complete");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 3);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 1;
+ msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
+
+ return msg;
+}
+
+struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "cipher-complete");
+ if (!msg)
+ return NULL;
+
+ /* send response with BSS override for A5/1... cheating */
+ msg->l3h = msgb_put(msg, 3);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 0xff;
+ msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
+
+ /* include layer3 in case we have at least two octets */
+ if (layer3 && msgb_l3len(layer3) > 2) {
+ msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
+ msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
+ msg->l4h[1] = msgb_l3len(layer3);
+ memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
+ }
+
+ /* and the optional BSS message */
+ msg->l4h = msgb_put(msg, 2);
+ msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
+ msg->l4h[1] = alg_id;
+
+ /* update the size */
+ msg->l3h[1] = msgb_l3len(msg) - 2;
+ return msg;
+}
+
+struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap: clear complete");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 3);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 2;
+ msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
+ msg->l3h[3] = cause;
+
+ return msg;
+}
+
+struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "classmark-update");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 3);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 0xff;
+ msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
+
+ msg->l4h = msgb_put(msg, length);
+ memcpy(msg->l4h, classmark_data, length);
+
+ /* update the size */
+ msg->l3h[1] = msgb_l3len(msg) - 2;
+ return msg;
+}
+
+struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
+{
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap: sapi 'n' reject");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 5);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 3;
+ msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
+ msg->l3h[3] = link_id;
+ msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
+
+ return msg;
+}
+
+struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
+ uint8_t chosen_channel, uint8_t encr_alg_id,
+ uint8_t speech_mode)
+{
+ uint8_t *data;
+
+ struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 3);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 0xff;
+ msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
+
+ /* write 3.2.2.22 */
+ data = msgb_put(msg, 2);
+ data[0] = GSM0808_IE_RR_CAUSE;
+ data[1] = rr_cause;
+
+ /* write cirtcuit identity code 3.2.2.2 */
+ /* write cell identifier 3.2.2.17 */
+ /* write chosen channel 3.2.2.33 when BTS picked it */
+ data = msgb_put(msg, 2);
+ data[0] = GSM0808_IE_CHOSEN_CHANNEL;
+ data[1] = chosen_channel;
+
+ /* write chosen encryption algorithm 3.2.2.44 */
+ data = msgb_put(msg, 2);
+ data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
+ data[1] = encr_alg_id;
+
+ /* write circuit pool 3.2.2.45 */
+ /* write speech version chosen: 3.2.2.51 when BTS picked it */
+ if (speech_mode != 0) {
+ data = msgb_put(msg, 2);
+ data[0] = GSM0808_IE_SPEECH_VERSION;
+ data[1] = speech_mode;
+ }
+
+ /* write LSA identifier 3.2.2.15 */
+
+
+ /* update the size */
+ msg->l3h[1] = msgb_l3len(msg) - 2;
+ return msg;
+}
+
+struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
+{
+ uint8_t *data;
+ struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
+ "bssmap: ass fail");
+ if (!msg)
+ return NULL;
+
+ msg->l3h = msgb_put(msg, 6);
+ msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
+ msg->l3h[1] = 0xff;
+ msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
+ msg->l3h[3] = GSM0808_IE_CAUSE;
+ msg->l3h[4] = 1;
+ msg->l3h[5] = cause;
+
+ /* RR cause 3.2.2.22 */
+ if (rr_cause) {
+ data = msgb_put(msg, 2);
+ data[0] = GSM0808_IE_RR_CAUSE;
+ data[1] = *rr_cause;
+ }
+
+ /* Circuit pool 3.22.45 */
+ /* Circuit pool list 3.2.2.46 */
+
+ /* update the size */
+ msg->l3h[1] = msgb_l3len(msg) - 2;
+ return msg;
+}
+
+static const struct tlv_definition bss_att_tlvdef = {
+ .def = {
+ [GSM0808_IE_IMSI] = { TLV_TYPE_TLV },
+ [GSM0808_IE_TMSI] = { TLV_TYPE_TLV },
+ [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
+ [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
+ [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
+ [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
+ [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
+ [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
+ [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
+ [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
+ [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
+ [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
+ [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
+ [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
+ [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
+ [GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
+ [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
+ [GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV },
+ },
+};
+
+const struct tlv_definition *gsm0808_att_tlvdef()
+{
+ return &bss_att_tlvdef;
+}
diff --git a/libosmocore/src/gsm48.c b/libosmocore/src/gsm48.c
index 5761c67b4..783ff6a5d 100644
--- a/libosmocore/src/gsm48.c
+++ b/libosmocore/src/gsm48.c
@@ -97,10 +97,10 @@ static const struct value_string rr_cause_names[] = {
};
/* FIXME: convert to value_string */
-static const char *cc_state_names[32] = {
+static const char *cc_state_names[33] = {
"NULL",
"INITIATED",
- "illegal state 2",
+ "MM_CONNECTION_PEND",
"MO_CALL_PROC",
"CALL_DELIVERED",
"illegal state 5",
@@ -261,3 +261,47 @@ int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi)
return 2 + buf[1];
}
+
+/* Convert Mobile Identity (10.5.1.4) to string */
+int gsm48_mi_to_string(char *string, const int str_len, const uint8_t *mi,
+ const int mi_len)
+{
+ int i;
+ uint8_t mi_type;
+ char *str_cur = string;
+ uint32_t tmsi;
+
+ mi_type = mi[0] & GSM_MI_TYPE_MASK;
+
+ switch (mi_type) {
+ case GSM_MI_TYPE_NONE:
+ break;
+ case GSM_MI_TYPE_TMSI:
+ /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
+ if (mi_len == GSM48_TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
+ memcpy(&tmsi, &mi[1], 4);
+ tmsi = ntohl(tmsi);
+ return snprintf(string, str_len, "%u", tmsi);
+ }
+ break;
+ case GSM_MI_TYPE_IMSI:
+ case GSM_MI_TYPE_IMEI:
+ case GSM_MI_TYPE_IMEISV:
+ *str_cur++ = bcd2char(mi[0] >> 4);
+
+ for (i = 1; i < mi_len; i++) {
+ if (str_cur + 2 >= string + str_len)
+ return str_cur - string;
+ *str_cur++ = bcd2char(mi[i] & 0xf);
+ /* skip last nibble in last input byte when GSM_EVEN */
+ if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
+ *str_cur++ = bcd2char(mi[i] >> 4);
+ }
+ break;
+ default:
+ break;
+ }
+ *str_cur++ = '\0';
+
+ return str_cur - string;
+}
diff --git a/libosmocore/src/gsm48_ie.c b/libosmocore/src/gsm48_ie.c
index 4ca5fb800..3c2a1f7b6 100644
--- a/libosmocore/src/gsm48_ie.c
+++ b/libosmocore/src/gsm48_ie.c
@@ -2,7 +2,7 @@
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008-2010 by Andreas Eversberg
+ * (C) 2009-2010 by Andreas Eversberg
*
* All Rights Reserved
*
diff --git a/libosmocore/src/logging.c b/libosmocore/src/logging.c
index 508ccfd3e..7c508771f 100644
--- a/libosmocore/src/logging.c
+++ b/libosmocore/src/logging.c
@@ -20,11 +20,16 @@
*
*/
+#include "../config.h"
+
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+
+#ifdef HAVE_STRINGS_H
#include <strings.h>
+#endif
#include <time.h>
#include <errno.h>
@@ -302,31 +307,46 @@ void log_set_category_filter(struct log_target *target, int category,
target->categories[category].loglevel = level;
}
+/* since C89/C99 says stderr is a macro, we can safely do this! */
+#ifdef stderr
static void _stderr_output(struct log_target *target, const char *log)
{
fprintf(target->tgt_stdout.out, "%s", log);
fflush(target->tgt_stdout.out);
}
+#endif
struct log_target *log_target_create(void)
{
struct log_target *target;
+ unsigned int i;
target = talloc_zero(tall_log_ctx, struct log_target);
if (!target)
return NULL;
INIT_LLIST_HEAD(&target->entry);
- memcpy(target->categories, log_info->cat,
- sizeof(struct log_category)*log_info->num_cat);
+
+ /* initialize the per-category enabled/loglevel from defaults */
+ for (i = 0; i < log_info->num_cat; i++) {
+ struct log_category *cat = &target->categories[i];
+ cat->enabled = log_info->cat[i].enabled;
+ cat->loglevel = log_info->cat[i].loglevel;
+ }
+
+ /* global settings */
target->use_color = 1;
target->print_timestamp = 0;
+
+ /* global log level */
target->loglevel = 0;
return target;
}
struct log_target *log_target_create_stderr(void)
{
+/* since C89/C99 says stderr is a macro, we can safely do this! */
+#ifdef stderr
struct log_target *target;
target = log_target_create();
@@ -336,6 +356,9 @@ struct log_target *log_target_create_stderr(void)
target->tgt_stdout.out = stderr;
target->output = _stderr_output;
return target;
+#else
+ return NULL;
+#endif /* stderr */
}
void log_init(const struct log_info *cat)
diff --git a/libosmocore/src/msgb.c b/libosmocore/src/msgb.c
index 60af373eb..9117a0ad0 100644
--- a/libosmocore/src/msgb.c
+++ b/libosmocore/src/msgb.c
@@ -80,10 +80,9 @@ void msgb_reset(struct msgb *msg)
msg->head = msg->_data;
msg->tail = msg->_data;
- msg->bts_link = NULL;
msg->trx = NULL;
msg->lchan = NULL;
msg->l2h = NULL;
msg->l3h = NULL;
- msg->smsh = NULL;
+ msg->l4h = NULL;
}
diff --git a/libosmocore/src/select.c b/libosmocore/src/select.c
index 9517778ce..2f6afa7f5 100644
--- a/libosmocore/src/select.c
+++ b/libosmocore/src/select.c
@@ -121,7 +121,8 @@ restart:
/* ugly, ugly hack. If more than one filedescriptors were
* unregistered, they might have been consecutive and
* llist_for_each_entry_safe() is no longer safe */
- if (unregistered_count > 1)
+ /* this seems to happen with the last element of the list as well */
+ if (unregistered_count >= 1)
goto restart;
}
return work;
diff --git a/libosmocore/src/write_queue.c b/libosmocore/src/write_queue.c
index a0ac2d6fd..618a8c0b3 100644
--- a/libosmocore/src/write_queue.c
+++ b/libosmocore/src/write_queue.c
@@ -32,6 +32,9 @@ int write_queue_bfd_cb(struct bsc_fd *fd, unsigned int what)
if (what & BSC_FD_READ)
queue->read_cb(fd);
+ if (what & BSC_FD_EXCEPT)
+ queue->except_cb(fd);
+
if (what & BSC_FD_WRITE) {
struct msgb *msg;