From: Harald Welte Date: Thu, 4 Mar 2010 10:59:12 +0000 (+0100) Subject: Merge commit '61e2bfc5f44267a7a3b0b25ff3ab922fca2a199c' X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=2507c4b1427ef52328a64ee5391e6253663d265d;p=osmocom-bb.git Merge commit '61e2bfc5f44267a7a3b0b25ff3ab922fca2a199c' --- 2507c4b1427ef52328a64ee5391e6253663d265d diff --cc src/shared/libosmocore/include/osmocore/Makefile.am index 8754295,0000000..b45d023 mode 100644,000000..100644 --- a/src/shared/libosmocore/include/osmocore/Makefile.am +++ b/src/shared/libosmocore/include/osmocore/Makefile.am @@@ -1,7 -1,0 +1,7 @@@ +osmocore_HEADERS = signal.h linuxlist.h timer.h talloc.h msgb.h select.h \ + tlv.h bitvec.h comp128.h statistics.h gsm_utils.h utils.h \ - gsmtap.h write_queue.h rsl.h ++ gsmtap.h write_queue.h rsl.h gsm48.h + +osmocoredir = $(includedir)/osmocore + +SUBDIRS = protocol diff --cc src/shared/libosmocore/include/osmocore/gsm48.h index 0000000,0000000..95963d5 new file mode 100644 --- /dev/null +++ b/src/shared/libosmocore/include/osmocore/gsm48.h @@@ -1,0 -1,0 +1,16 @@@ ++#ifndef _OSMOCORE_GSM48_H ++ ++#include ++#include ++ ++extern const struct tlv_definition gsm48_att_tlvdef; ++extern const char *cc_state_names[32]; ++const char *gsm48_cc_msg_names[0x40]; ++const char *rr_cause_name(uint8_t cause); ++ ++void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, ++ uint16_t mnc, uint16_t lac); ++int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi); ++int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi); ++ ++#endif diff --cc src/shared/libosmocore/include/osmocore/gsm_utils.h index 57521ac,0000000..b611050 mode 100644,000000..100644 --- a/src/shared/libosmocore/include/osmocore/gsm_utils.h +++ b/src/shared/libosmocore/include/osmocore/gsm_utils.h @@@ -1,59 -1,0 +1,62 @@@ +/* GSM utility functions, e.g. coding and decoding */ +/* + * (C) 2008 by Daniel Willmann + * (C) 2009 by Holger Hans Peter Freyther - * (C) 2009 by Harald Welte ++ * (C) 2009-2010 by Harald Welte + * + * 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. + * + */ + +#ifndef GSM_UTILS_H +#define GSM_UTILS_H + +#include + +enum gsm_band { + GSM_BAND_850 = 1, + GSM_BAND_900 = 2, + GSM_BAND_1800 = 4, + GSM_BAND_1900 = 8, + GSM_BAND_450 = 0x10, + GSM_BAND_480 = 0x20, + GSM_BAND_750 = 0x40, + GSM_BAND_810 = 0x80, +}; + ++char *gsm_band_name(enum gsm_band band); ++enum gsm_band gsm_band_parse(const char *mhz); ++ +int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length); +int gsm_7bit_encode(uint8_t *result, const char *data); + +int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm); +int ms_pwr_dbm(enum gsm_band band, uint8_t lvl); + +/* According to TS 08.05 Chapter 8.1.4 */ +int rxlev2dbm(uint8_t rxlev); +uint8_t dbm2rxlev(int dbm); + +/* According to GSM 04.08 Chapter 10.5.2.29 */ +static inline int rach_max_trans_val2raw(int val) { return (val >> 1) & 3; } +static inline int rach_max_trans_raw2val(int raw) { + const int tbl[4] = { 1, 2, 4, 7 }; + return tbl[raw & 3]; +} + +void generate_backtrace(); +#endif diff --cc src/shared/libosmocore/include/osmocore/rsl.h index 250c6ea,0000000..0da0520 mode 100644,000000..100644 --- a/src/shared/libosmocore/include/osmocore/rsl.h +++ b/src/shared/libosmocore/include/osmocore/rsl.h @@@ -1,31 -1,0 +1,31 @@@ +#ifndef _OSMOCORE_RSL_H +#define _OSMOCORE_RSL_H + +#include +#include +#include + +void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type); + +extern const struct tlv_definition rsl_att_tlvdef; +#define rsl_tlv_parse(dec, buf, len) \ + tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0) + +/* encode channel number as per Section 9.3.1 */ +uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot); + +const struct value_string rsl_rlm_cause_strs[]; + +const char *rsl_err_name(uint8_t err); + +/* Section 3.3.2.3 TS 05.02. I think this looks like a table */ +int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf); + +/* Push a RSL RLL header with L3_INFO IE */ - int rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, - uint8_t chan_nr, uint8_t link_id); ++void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, ++ uint8_t link_id, int transparent); + +/* Allocate msgb and fill with simple RSL RLL header */ +struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id); ++ uint8_t link_id, int transparent); +#endif /* _OSMOCORE_RSL_H */ diff --cc src/shared/libosmocore/include/osmocore/utils.h index cf3b460,0000000..51c6f03 mode 100644,000000..100644 --- a/src/shared/libosmocore/include/osmocore/utils.h +++ b/src/shared/libosmocore/include/osmocore/utils.h @@@ -1,17 -1,0 +1,20 @@@ +#ifndef OSMOCORE_UTIL_H +#define OSMOCORE_UTIL_H + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#include + +struct value_string { + unsigned int value; + const char *str; +}; + +const char *get_value_string(const struct value_string *vs, uint32_t val); +int get_string_value(const struct value_string *vs, const char *str); + ++char bcd2char(uint8_t bcd); ++/* only works for numbers in ascci */ ++uint8_t char2bcd(char c); + +#endif diff --cc src/shared/libosmocore/src/Makefile.am index 65415ee,0000000..b6826ea mode 100644,000000..100644 --- a/src/shared/libosmocore/src/Makefile.am +++ b/src/shared/libosmocore/src/Makefile.am @@@ -1,12 -1,0 +1,12 @@@ +# This is _NOT_ the library release version, it's an API version. +# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification +LIBVERSION=0:0:0 + +INCLUDES = $(all_includes) -I$(top_srcdir)/include +AM_CFLAGS = -fPIC -Wall + +lib_LTLIBRARIES = libosmocore.la + +libosmocore_la_SOURCES = msgb.c timer.c talloc.c select.c signal.c \ + tlv_parser.c bitvec.c comp128.c gsm_utils.c statistics.c \ - write_queue.c utils.c rsl.c ++ write_queue.c utils.c rsl.c gsm48.c diff --cc src/shared/libosmocore/src/gsm48.c index 0000000,0000000..ff989ea new file mode 100644 --- /dev/null +++ b/src/shared/libosmocore/src/gsm48.c @@@ -1,0 -1,0 +1,283 @@@ ++/* GSM Mobile Radio Interface Layer 3 messages ++ * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ ++ ++/* (C) 2008-2009 by Harald Welte ++ * (C) 2008, 2009 by Holger Hans Peter Freyther ++ * ++ * 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 ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++const struct tlv_definition gsm48_att_tlvdef = { ++ .def = { ++ [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV }, ++ [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV }, ++ [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV }, ++ [GSM48_IE_UTC] = { TLV_TYPE_TV }, ++ [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 }, ++ [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV }, ++ ++ [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CAUSE] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV }, ++ [GSM48_IE_ALERT] = { TLV_TYPE_TLV }, ++ [GSM48_IE_FACILITY] = { TLV_TYPE_TLV }, ++ [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV }, ++ [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV }, ++ [GSM48_IE_NOTIFY] = { TLV_TYPE_TV }, ++ [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV }, ++ [GSM48_IE_SIGNAL] = { TLV_TYPE_TV }, ++ [GSM48_IE_CONN_BCD] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CONN_SUB] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV }, ++ [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV }, ++ [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV }, ++ [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV }, ++ [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV }, ++ [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV }, ++ [GSM48_IE_USER_USER] = { TLV_TYPE_TLV }, ++ [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV }, ++ [GSM48_IE_MORE_DATA] = { TLV_TYPE_T }, ++ [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T }, ++ [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T }, ++ [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T }, ++ [GSM48_IE_REPEAT_CIR] = { TLV_TYPE_T }, ++ [GSM48_IE_REPEAT_SEQ] = { TLV_TYPE_T }, ++ /* FIXME: more elements */ ++ }, ++}; ++ ++static const char *rr_cause_names[] = { ++ [GSM48_RR_CAUSE_NORMAL] = "Normal event", ++ [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified", ++ [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable", ++ [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired", ++ [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path", ++ [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release", ++ [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range", ++ [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable", ++ [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented", ++ [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared", ++ [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message", ++ [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information", ++ [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented", ++ [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state", ++ [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error", ++ [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available", ++ [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified", ++}; ++ ++const char *cc_state_names[32] = { ++ "NULL", ++ "INITIATED", ++ "illegal state 2", ++ "MO_CALL_PROC", ++ "CALL_DELIVERED", ++ "illegal state 5", ++ "CALL_PRESENT", ++ "CALL_RECEIVED", ++ "CONNECT_REQUEST", ++ "MO_TERM_CALL_CONF", ++ "ACTIVE", ++ "DISCONNECT_REQ", ++ "DISCONNECT_IND", ++ "illegal state 13", ++ "illegal state 14", ++ "illegal state 15", ++ "illegal state 16", ++ "illegal state 17", ++ "illegal state 18", ++ "RELEASE_REQ", ++ "illegal state 20", ++ "illegal state 21", ++ "illegal state 22", ++ "illegal state 23", ++ "illegal state 24", ++ "illegal state 25", ++ "MO_ORIG_MODIFY", ++ "MO_TERM_MODIFY", ++ "CONNECT_IND", ++ "illegal state 29", ++ "illegal state 30", ++ "illegal state 31", ++}; ++ ++const char *gsm48_cc_msg_names[0x40] = { ++ "unknown 0x00", ++ "ALERTING", ++ "CALL_PROC", ++ "PROGRESS", ++ "ESTAB", ++ "SETUP", ++ "ESTAB_CONF", ++ "CONNECT", ++ "CALL_CONF", ++ "START_CC", ++ "unknown 0x0a", ++ "RECALL", ++ "unknown 0x0c", ++ "unknown 0x0d", ++ "EMERG_SETUP", ++ "CONNECT_ACK", ++ "USER_INFO", ++ "unknown 0x11", ++ "unknown 0x12", ++ "MODIFY_REJECT", ++ "unknown 0x14", ++ "unknown 0x15", ++ "unknown 0x16", ++ "MODIFY", ++ "HOLD", ++ "HOLD_ACK", ++ "HOLD_REJ", ++ "unknown 0x1b", ++ "RETR", ++ "RETR_ACK", ++ "RETR_REJ", ++ "MODIFY_COMPL", ++ "unknown 0x20", ++ "unknown 0x21", ++ "unknown 0x22", ++ "unknown 0x23", ++ "unknown 0x24", ++ "DISCONNECT", ++ "unknown 0x26", ++ "unknown 0x27", ++ "unknown 0x28", ++ "unknown 0x29", ++ "RELEASE_COMPL", ++ "unknown 0x2b", ++ "unknown 0x2c", ++ "RELEASE", ++ "unknown 0x2e", ++ "unknown 0x2f", ++ "unknown 0x30", ++ "STOP_DTMF", ++ "STOP_DTMF_ACK", ++ "unknown 0x33", ++ "STATUS_ENQ", ++ "START_DTMF", ++ "START_DTMF_ACK", ++ "START_DTMF_REJ", ++ "unknown 0x38", ++ "CONG_CTRL", ++ "FACILITY", ++ "unknown 0x3b", ++ "STATUS", ++ "unknown 0x3d", ++ "NOTIFY", ++ "unknown 0x3f", ++}; ++ ++static char strbuf[64]; ++ ++const char *rr_cause_name(uint8_t cause) ++{ ++ if (cause < ARRAY_SIZE(rr_cause_names) && ++ rr_cause_names[cause]) ++ return rr_cause_names[cause]; ++ ++ snprintf(strbuf, sizeof(strbuf), "0x%02x", cause); ++ return strbuf; ++} ++ ++static void to_bcd(uint8_t *bcd, uint16_t val) ++{ ++ bcd[2] = val % 10; ++ val = val / 10; ++ bcd[1] = val % 10; ++ val = val / 10; ++ bcd[0] = val % 10; ++ val = val / 10; ++} ++ ++void gsm48_generate_lai(struct gsm48_loc_area_id *lai48, uint16_t mcc, ++ uint16_t mnc, uint16_t lac) ++{ ++ uint8_t bcd[3]; ++ ++ to_bcd(bcd, mcc); ++ lai48->digits[0] = bcd[0] | (bcd[1] << 4); ++ lai48->digits[1] = bcd[2]; ++ ++ to_bcd(bcd, mnc); ++ /* FIXME: do we need three-digit MNC? See Table 10.5.3 */ ++#if 0 ++ lai48->digits[1] |= bcd[2] << 4; ++ lai48->digits[2] = bcd[0] | (bcd[1] << 4); ++#else ++ lai48->digits[1] |= 0xf << 4; ++ lai48->digits[2] = bcd[1] | (bcd[2] << 4); ++#endif ++ ++ lai48->lac = htons(lac); ++} ++ ++int gsm48_generate_mid_from_tmsi(uint8_t *buf, uint32_t tmsi) ++{ ++ uint32_t *tptr = (uint32_t *) &buf[3]; ++ ++ buf[0] = GSM48_IE_MOBILE_ID; ++ buf[1] = GSM48_TMSI_LEN; ++ buf[2] = 0xf0 | GSM_MI_TYPE_TMSI; ++ *tptr = htonl(tmsi); ++ ++ return 7; ++} ++ ++int gsm48_generate_mid_from_imsi(uint8_t *buf, const char *imsi) ++{ ++ unsigned int length = strlen(imsi), i, off = 0; ++ uint8_t odd = (length & 0x1) == 1; ++ ++ buf[0] = GSM48_IE_MOBILE_ID; ++ buf[2] = char2bcd(imsi[0]) << 4 | GSM_MI_TYPE_IMSI | (odd << 3); ++ ++ /* if the length is even we will fill half of the last octet */ ++ if (odd) ++ buf[1] = (length + 1) >> 1; ++ else ++ buf[1] = (length + 2) >> 1; ++ ++ for (i = 1; i < buf[1]; ++i) { ++ uint8_t lower, upper; ++ ++ lower = char2bcd(imsi[++off]); ++ if (!odd && off + 1 == length) ++ upper = 0x0f; ++ else ++ upper = char2bcd(imsi[++off]) & 0x0f; ++ ++ buf[2 + i] = (upper << 4) | lower; ++ } ++ ++ return 2 + buf[1]; ++} diff --cc src/shared/libosmocore/src/gsm_utils.c index b0a66a6,0000000..174b2d4 mode 100644,000000..100644 --- a/src/shared/libosmocore/src/gsm_utils.c +++ b/src/shared/libosmocore/src/gsm_utils.c @@@ -1,215 -1,0 +1,270 @@@ +/* + * (C) 2008 by Daniel Willmann + * (C) 2009 by Holger Hans Peter Freyther + * (C) 2009 by Harald Welte + * + * 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 +#include +#include + +#include +#include +#include +#include +#include ++#include + +#include "../config.h" + +/* GSM 03.38 6.2.1 Charachter packing */ +int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t length) +{ + int i = 0; + int l = 0; + + /* FIXME: We need to account for user data headers here */ + i += l; + for (; i < length; i ++) + *(text ++) = + ((user_data[(i * 7 + 7) >> 3] << + (7 - ((i * 7 + 7) & 7))) | + (user_data[(i * 7) >> 3] >> + ((i * 7) & 7))) & 0x7f; + *text = '\0'; + + return i - l; +} + + +/* GSM 03.38 6.2.1 Charachter packing */ +int gsm_7bit_encode(uint8_t *result, const char *data) +{ + int i,j = 0; + unsigned char ch1, ch2; + int shift = 0; + + for ( i=0; i> shift; + ch2 = data[(i+1)] & 0x7F; + ch2 = ch2 << (7-shift); + + ch1 = ch1 | ch2; + + result[j++] = ch1; + + shift++; + + if ((shift == 7) && (i+1= 39) + return 0; + else if (dbm < 5) + return 19; + else { + /* we are guaranteed to have (5 <= dbm < 39) */ + return 2 + ((39 - dbm) / 2); + } + break; + case GSM_BAND_1800: + if (dbm >= 36) + return 29; + else if (dbm >= 34) + return 30; + else if (dbm >= 32) + return 31; + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ + return (30 - dbm) / 2; + } + break; + case GSM_BAND_1900: + if (dbm >= 33) + return 30; + else if (dbm >= 32) + return 31; + else if (dbm == 31) + return 0; + else { + /* we are guaranteed to have (0 <= dbm < 31) */ + return (30 - dbm) / 2; + } + break; + } + return -EINVAL; +} + +int ms_pwr_dbm(enum gsm_band band, uint8_t lvl) +{ + lvl &= 0x1f; + + switch (band) { + case GSM_BAND_450: + case GSM_BAND_480: + case GSM_BAND_750: + case GSM_BAND_900: + case GSM_BAND_810: + case GSM_BAND_850: + if (lvl < 2) + return 39; + else if (lvl < 20) + return 39 - ((lvl - 2) * 2) ; + else + return 5; + break; + case GSM_BAND_1800: + if (lvl < 16) + return 30 - (lvl * 2); + else if (lvl < 29) + return 0; + else + return 36 - ((lvl - 29) * 2); + break; + case GSM_BAND_1900: + if (lvl < 16) + return 30 - (lvl * 2); + else if (lvl < 30) + return -EINVAL; + else + return 33 - (lvl - 30); + break; + } + return -EINVAL; +} + +/* According to TS 08.05 Chapter 8.1.4 */ +int rxlev2dbm(uint8_t rxlev) +{ + if (rxlev > 63) + rxlev = 63; + + return -110 + rxlev; +} + +/* According to TS 08.05 Chapter 8.1.4 */ +uint8_t dbm2rxlev(int dbm) +{ + int rxlev = dbm + 110; + + if (rxlev > 63) + rxlev = 63; + else if (rxlev < 0) + rxlev = 0; + + return rxlev; +} + ++char *gsm_band_name(enum gsm_band band) ++{ ++ switch (band) { ++ case GSM_BAND_450: ++ return "GSM450"; ++ case GSM_BAND_480: ++ return "GSM450"; ++ case GSM_BAND_750: ++ return "GSM750"; ++ case GSM_BAND_810: ++ return "GSM810"; ++ case GSM_BAND_850: ++ return "GSM850"; ++ case GSM_BAND_900: ++ return "GSM900"; ++ case GSM_BAND_1800: ++ return "DCS1800"; ++ case GSM_BAND_1900: ++ return "PCS1900"; ++ } ++ return "invalid"; ++} ++ ++enum gsm_band gsm_band_parse(const char* mhz) ++{ ++ while (*mhz && !isdigit(*mhz)) ++ mhz++; ++ ++ if (*mhz == '\0') ++ return -EINVAL; ++ ++ switch (atoi(mhz)) { ++ case 450: ++ return GSM_BAND_450; ++ case 480: ++ return GSM_BAND_480; ++ case 750: ++ return GSM_BAND_750; ++ case 810: ++ return GSM_BAND_810; ++ case 850: ++ return GSM_BAND_850; ++ case 900: ++ return GSM_BAND_900; ++ case 1800: ++ return GSM_BAND_1800; ++ case 1900: ++ return GSM_BAND_1900; ++ default: ++ return -EINVAL; ++ } ++} ++ ++ +#ifdef HAVE_EXECINFO_H +#include +void generate_backtrace() +{ + int i, nptrs; + void *buffer[100]; + char **strings; + + nptrs = backtrace(buffer, ARRAY_SIZE(buffer)); + printf("backtrace() returned %d addresses\n", nptrs); + + strings = backtrace_symbols(buffer, nptrs); + if (!strings) + return; + + for (i = 1; i < nptrs; i++) + printf("%s\n", strings[i]); + + free(strings); +} +#endif diff --cc src/shared/libosmocore/src/rsl.c index 62cd562,0000000..58afc9d mode 100644,000000..100644 --- a/src/shared/libosmocore/src/rsl.c +++ b/src/shared/libosmocore/src/rsl.c @@@ -1,287 -1,0 +1,293 @@@ +/* GSM Radio Signalling Link messages on the A-bis interface + * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */ + - /* (C) 2008-2009 by Harald Welte ++/* (C) 2008-2010 by Harald Welte + * + * 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 +#include + ++#define RSL_ALLOC_SIZE 200 ++#define RSL_ALLOC_HEADROOM 56 ++ +void rsl_init_rll_hdr(struct abis_rsl_rll_hdr *dh, uint8_t msg_type) +{ + dh->c.msg_discr = ABIS_RSL_MDISC_RLL; + dh->c.msg_type = msg_type; + dh->ie_chan = RSL_IE_CHAN_NR; + dh->ie_link_id = RSL_IE_LINK_IDENT; +} + +const struct tlv_definition rsl_att_tlvdef = { + .def = { + [RSL_IE_CHAN_NR] = { TLV_TYPE_TV }, + [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV }, + [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_BS_POWER] = { TLV_TYPE_TV }, + [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV }, + [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_HANDO_REF] = { TLV_TYPE_TV }, + [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V }, + [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV }, + [RSL_IE_MS_POWER] = { TLV_TYPE_TV }, + [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV }, + [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV }, + [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV }, + [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV }, + [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 }, + [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV }, + [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV }, + [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV }, + [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV }, + [RSL_IE_CAUSE] = { TLV_TYPE_TLV }, + [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV }, + [RSL_IE_MSG_ID] = { TLV_TYPE_TV }, + [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV }, + [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV }, + [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 }, + [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV }, + [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV }, + [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV }, + [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV }, + [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV }, + [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV }, + [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV }, + [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV }, + [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV }, + [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV }, + [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV }, + [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV }, + [RSL_IE_UIC] = { TLV_TYPE_TLV }, + [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV }, + [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV }, + [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV }, + [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV }, + [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV }, + [RSL_IE_RTD] = { TLV_TYPE_TV }, + [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV }, + [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV }, + [RSL_IE_SIEMENS_MRPCI] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_PROXY_UDP] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_BSCMPL_TOUT] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 }, + [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_RTP_PAYLOAD] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_SPEECH_MODE] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 }, + [RSL_IE_IPAC_CONN_ID] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_RTP_CSD_FMT] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_RTP_JIT_BUF] = { TLV_TYPE_FIXED, 2 }, + [RSL_IE_IPAC_RTP_COMPR] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_RTP_PAYLOAD2] = { TLV_TYPE_TV }, + [RSL_IE_IPAC_RTP_MPLEX] = { TLV_TYPE_FIXED, 8 }, + [RSL_IE_IPAC_RTP_MPLEX_ID] = { TLV_TYPE_TV }, + }, +}; + +/* encode channel number as per Section 9.3.1 */ +uint8_t rsl_enc_chan_nr(uint8_t type, uint8_t subch, uint8_t timeslot) +{ + uint8_t ret; + + ret = (timeslot & 0x07) | type; + + switch (type) { + case RSL_CHAN_Lm_ACCHs: + subch &= 0x01; + break; + case RSL_CHAN_SDCCH4_ACCH: - subch &= 0x07; ++ subch &= 0x03; + break; + case RSL_CHAN_SDCCH8_ACCH: + subch &= 0x07; + break; + default: + /* no subchannels allowed */ + subch = 0x00; + break; + } + ret |= (subch << 3); + + return ret; +} + +/* FIXME: convert to value_string */ +static const char *rsl_err_vals[0xff] = { + [RSL_ERR_RADIO_IF_FAIL] = "Radio Interface Failure", + [RSL_ERR_RADIO_LINK_FAIL] = "Radio Link Failure", + [RSL_ERR_HANDOVER_ACC_FAIL] = "Handover Access Failure", + [RSL_ERR_TALKER_ACC_FAIL] = "Talker Access Failure", + [RSL_ERR_OM_INTERVENTION] = "O&M Intervention", + [RSL_ERR_NORMAL_UNSPEC] = "Normal event, unspecified", + [RSL_ERR_T_MSRFPCI_EXP] = "Siemens: T_MSRFPCI Expired", + [RSL_ERR_EQUIPMENT_FAIL] = "Equipment Failure", + [RSL_ERR_RR_UNAVAIL] = "Radio Resource not available", + [RSL_ERR_TERR_CH_FAIL] = "Terrestrial Channel Failure", + [RSL_ERR_CCCH_OVERLOAD] = "CCCH Overload", + [RSL_ERR_ACCH_OVERLOAD] = "ACCH Overload", + [RSL_ERR_PROCESSOR_OVERLOAD] = "Processor Overload", + [RSL_ERR_RES_UNAVAIL] = "Resource not available, unspecified", + [RSL_ERR_TRANSC_UNAVAIL] = "Transcoding not available", + [RSL_ERR_SERV_OPT_UNAVAIL] = "Service or Option not available", + [RSL_ERR_ENCR_UNIMPL] = "Encryption algorithm not implemented", + [RSL_ERR_SERV_OPT_UNIMPL] = "Service or Option not implemented", + [RSL_ERR_RCH_ALR_ACTV_ALLOC] = "Radio channel already activated", + [RSL_ERR_INVALID_MESSAGE] = "Invalid Message, unspecified", + [RSL_ERR_MSG_DISCR] = "Message Discriminator Error", + [RSL_ERR_MSG_TYPE] = "Message Type Error", + [RSL_ERR_MSG_SEQ] = "Message Sequence Error", + [RSL_ERR_IE_ERROR] = "General IE error", + [RSL_ERR_MAND_IE_ERROR] = "Mandatory IE error", + [RSL_ERR_OPT_IE_ERROR] = "Optional IE error", + [RSL_ERR_IE_NONEXIST] = "IE non-existent", + [RSL_ERR_IE_LENGTH] = "IE length error", + [RSL_ERR_IE_CONTENT] = "IE content error", + [RSL_ERR_PROTO] = "Protocol error, unspecified", + [RSL_ERR_INTERWORKING] = "Interworking error, unspecified", +}; + +const struct value_string rsl_rlm_cause_strs[] = { + { RLL_CAUSE_T200_EXPIRED, "Timer T200 expired (N200+1) times" }, + { RLL_CAUSE_REEST_REQ, "Re-establishment request" }, + { RLL_CAUSE_UNSOL_UA_RESP, "Unsolicited UA response" }, + { RLL_CAUSE_UNSOL_DM_RESP, "Unsolicited DM response" }, + { RLL_CAUSE_UNSOL_DM_RESP_MF, "Unsolicited DM response, multiple frame" }, + { RLL_CAUSE_UNSOL_SPRV_RESP, "Unsolicited supervisory response" }, + { RLL_CAUSE_SEQ_ERR, "Sequence Error" }, + { RLL_CAUSE_UFRM_INC_PARAM, "U-Frame with incorrect parameters" }, + { RLL_CAUSE_SFRM_INC_PARAM, "S-Frame with incorrect parameters" }, + { RLL_CAUSE_IFRM_INC_MBITS, "I-Frame with incorrect use of M bit" }, + { RLL_CAUSE_IFRM_INC_LEN, "I-Frame with incorrect length" }, + { RLL_CAUSE_FRM_UNIMPL, "Fraeme not implemented" }, + { RLL_CAUSE_SABM_MF, "SABM command, multiple frame established state" }, + { RLL_CAUSE_SABM_INFO_NOTALL, "SABM frame with information not allowed in this state" }, + { 0, NULL }, +}; + +const char *rsl_err_name(uint8_t err) +{ + if (rsl_err_vals[err]) + return rsl_err_vals[err]; + else + return "unknown"; +} + +/* Section 3.3.2.3 TS 05.02. I think this looks like a table */ +int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf) +{ + switch (ccch_conf) { + case RSL_BCCH_CCCH_CONF_1_NC: + return 1; + case RSL_BCCH_CCCH_CONF_1_C: + return 1; + case RSL_BCCH_CCCH_CONF_2_NC: + return 2; + case RSL_BCCH_CCCH_CONF_3_NC: + return 3; + case RSL_BCCH_CCCH_CONF_4_NC: + return 4; + default: + return -1; + } +} + +/* Section 3.3.2.3 TS 05.02 */ +int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf) +{ + switch (ccch_conf) { + case RSL_BCCH_CCCH_CONF_1_NC: + return 0; + case RSL_BCCH_CCCH_CONF_1_C: + return 1; + case RSL_BCCH_CCCH_CONF_2_NC: + return 0; + case RSL_BCCH_CCCH_CONF_3_NC: + return 0; + case RSL_BCCH_CCCH_CONF_4_NC: + return 0; + default: + return -1; + } +} + +/* Push a RSL RLL header with L3_INFO IE */ - int rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, - uint8_t chan_nr, uint8_t link_id) ++void rsl_rll_push_l3(struct msgb *msg, uint8_t msg_type, uint8_t chan_nr, ++ uint8_t link_id, int transparent) +{ + uint8_t l3_len = msg->tail - (uint8_t *)msgb_l3(msg); + struct abis_rsl_rll_hdr *rh; + + /* construct a RSLms RLL message (DATA INDICATION, UNIT DATA + * INDICATION) and send it off via RSLms */ + + /* Push the L3 IE tag and lengh */ + msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); + + /* Then push the RSL header */ + rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh)); + rsl_init_rll_hdr(rh, msg_type); - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; ++ if (transparent) ++ rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; + rh->chan_nr = chan_nr; + rh->link_id = link_id; + + /* set the l2 header pointer */ + msg->l2h = (uint8_t *)rh; - - return 0; +} + +struct msgb *rsl_rll_simple(uint8_t msg_type, uint8_t chan_nr, - uint8_t link_id) ++ uint8_t link_id, int transparent) +{ + struct abis_rsl_rll_hdr *rh; - struct msgb *msg = msgb_alloc(sizeof(*rh), "rsl_rll_simple"); ++ struct msgb *msg; ++ ++ msg = msgb_alloc_headroom(RSL_ALLOC_SIZE+RSL_ALLOC_HEADROOM, ++ RSL_ALLOC_HEADROOM, "rsl_rll_simple"); + + if (!msg) + return NULL; + + /* put the RSL header */ + rh = (struct abis_rsl_rll_hdr *) msgb_put(msg, sizeof(*rh)); + rsl_init_rll_hdr(rh, msg_type); - rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; ++ if (transparent) ++ rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP; + rh->chan_nr = chan_nr; + rh->link_id = link_id; + + /* set the l2 header pointer */ + msg->l2h = (uint8_t *)rh; + + return msg; +} diff --cc src/shared/libosmocore/src/utils.c index 0d878c7,0000000..2a73d39 mode 100644,000000..100644 --- a/src/shared/libosmocore/src/utils.c +++ b/src/shared/libosmocore/src/utils.c @@@ -1,32 -1,0 +1,46 @@@ + +#include +#include +#include + +#include + +const char *get_value_string(const struct value_string *vs, uint32_t val) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (vs[i].value == val) + return vs[i].str; + } + return "unknown"; +} + +int get_string_value(const struct value_string *vs, const char *str) +{ + int i; + + for (i = 0;; i++) { + if (vs[i].value == 0 && vs[i].str == NULL) + break; + if (!strcasecmp(vs[i].str, str)) + return vs[i].value; + } + return -EINVAL; +} ++ ++char bcd2char(uint8_t bcd) ++{ ++ if (bcd < 0xa) ++ return '0' + bcd; ++ else ++ return 'A' + (bcd - 0xa); ++} ++ ++/* only works for numbers in ascci */ ++uint8_t char2bcd(char c) ++{ ++ return c - 0x30; ++}