[bsc_msc_ip] This is a BSC that connects to real MSC via IP
This is a BSC to be used by on-waves.com to connect to a real MSC using SCCP over IP. The following messages and features are currently implemented: - IPA identity ack's - COMPLETE LAYER3 INFORMATION - DTAP - PAGING COMMAND - CLEAR COMPLETE/CLEAR REQUEST - CIPHER MODE COMMAND/ REJECT /COMPLETE It comes with a tool to create the enum's from the spec and a very simple test server to do the handshaking.
This commit is contained in:
parent
adb8bcea5f
commit
d954dcf9e1
|
@ -0,0 +1,2 @@
|
|||
This contains a set of scripts used for the development of the
|
||||
MSC functionality.
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
|
||||
# packages
|
||||
ACK ="\x00\x01\xfe\x06"
|
||||
RESET_ACK = "\x00\x13\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x03\x00\x01\x31"
|
||||
PAGE = "\x00\x20\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x10\x00\x0e\x52\x08\x08\x29\x42\x08\x05\x03\x12\x23\x42\x1a\x01\x06"
|
||||
|
||||
|
||||
# simple handshake...
|
||||
sys.stdout.write(ACK)
|
||||
sys.stdout.flush()
|
||||
sys.stdin.read(4)
|
||||
|
||||
# wait for some data and send reset ack
|
||||
sys.stdin.read(21)
|
||||
sys.stdout.write(RESET_ACK)
|
||||
sys.stdout.flush()
|
||||
|
||||
sys.stdout.write(RESET_ACK)
|
||||
sys.stdout.flush()
|
||||
|
||||
# page a subscriber
|
||||
sys.stdout.write(PAGE)
|
||||
sys.stdout.flush()
|
||||
|
||||
while True:
|
||||
sys.stdin.read(1)
|
||||
|
|
@ -3,4 +3,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
|
|||
timer.h misdn.h chan_alloc.h telnet_interface.h paging.h \
|
||||
subchan_demux.h trau_frame.h e1_input.h trau_mux.h signal.h \
|
||||
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
|
||||
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h
|
||||
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h bssap.h
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
/* From GSM08.08 */
|
||||
|
||||
#ifndef BSSAP_H
|
||||
#define BSSAP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openbsc/msgb.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
|
||||
/*
|
||||
* this is from GSM 03.03 CGI but is copied in GSM 08.08
|
||||
* in § 3.2.2.27 for Cell Identifier List
|
||||
*/
|
||||
enum CELL_IDENT {
|
||||
CELL_IDENT_WHOLE_GLOBAL = 0,
|
||||
CELL_IDENT_LAC_AND_CI = 1,
|
||||
CELL_IDENT_CI = 2,
|
||||
CELL_IDENT_NO_CELL = 3,
|
||||
CELL_IDENT_LAI_AND_LAC = 4,
|
||||
CELL_IDENT_LAC = 5,
|
||||
CELL_IDENT_BSS = 6,
|
||||
CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8,
|
||||
CELL_IDENT_UTRAN_RNC = 9,
|
||||
CELL_IDENT_UTRAN_LAC_RNC = 10,
|
||||
};
|
||||
|
||||
|
||||
/* GSM 08.06 § 6.3 */
|
||||
enum BSSAP_MSG_TYPE {
|
||||
BSSAP_MSG_BSS_MANAGEMENT = 0x0,
|
||||
BSSAP_MSG_DTAP = 0x1,
|
||||
};
|
||||
|
||||
struct bssmap_header {
|
||||
u_int8_t type;
|
||||
u_int8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dtap_header {
|
||||
u_int8_t type;
|
||||
u_int8_t link_id;
|
||||
u_int8_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
enum BSS_MAP_MSG_TYPE {
|
||||
BSS_MAP_MSG_RESERVED_0 = 0,
|
||||
|
||||
/* ASSIGNMENT MESSAGES */
|
||||
BSS_MAP_MSG_ASSIGMENT_RQST = 1,
|
||||
BSS_MAP_MSG_ASSIGMENT_COMPLETE = 2,
|
||||
BSS_MAP_MSG_ASSIGMENT_FAILURE = 3,
|
||||
|
||||
/* HANDOVER MESSAGES */
|
||||
BSS_MAP_MSG_HANDOVER_RQST = 16,
|
||||
BSS_MAP_MSG_HANDOVER_REQUIRED = 17,
|
||||
BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
|
||||
BSS_MAP_MSG_HANDOVER_CMD = 19,
|
||||
BSS_MAP_MSG_HANDOVER_COMPLETE = 20,
|
||||
BSS_MAP_MSG_HANDOVER_SUCCEEDED = 21,
|
||||
BSS_MAP_MSG_HANDOVER_FAILURE = 22,
|
||||
BSS_MAP_MSG_HANDOVER_PERFORMED = 23,
|
||||
BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE = 24,
|
||||
BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE = 25,
|
||||
BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT = 26,
|
||||
BSS_MAP_MSG_HANDOVER_DETECT = 27,
|
||||
|
||||
/* RELEASE MESSAGES */
|
||||
BSS_MAP_MSG_CLEAR_CMD = 32,
|
||||
BSS_MAP_MSG_CLEAR_COMPLETE = 33,
|
||||
BSS_MAP_MSG_CLEAR_RQST = 34,
|
||||
BSS_MAP_MSG_RESERVED_1 = 35,
|
||||
BSS_MAP_MSG_RESERVED_2 = 36,
|
||||
BSS_MAP_MSG_SAPI_ = 37,
|
||||
BSS_MAP_MSG_CONFUSION = 38,
|
||||
|
||||
/* OTHER CONNECTION RELATED MESSAGES */
|
||||
BSS_MAP_MSG_SUSPEND = 40,
|
||||
BSS_MAP_MSG_RESUME = 41,
|
||||
BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
|
||||
BSS_MAP_MSG_PERFORM_LOCATION_RQST = 43,
|
||||
BSS_MAP_MSG_LSA_INFORMATION = 44,
|
||||
BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE = 45,
|
||||
BSS_MAP_MSG_PERFORM_LOCATION_ABORT = 46,
|
||||
BSS_MAP_MSG_COMMON_ID = 47,
|
||||
|
||||
/* GENERAL MESSAGES */
|
||||
BSS_MAP_MSG_RESET = 48,
|
||||
BSS_MAP_MSG_RESET_ACKNOWLEDGE = 49,
|
||||
BSS_MAP_MSG_OVERLOAD = 50,
|
||||
BSS_MAP_MSG_RESERVED_3 = 51,
|
||||
BSS_MAP_MSG_RESET_CIRCUIT = 52,
|
||||
BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE = 53,
|
||||
BSS_MAP_MSG_MSC_INVOKE_TRACE = 54,
|
||||
BSS_MAP_MSG_BSS_INVOKE_TRACE = 55,
|
||||
BSS_MAP_MSG_CONNECTIONLESS_INFORMATION = 58,
|
||||
|
||||
/* TERRESTRIAL RESOURCE MESSAGES */
|
||||
BSS_MAP_MSG_BLOCK = 64,
|
||||
BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE = 65,
|
||||
BSS_MAP_MSG_UNBLOCK = 66,
|
||||
BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE = 67,
|
||||
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK = 68,
|
||||
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE = 69,
|
||||
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK = 70,
|
||||
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
|
||||
BSS_MAP_MSG_UNEQUIPPED_CIRCUIT = 72,
|
||||
BSS_MAP_MSG_CHANGE_CIRCUIT = 78,
|
||||
BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE = 79,
|
||||
|
||||
/* RADIO RESOURCE MESSAGES */
|
||||
BSS_MAP_MSG_RESOURCE_RQST = 80,
|
||||
BSS_MAP_MSG_RESOURCE_INDICATION = 81,
|
||||
BSS_MAP_MSG_PAGING = 82,
|
||||
BSS_MAP_MSG_CIPHER_MODE_CMD = 83,
|
||||
BSS_MAP_MSG_CLASSMARK_UPDATE = 84,
|
||||
BSS_MAP_MSG_CIPHER_MODE_COMPLETE = 85,
|
||||
BSS_MAP_MSG_QUEUING_INDICATION = 86,
|
||||
BSS_MAP_MSG_COMPLETE_LAYER_3 = 87,
|
||||
BSS_MAP_MSG_CLASSMARK_RQST = 88,
|
||||
BSS_MAP_MSG_CIPHER_MODE_REJECT = 89,
|
||||
BSS_MAP_MSG_LOAD_INDICATION = 90,
|
||||
|
||||
/* VGCS/VBS */
|
||||
BSS_MAP_MSG_VGCS_VBS_SETUP = 4,
|
||||
BSS_MAP_MSG_VGCS_VBS_SETUP_ACK = 5,
|
||||
BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE = 6,
|
||||
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST = 7,
|
||||
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT = 28,
|
||||
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE = 29,
|
||||
BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30,
|
||||
BSS_MAP_MSG_UPLINK_RQST = 31,
|
||||
BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39,
|
||||
BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73,
|
||||
BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74,
|
||||
BSS_MAP_MSG_UPLINK_REJECT_CMD = 75,
|
||||
BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76,
|
||||
BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77,
|
||||
};
|
||||
|
||||
enum GSM0808_IE_CODING {
|
||||
GSM0808_IE_CIRCUIT_IDENTITY_CODE = 1,
|
||||
GSM0808_IE_RESERVED_0 = 2,
|
||||
GSM0808_IE_RESOURCE_AVAILABLE = 3,
|
||||
GSM0808_IE_CAUSE = 4,
|
||||
GSM0808_IE_CELL_IDENTIFIER = 5,
|
||||
GSM0808_IE_PRIORITY = 6,
|
||||
GSM0808_IE_LAYER_3_HEADER_INFORMATION = 7,
|
||||
GSM0808_IE_IMSI = 8,
|
||||
GSM0808_IE_TMSI = 9,
|
||||
GSM0808_IE_ENCRYPTION_INFORMATION = 10,
|
||||
GSM0808_IE_CHANNEL_TYPE = 11,
|
||||
GSM0808_IE_PERIODICITY = 12,
|
||||
GSM0808_IE_EXTENDED_RESOURCE_INDICATOR = 13,
|
||||
GSM0808_IE_NUMBER_OF_MSS = 14,
|
||||
GSM0808_IE_RESERVED_1 = 15,
|
||||
GSM0808_IE_RESERVED_2 = 16,
|
||||
GSM0808_IE_RESERVED_3 = 17,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_2 = 18,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_3 = 19,
|
||||
GSM0808_IE_INTERFERENCE_BAND_TO_BE_USED = 20,
|
||||
GSM0808_IE_RR_CAUSE = 21,
|
||||
GSM0808_IE_RESERVED_4 = 22,
|
||||
GSM0808_IE_LAYER_3_INFORMATION = 23,
|
||||
GSM0808_IE_DLCI = 24,
|
||||
GSM0808_IE_DOWNLINK_DTX_FLAG = 25,
|
||||
GSM0808_IE_CELL_IDENTIFIER_LIST = 26,
|
||||
GSM0808_IE_RESPONSE_RQST = 27,
|
||||
GSM0808_IE_RESOURCE_INDICATION_METHOD = 28,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1 = 29,
|
||||
GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST = 30,
|
||||
GSM0808_IE_DIAGNOSTIC = 31,
|
||||
GSM0808_IE_LAYER_3_MESSAGE_CONTENTS = 32,
|
||||
GSM0808_IE_CHOSEN_CHANNEL = 33,
|
||||
GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE = 34,
|
||||
GSM0808_IE_CIPHER_RESPONSE_MODE = 35,
|
||||
GSM0808_IE_CHANNEL_NEEDED = 36,
|
||||
GSM0808_IE_TRACE_TYPE = 37,
|
||||
GSM0808_IE_TRIGGERID = 38,
|
||||
GSM0808_IE_TRACE_REFERENCE = 39,
|
||||
GSM0808_IE_TRANSACTIONID = 40,
|
||||
GSM0808_IE_MOBILE_IDENTITY = 41,
|
||||
GSM0808_IE_OMCID = 42,
|
||||
GSM0808_IE_FORWARD_INDICATOR = 43,
|
||||
GSM0808_IE_CHOSEN_ENCR_ALG = 44,
|
||||
GSM0808_IE_CIRCUIT_POOL = 45,
|
||||
GSM0808_IE_CIRCUIT_POOL_LIST = 46,
|
||||
GSM0808_IE_TIME_INDICATION = 47,
|
||||
GSM0808_IE_RESOURCE_SITUATION = 48,
|
||||
GSM0808_IE_CURRENT_CHANNEL_TYPE_1 = 49,
|
||||
GSM0808_IE_QUEUEING_INDICATOR = 50,
|
||||
GSM0808_IE_SPEECH_VERSION = 64,
|
||||
GSM0808_IE_ASSIGNMENT_REQUIREMENT = 51,
|
||||
GSM0808_IE_TALKER_FLAG = 53,
|
||||
GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54,
|
||||
GSM0808_IE_GROUP_CALL_REFERENCE = 55,
|
||||
GSM0808_IE_EMLPP_PRIORITY = 56,
|
||||
GSM0808_IE_CONFIGURATION_EVOLUTION_INDICATION = 57,
|
||||
GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58,
|
||||
GSM0808_IE_LSA_IDENTIFIER = 59,
|
||||
GSM0808_IE_LSA_IDENTIFIER_LIST = 60,
|
||||
GSM0808_IE_LSA_INFORMATION = 61,
|
||||
GSM0808_IE_LCS_QOS = 62,
|
||||
GSM0808_IE_LSA_ACCESS_CONTROL_SUPPRESSION = 63,
|
||||
GSM0808_IE_LCS_PRIORITY = 67,
|
||||
GSM0808_IE_LOCATION_TYPE = 68,
|
||||
GSM0808_IE_LOCATION_ESTIMATE = 69,
|
||||
GSM0808_IE_POSITIONING_DATA = 70,
|
||||
GSM0808_IE_LCS_CAUSE = 71,
|
||||
GSM0808_IE_LCS_CLIENT_TYPE = 72,
|
||||
GSM0808_IE_APDU = 73,
|
||||
GSM0808_IE_NETWORK_ELEMENT_IDENTITY = 74,
|
||||
GSM0808_IE_GPS_ASSISTANCE_DATA = 75,
|
||||
GSM0808_IE_DECIPHERING_KEYS = 76,
|
||||
GSM0808_IE_RETURN_ERROR_RQST = 77,
|
||||
GSM0808_IE_RETURN_ERROR_CAUSE = 78,
|
||||
GSM0808_IE_SEGMENTATION = 79,
|
||||
GSM0808_IE_SERVICE_HANDOVER = 80,
|
||||
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81,
|
||||
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
|
||||
GSM0808_IE_RESERVED_5 = 65,
|
||||
GSM0808_IE_RESERVED_6 = 66,
|
||||
};
|
||||
|
||||
enum gsm0808_cause {
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE = 0,
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE = 1,
|
||||
GSM0808_CAUSE_UPLINK_QUALITY = 2,
|
||||
GSM0808_CAUSE_UPLINK_STRENGTH = 3,
|
||||
GSM0808_CAUSE_DOWNLINK_QUALITY = 4,
|
||||
GSM0808_CAUSE_DOWNLINK_STRENGTH = 5,
|
||||
GSM0808_CAUSE_DISTANCE = 6,
|
||||
GSM0808_CAUSE_O_AND_M_INTERVENTION = 7,
|
||||
GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION = 8,
|
||||
GSM0808_CAUSE_CALL_CONTROL = 9,
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION = 10,
|
||||
GSM0808_CAUSE_HANDOVER_SUCCESSFUL = 11,
|
||||
GSM0808_CAUSE_BETTER_CELL = 12,
|
||||
GSM0808_CAUSE_DIRECTED_RETRY = 13,
|
||||
GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL = 14,
|
||||
GSM0808_CAUSE_TRAFFIC = 15,
|
||||
GSM0808_CAUSE_EQUIPMENT_FAILURE = 32,
|
||||
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE = 33,
|
||||
GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE = 34,
|
||||
GSM0808_CAUSE_CCCH_OVERLOAD = 35,
|
||||
GSM0808_CAUSE_PROCESSOR_OVERLOAD = 36,
|
||||
GSM0808_CAUSE_BSS_NOT_EQUIPPED = 37,
|
||||
GSM0808_CAUSE_MS_NOT_EQUIPPED = 38,
|
||||
GSM0808_CAUSE_INVALID_CELL = 39,
|
||||
GSM0808_CAUSE_TRAFFIC_LOAD = 40,
|
||||
GSM0808_CAUSE_PREEMPTION = 41,
|
||||
GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE = 48,
|
||||
GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH = 49,
|
||||
GSM0808_CAUSE_SWITCH_CIRCUIT_POOL = 50,
|
||||
GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE = 51,
|
||||
GSM0808_CAUSE_LSA_NOT_ALLOWED = 52,
|
||||
GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED = 64,
|
||||
GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED = 80,
|
||||
GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS = 81,
|
||||
GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING = 82,
|
||||
GSM0808_CAUSE_INCORRECT_VALUE = 83,
|
||||
GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE = 84,
|
||||
GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT = 85,
|
||||
GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC = 96,
|
||||
};
|
||||
|
||||
int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned int length);
|
||||
int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length);
|
||||
|
||||
struct msgb *bssmap_create_layer3(struct msgb *msg);
|
||||
struct msgb *bssmap_create_reset(void);
|
||||
struct msgb *bssmap_create_clear_complete(void);
|
||||
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3, int bsc_enc_algo);
|
||||
struct msgb *bssmap_create_cipher_reject(u_int8_t cause);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
|
@ -110,11 +110,25 @@ struct gsm_bts_link {
|
|||
struct gsm_bts *bts;
|
||||
};
|
||||
|
||||
struct sccp_connection;
|
||||
struct gsm_lchan;
|
||||
struct gsm_subscriber;
|
||||
struct gsm_mncc;
|
||||
struct rtp_socket;
|
||||
|
||||
/* BSC/MSC data holding them together */
|
||||
struct bss_sccp_connection_data {
|
||||
struct gsm_lchan *lchan;
|
||||
struct sccp_connection *sccp;
|
||||
int ciphering_handled : 1;
|
||||
};
|
||||
|
||||
#define sccp_get_lchan(data_ctx) ((struct bss_sccp_connection_data *)data_ctx)->lchan
|
||||
#define lchan_get_sccp(lchan) lchan->msc_data->sccp
|
||||
struct bss_sccp_connection_data *bss_sccp_create_data();
|
||||
void bss_sccp_free_data(struct bss_sccp_connection_data *);
|
||||
|
||||
|
||||
/* Network Management State */
|
||||
struct gsm_nm_state {
|
||||
u_int8_t operational;
|
||||
|
@ -183,6 +197,12 @@ struct gsm_lchan {
|
|||
*/
|
||||
struct gsm_loc_updating_operation *loc_operation;
|
||||
|
||||
/*
|
||||
* MSC handling...
|
||||
*/
|
||||
struct bss_sccp_connection_data *msc_data;
|
||||
|
||||
|
||||
/* use count. how many users use this channel */
|
||||
unsigned int use_count;
|
||||
};
|
||||
|
|
|
@ -81,6 +81,8 @@ struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
|
|||
const char *ext);
|
||||
struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
|
||||
unsigned long long id);
|
||||
struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
|
||||
const char *imsi);
|
||||
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
|
||||
void subscr_put_channel(struct gsm_lchan *lchan);
|
||||
void subscr_get_channel(struct gsm_subscriber *subscr,
|
||||
|
|
|
@ -37,6 +37,7 @@ struct msgb {
|
|||
unsigned char *l2h;
|
||||
unsigned char *l3h;
|
||||
unsigned char *smsh;
|
||||
unsigned char *l4h;
|
||||
|
||||
u_int16_t data_len;
|
||||
u_int16_t len;
|
||||
|
@ -55,6 +56,7 @@ extern void msgb_reset(struct msgb *m);
|
|||
|
||||
#define msgb_l2(m) ((void *)(m->l2h))
|
||||
#define msgb_l3(m) ((void *)(m->l3h))
|
||||
#define msgb_l4(m) ((void *)(m->l4h))
|
||||
#define msgb_sms(m) ((void *)(m->smsh))
|
||||
|
||||
static inline unsigned int msgb_l2len(const struct msgb *msgb)
|
||||
|
|
|
@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
|||
AM_CFLAGS=-Wall
|
||||
|
||||
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync \
|
||||
isdnsync bsc_mgcp
|
||||
isdnsync bsc_mgcp bsc_msc_ip
|
||||
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
|
||||
noinst_HEADERS = vty/cardshell.h
|
||||
|
||||
|
@ -11,9 +11,9 @@ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
|
|||
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
|
||||
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
|
||||
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
|
||||
talloc_ctx.c
|
||||
talloc_ctx.c telnet_interface.c
|
||||
|
||||
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \
|
||||
libmsc_a_SOURCES = gsm_subscriber.c db.c \
|
||||
mncc.c rtp_proxy.c gsm_04_08.c gsm_04_11.c transaction.c \
|
||||
token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c
|
||||
|
||||
|
@ -24,6 +24,9 @@ libsccp_a_SOURCES = sccp/sccp.c
|
|||
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
|
||||
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
|
||||
|
||||
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c
|
||||
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a
|
||||
|
||||
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
|
||||
select.c timer.c rs232.c tlv_parser.c signal.c talloc.c
|
||||
|
||||
|
|
|
@ -0,0 +1,617 @@
|
|||
/* A hackish minimal BSC (+MSC +HLR) implementation */
|
||||
|
||||
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009 by on-waves.com
|
||||
* 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 <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
#include <openbsc/select.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/e1_input.h>
|
||||
#include <openbsc/talloc.h>
|
||||
#include <openbsc/select.h>
|
||||
#include <openbsc/ipaccess.h>
|
||||
#include <openbsc/bssap.h>
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/signal.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
|
||||
/* MCC and MNC for the Location Area Identifier */
|
||||
struct gsm_network *bsc_gsmnet = 0;
|
||||
static const char *config_file = "openbsc.cfg";
|
||||
static char *msc_address = "127.0.0.1";
|
||||
static struct bsc_fd msc_connection;
|
||||
extern int ipacc_rtp_direct;
|
||||
|
||||
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
|
||||
extern int bsc_shutdown_net(struct gsm_network *net);
|
||||
|
||||
struct bss_sccp_connection_data *bss_sccp_create_data()
|
||||
{
|
||||
return _talloc_zero(tall_bsc_ctx,
|
||||
sizeof(struct bss_sccp_connection_data),
|
||||
"bsc<->msc");
|
||||
}
|
||||
|
||||
void bss_sccp_free_data(struct bss_sccp_connection_data *data)
|
||||
{
|
||||
talloc_free(data);
|
||||
}
|
||||
|
||||
|
||||
/* GSM subscriber drop-ins */
|
||||
extern struct llist_head *subscr_bsc_active_subscriber(void);
|
||||
struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
u_int32_t tmsi = GSM_RESERVED_TMSI;
|
||||
if (type == GSM_MI_TYPE_TMSI) {
|
||||
tmsi = tmsi_from_string(mi_string);
|
||||
if (tmsi == GSM_RESERVED_TMSI) {
|
||||
DEBUGP(DMSC, "The TMSI is the reserved one.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
|
||||
if (type == GSM_MI_TYPE_TMSI && tmsi == subscr->tmsi) {
|
||||
return subscr_get(subscr);
|
||||
} else if (type == GSM_MI_TYPE_IMSI && strcmp(mi_string, subscr->imsi) == 0) {
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "No subscriber has been found.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* BSC -> MSC hooks */
|
||||
void bsc_vty_init_extra(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* SCCP handling */
|
||||
void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
|
||||
{
|
||||
struct bssmap_header *bs;
|
||||
|
||||
if (len < 1) {
|
||||
DEBUGP(DMSC, "The header is too short.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg->l3h[0]) {
|
||||
case BSSAP_MSG_BSS_MANAGEMENT:
|
||||
msg->l4h = &msg->l3h[sizeof(*bs)];
|
||||
msg->lchan = sccp_get_lchan(conn->data_ctx);
|
||||
bssmap_rcvmsg_dt1(conn, msg, len - sizeof(*bs));
|
||||
break;
|
||||
case BSSAP_MSG_DTAP:
|
||||
dtap_rcvmsg(sccp_get_lchan(conn->data_ctx), msg, len);
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", msg->l3h[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
|
||||
{
|
||||
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
|
||||
DEBUGP(DMSC, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
|
||||
if (sccp_get_lchan(conn->data_ctx) != NULL) {
|
||||
DEBUGP(DMSC, "ERROR: The lchan is still associated\n.");
|
||||
}
|
||||
|
||||
bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx);
|
||||
sccp_connection_free(conn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* General COMPLETE LAYER3 INFORMATION handling for
|
||||
* PAGING RESPONSE, LOCATION UPDATING REQUEST, CM REESTABLISHMENT REQUEST,
|
||||
* CM SERVICE REQUEST, IMSI DETACH, IMMEDIATE SETUP.
|
||||
*
|
||||
* IMMEDIATE SETUP is coming from GROUP CC that is not yet
|
||||
* supported...
|
||||
*/
|
||||
int open_sccp_connection(struct msgb *layer3)
|
||||
{
|
||||
struct bss_sccp_connection_data *con_data;
|
||||
struct sccp_connection *sccp_connection;
|
||||
struct msgb *data;
|
||||
|
||||
DEBUGP(DMSC, "Opening new layer3 connection\n");
|
||||
sccp_connection = sccp_connection_socket();
|
||||
if (!sccp_connection) {
|
||||
DEBUGP(DMSC, "Failed to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = bssmap_create_layer3(layer3);
|
||||
if (!data) {
|
||||
DEBUGP(DMSC, "Failed to allocate complete layer3.\n");
|
||||
sccp_connection_free(sccp_connection);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
con_data = bss_sccp_create_data();
|
||||
if (!con_data) {
|
||||
DEBUGP(DMSC, "Failed to allocate bss<->msc data.\n");
|
||||
sccp_connection_free(sccp_connection);
|
||||
msgb_free(data);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* initialize the bridge */
|
||||
con_data->lchan = layer3->lchan;
|
||||
con_data->sccp = sccp_connection;
|
||||
|
||||
sccp_connection->state_cb = msc_outgoing_sccp_state;
|
||||
sccp_connection->data_cb = msc_outgoing_sccp_data;
|
||||
sccp_connection->data_ctx = con_data;
|
||||
layer3->lchan->msc_data = con_data;
|
||||
|
||||
/* FIXME: Use transaction for this */
|
||||
use_lchan(layer3->lchan);
|
||||
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
|
||||
msgb_free(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* figure out if this is the inial layer3 message */
|
||||
static int send_dtap_or_open_connection(struct msgb *msg)
|
||||
{
|
||||
if (msg->lchan->msc_data) {
|
||||
struct msgb *dtap = dtap_create_msg(msg, 0);
|
||||
if (!dtap) {
|
||||
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sccp_connection_write(lchan_get_sccp(msg->lchan), dtap);
|
||||
return 1;
|
||||
} else {
|
||||
return open_sccp_connection(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive a PAGING RESPONSE message from the MS */
|
||||
static int handle_paging_response(struct msgb *msg)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
u_int8_t mi_type;
|
||||
|
||||
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
|
||||
DEBUGP(DMSC, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
|
||||
mi_type, mi_string);
|
||||
|
||||
subscr = find_subscriber(mi_type, mi_string);
|
||||
if (!subscr)
|
||||
return -EINVAL;
|
||||
|
||||
/* force the paging to stop at every bts */
|
||||
subscr->lac = GSM_LAC_RESERVED_ALL_BTS;
|
||||
if (gsm48_handle_paging_resp(msg, subscr) != 0) {
|
||||
DEBUGP(DMSC, "Paging failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open a new transaction and SCCP connection */
|
||||
return send_dtap_or_open_connection(msg);
|
||||
}
|
||||
|
||||
/* Receive a CIPHER MODE COMPLETE from the MS */
|
||||
static int handle_cipher_m_complete(struct msgb *msg)
|
||||
{
|
||||
struct msgb *resp;
|
||||
|
||||
DEBUGP(DMSC, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
|
||||
resp = bssmap_create_cipher_complete(msg, -1);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Creating MSC response failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* handled this message */
|
||||
sccp_connection_write(lchan_get_sccp(msg->lchan), resp);
|
||||
msgb_free(resp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Receive a GSM 04.08 Radio Resource (RR) message */
|
||||
static int gsm0408_rcv_rr(struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
int rc = 0;
|
||||
|
||||
switch (gh->msg_type) {
|
||||
case GSM48_MT_RR_PAG_RESP:
|
||||
rc = handle_paging_response(msg);
|
||||
break;
|
||||
case GSM48_MT_RR_MEAS_REP:
|
||||
/* ignore measurement for now */
|
||||
rc = -1;
|
||||
break;
|
||||
case GSM48_MT_RR_CIPH_M_COMPL:
|
||||
rc = handle_cipher_m_complete(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Receive a GSM 04.08 Mobility Management (MM) message */
|
||||
static int gsm0408_rcv_mm(struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
int rc = 0;
|
||||
|
||||
switch (gh->msg_type & 0xbf) {
|
||||
case GSM48_MT_MM_LOC_UPD_REQUEST:
|
||||
case GSM48_MT_MM_CM_REEST_REQ:
|
||||
case GSM48_MT_MM_CM_SERV_REQ:
|
||||
case GSM48_MT_MM_IMSI_DETACH_IND:
|
||||
rc = send_dtap_or_open_connection(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
u_int8_t pdisc = gh->proto_discr & 0x0f;
|
||||
int rc = 0;
|
||||
|
||||
switch (pdisc) {
|
||||
case GSM48_PDISC_RR:
|
||||
rc = gsm0408_rcv_rr(msg);
|
||||
break;
|
||||
case GSM48_PDISC_MM:
|
||||
rc = gsm0408_rcv_mm(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* if we have a sccp connection and didn't handle the message
|
||||
* forward it to the MSC using DTAP
|
||||
*/
|
||||
if (rc == 0 && msg->lchan->msc_data && lchan_get_sccp(msg->lchan)) {
|
||||
struct msgb *dtap = dtap_create_msg(msg, link_id);
|
||||
if (!dtap) {
|
||||
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sccp_connection_write(lchan_get_sccp(msg->lchan), dtap);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: bsc_hack\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* SCCP handling
|
||||
*/
|
||||
static int msc_sccp_write_ipa(struct msgb *msg, void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
|
||||
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
|
||||
|
||||
|
||||
DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
|
||||
ret = write(msc_connection.fd, msg->data, msg->len);
|
||||
|
||||
if (ret <= 0) {
|
||||
perror("MSC: Failed to send SCCP");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
|
||||
{
|
||||
DEBUGP(DMSC, "Rejecting incoming SCCP connection.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
|
||||
{
|
||||
struct bssmap_header *bs;
|
||||
|
||||
DEBUGP(DMSC, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length));
|
||||
|
||||
if (length < sizeof(*bs)) {
|
||||
DEBUGP(DMSC, "The header is too short.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bs = (struct bssmap_header *) msgb->l3h;
|
||||
if (bs->length < length - sizeof(*bs))
|
||||
return -1;
|
||||
|
||||
switch (bs->type) {
|
||||
case BSSAP_MSG_BSS_MANAGEMENT:
|
||||
msgb->l4h = &msgb->l3h[sizeof(*bs)];
|
||||
bssmap_rcvmsg_udt(bsc_gsmnet, msgb, length - sizeof(*bs));
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", bs->type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* network initialisation
|
||||
*/
|
||||
static void initialize_if_needed(void)
|
||||
{
|
||||
if (!bsc_gsmnet) {
|
||||
int rc;
|
||||
struct msgb *msg;
|
||||
|
||||
fprintf(stderr, "Bootstraping the network. Sending GSM08.08 reset.\n");
|
||||
rc = bsc_bootstrap_network(NULL, config_file);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* send a gsm 08.08 reset message from here */
|
||||
msg = bssmap_create_reset();
|
||||
if (!msg) {
|
||||
DEBUGP(DMSC, "Failed to create the reset message.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback with IP access data
|
||||
*/
|
||||
static int ipaccess_a_fd_cb(struct bsc_fd *bfd, unsigned int what)
|
||||
{
|
||||
int error;
|
||||
struct msgb *msg = ipaccess_read_msg(bfd, &error);
|
||||
struct ipaccess_head *hh;
|
||||
|
||||
if (!msg) {
|
||||
if (error == 0) {
|
||||
fprintf(stderr, "The connection to the MSC was lost, exiting\n");
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
|
||||
|
||||
/* handle base message handling */
|
||||
hh = (struct ipaccess_head *) msg->data;
|
||||
ipaccess_rcvmsg_base(msg, bfd);
|
||||
|
||||
/* initialize the networking. This includes sending a GSM08.08 message */
|
||||
if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
|
||||
initialize_if_needed();
|
||||
else if (hh->proto == IPAC_PROTO_SCCP)
|
||||
sccp_system_incoming(msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the MSC
|
||||
*/
|
||||
static int connect_to_msc(const char *ip, int port)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
int on = 1, ret;
|
||||
|
||||
printf("Attempting to connect MSC at %s:%d\n", ip, port);
|
||||
|
||||
msc_connection.fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
msc_connection.cb = ipaccess_a_fd_cb;
|
||||
msc_connection.when = BSC_FD_READ;
|
||||
msc_connection.data = NULL;
|
||||
msc_connection.priv_nr = 1;
|
||||
|
||||
if (msc_connection.fd < 0) {
|
||||
perror("Creating TCP socket failed");
|
||||
return msc_connection.fd;
|
||||
}
|
||||
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = htons(port);
|
||||
inet_aton(ip, &sin.sin_addr);
|
||||
|
||||
setsockopt(msc_connection.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
ret = connect(msc_connection.fd, (struct sockaddr *) &sin, sizeof(sin));
|
||||
|
||||
if (ret < 0) {
|
||||
perror("Connection failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bsc_register_fd(&msc_connection);
|
||||
if (ret < 0) {
|
||||
perror("Registering the fd failed");
|
||||
close(msc_connection.fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void print_help()
|
||||
{
|
||||
printf(" Some useful help...\n");
|
||||
printf(" -h --help this text\n");
|
||||
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
|
||||
printf(" -s --disable-color\n");
|
||||
printf(" -c --config-file filename The config file to use.\n");
|
||||
printf(" -m --msc=IP. The address of the MSC.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char** argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"debug", 1, 0, 'd'},
|
||||
{"config-file", 1, 0, 'c'},
|
||||
{"disable-color", 0, 0, 's'},
|
||||
{"timestamp", 0, 0, 'T'},
|
||||
{"rtp-proxy", 0, 0, 'P'},
|
||||
{"msc", 1, 0, 'm'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hd:sTPc:m:",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_usage();
|
||||
print_help();
|
||||
exit(0);
|
||||
case 's':
|
||||
debug_use_color(0);
|
||||
break;
|
||||
case 'd':
|
||||
debug_parse_category_mask(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
config_file = strdup(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
debug_timestamp(1);
|
||||
break;
|
||||
case 'P':
|
||||
ipacc_rtp_direct = 0;
|
||||
break;
|
||||
case 'm':
|
||||
msc_address = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void signal_handler(int signal)
|
||||
{
|
||||
fprintf(stdout, "signal %u received\n", signal);
|
||||
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
bsc_shutdown_net(bsc_gsmnet);
|
||||
sleep(3);
|
||||
exit(0);
|
||||
break;
|
||||
case SIGABRT:
|
||||
/* in case of abort, we want to obtain a talloc report
|
||||
* and then return to the caller, who will abort the process */
|
||||
case SIGUSR1:
|
||||
talloc_report_full(tall_bsc_ctx, stderr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
|
||||
|
||||
/* parse options */
|
||||
handle_options(argc, argv);
|
||||
|
||||
/* seed the PRNG */
|
||||
srand(time(NULL));
|
||||
|
||||
/* initialize sccp */
|
||||
sccp_system_init(msc_sccp_write_ipa, NULL);
|
||||
sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
|
||||
sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL);
|
||||
|
||||
rc = connect_to_msc(msc_address, 5000);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Opening the MSC connection failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
signal(SIGINT, &signal_handler);
|
||||
signal(SIGABRT, &signal_handler);
|
||||
signal(SIGUSR1, &signal_handler);
|
||||
|
||||
while (1) {
|
||||
bsc_select_main(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,501 @@
|
|||
/* GSM 08.08 BSSMAP handling */
|
||||
/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2009 by on-waves.com
|
||||
* 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 <openbsc/bssap.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/tlv.h>
|
||||
#include <openbsc/paging.h>
|
||||
|
||||
#include <sccp/sccp.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
|
||||
#define BSSMAP_MSG_SIZE 512
|
||||
#define BSSMAP_MSG_HEADROOM 128
|
||||
|
||||
|
||||
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 },
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static int bssmap_paging_cb(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param)
|
||||
{
|
||||
DEBUGP(DMSC, "Paging is complete.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bssmap_handle_reset_ack(struct gsm_network *net, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
DEBUGP(DMSC, "Reset ACK from MSC\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* GSM 08.08 § 3.2.1.19 */
|
||||
static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsigned int payload_length)
|
||||
{
|
||||
struct tlv_parsed tp;
|
||||
char mi_string[GSM48_MI_SIZE];
|
||||
u_int32_t tmsi = GSM_RESERVED_TMSI;
|
||||
unsigned int lac = GSM_LAC_RESERVED_ALL_BTS;
|
||||
u_int8_t data_length;
|
||||
const u_int8_t *data;
|
||||
struct gsm_subscriber *subscr;
|
||||
u_int8_t chan_needed = RSL_CHANNEED_ANY;
|
||||
int paged;
|
||||
|
||||
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
|
||||
DEBUGP(DMSC, "Mandantory IMSI not present.\n");
|
||||
return -1;
|
||||
} else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) {
|
||||
DEBUGP(DMSC, "Wrong content in the IMSI\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
|
||||
DEBUGP(DMSC, "Mandantory CELL IDENTIFIER LIST not present.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI)) {
|
||||
gsm48_mi_to_string(mi_string, sizeof(mi_string),
|
||||
TLVP_VAL(&tp, GSM0808_IE_TMSI), TLVP_LEN(&tp, GSM0808_IE_TMSI));
|
||||
tmsi = strtoul(mi_string, NULL, 10);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* parse the IMSI
|
||||
*/
|
||||
gsm48_mi_to_string(mi_string, sizeof(mi_string),
|
||||
TLVP_VAL(&tp, GSM0808_IE_IMSI), TLVP_LEN(&tp, GSM0808_IE_IMSI));
|
||||
|
||||
/*
|
||||
* parse the cell identifier list
|
||||
*/
|
||||
data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
|
||||
data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
|
||||
|
||||
/*
|
||||
* Support paging to all network or one BTS at one LAC
|
||||
*/
|
||||
if (data_length == 3 && data[0] == CELL_IDENT_LAC) {
|
||||
unsigned int *_lac = (unsigned int *)&data[1];
|
||||
lac = ntohs(*_lac);
|
||||
} else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
|
||||
DEBUGPC(DMSC, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_NEEDED) && TLVP_LEN(&tp, GSM0808_IE_CHANNEL_NEEDED) == 1)
|
||||
chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03;
|
||||
|
||||
if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) {
|
||||
DEBUGP(DMSC, "eMLPP is not handled\n");
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
|
||||
subscr = subscr_get_or_create(net, mi_string);
|
||||
if (!subscr)
|
||||
return -1;
|
||||
|
||||
/* reassign the tmsi, trust the net over our internal state */
|
||||
subscr->tmsi = tmsi;
|
||||
subscr->lac = lac;
|
||||
paged = paging_request(net, subscr, chan_needed, bssmap_paging_cb, subscr);
|
||||
DEBUGP(DMSC, "Paged IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x on #bts: %d\n", mi_string, tmsi, tmsi, lac, paged);
|
||||
|
||||
subscr_put(subscr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* GSM 08.08 § 3.1.9.1 and 3.2.1.21... release our gsm_lchan and send message */
|
||||
static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
||||
struct msgb *msg, unsigned int payload_length)
|
||||
{
|
||||
struct msgb *resp;
|
||||
|
||||
/* TODO: handle the cause of this package */
|
||||
|
||||
if (msg->lchan) {
|
||||
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
|
||||
msg->lchan->msc_data->lchan = NULL;
|
||||
msg->lchan->msc_data = NULL;
|
||||
put_lchan(msg->lchan);
|
||||
}
|
||||
|
||||
/* send the clear complete message */
|
||||
resp = bssmap_create_clear_complete();
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Sending clear complete failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sccp_connection_write(conn, resp);
|
||||
msgb_free(resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* GSM 08.08 § 3.4.7 cipher mode handling. We will have to pick
|
||||
* the cipher to be used for this. In case we are already using
|
||||
* a cipher we will have to send cipher mode reject to the MSC,
|
||||
* otherwise we will have to pick something that we and the MS
|
||||
* is supporting. Currently we are doing it in a rather static
|
||||
* way by picking one ecnryption or no encrytpion.
|
||||
*/
|
||||
static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
struct msgb *msg, unsigned int payload_length)
|
||||
{
|
||||
struct msgb *resp;
|
||||
int reject_cause = -1;
|
||||
|
||||
/* HACK: Sending A5/0 to the MS */
|
||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
if (msg->lchan->msc_data->ciphering_handled) {
|
||||
DEBUGP(DMSC, "Already seen ciphering command. Protocol Error.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
msg->lchan->msc_data->ciphering_handled = 1;
|
||||
|
||||
/* FIXME: parse the message. TLVP */
|
||||
|
||||
return gsm48_send_rr_ciph_mode(msg->lchan, 1);
|
||||
|
||||
reject:
|
||||
resp = bssmap_create_cipher_reject(reject_cause);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Sending the cipher reject failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sccp_connection_write(conn, resp);
|
||||
msgb_free(resp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (length < 1) {
|
||||
DEBUGP(DMSC, "Not enough room: %d\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (msg->l4h[0]) {
|
||||
case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
|
||||
ret = bssmap_handle_reset_ack(net, msg, length);
|
||||
break;
|
||||
case BSS_MAP_MSG_PAGING:
|
||||
ret = bssmap_handle_paging(net, msg, length);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (length < 1) {
|
||||
DEBUGP(DMSC, "Not enough room: %d\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (msg->l4h[0]) {
|
||||
case BSS_MAP_MSG_CLEAR_CMD:
|
||||
ret = bssmap_handle_clear_command(conn, msg, length);
|
||||
break;
|
||||
case BSS_MAP_MSG_CIPHER_MODE_CMD:
|
||||
ret = bssmap_handle_cipher_mode(conn, msg, length);
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMSC, "Unimplemented msg type: %d\n", msg->l4h[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
header = (struct dtap_header *) msg->l3h;
|
||||
if (sizeof(*header) >= length) {
|
||||
DEBUGP(DMSC, "The DTAP header does not fit. Wanted: %u got: %u\n", sizeof(*header), length);
|
||||
DEBUGP(DMSC, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->length > length - sizeof(*header)) {
|
||||
DEBUGP(DMSC, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
|
||||
DEBUGP(DMSC, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "DTAP message: SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
|
||||
|
||||
/* forward the data */
|
||||
gsm48 = gsm48_msgb_alloc();
|
||||
if (!gsm48) {
|
||||
DEBUGP(DMSC, "Allocation of the message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
gsm48->lchan = lchan;
|
||||
gsm48->trx = gsm48->lchan->ts->trx;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Create messages */
|
||||
struct msgb *bssmap_create_layer3(struct msgb *msg_l3)
|
||||
{
|
||||
u_int8_t *data;
|
||||
u_int16_t *ci;
|
||||
struct msgb* msg;
|
||||
struct gsm48_loc_area_id *lai;
|
||||
struct gsm_bts *bts = msg_l3->lchan->ts->trx->bts;
|
||||
|
||||
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));
|
||||
gsm0408_generate_lai(lai, bts->network->country_code,
|
||||
bts->network->network_code, bts->location_area_code);
|
||||
|
||||
ci = (u_int16_t *) msgb_put(msg, 2);
|
||||
*ci = htons(bts->cell_identity);
|
||||
|
||||
/* 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 *bssmap_create_reset(void)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(30, "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 *bssmap_create_clear_complete(void)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(30, "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 *bssmap_create_cipher_complete(struct msgb *layer3, int bsc_enc_algo)
|
||||
{
|
||||
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] = 1;
|
||||
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->l3h[1] += 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 */
|
||||
if (bsc_enc_algo != -1) {
|
||||
msg->l3h[1] += 2;
|
||||
|
||||
msg->l4h = msgb_put(msg, 2);
|
||||
msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
|
||||
msg->l4h[1] = bsc_enc_algo;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_cipher_reject(u_int8_t cause)
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(30, "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 *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id)
|
||||
{
|
||||
struct dtap_header *header;
|
||||
u_int8_t *data;
|
||||
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
|
||||
"dtap");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
/* DTAP header */
|
||||
msg->l3h = msgb_put(msg, sizeof(*header));
|
||||
header = (struct dtap_header *) &msg->l3h[0];
|
||||
header->type = BSSAP_MSG_DTAP;
|
||||
header->link_id = link_id;
|
||||
header->length = msgb_l3len(msg_l3);
|
||||
|
||||
/* Payload */
|
||||
data = msgb_put(msg, header->length);
|
||||
memcpy(data, msg_l3->l3h, header->length);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct gsm_lchan *lchan;
|
||||
struct sccp_connection *conn;
|
||||
|
||||
if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If we have a SCCP Connection we need to inform the MSC about
|
||||
* the resource error and then drop the lchan<->sccp association.
|
||||
*/
|
||||
lchan = (struct gsm_lchan *)signal_data;
|
||||
|
||||
if (!lchan || !lchan->msc_data)
|
||||
return 0;
|
||||
|
||||
conn = lchan->msc_data->sccp;
|
||||
lchan->msc_data->lchan = NULL;
|
||||
lchan->msc_data = NULL;
|
||||
|
||||
msg = msgb_alloc(30, "sccp: clear request");
|
||||
if (!msg) {
|
||||
DEBUGP(DMSC, "Failed to allocate clear request.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
msg->l3h = msgb_put(msg, 2 + 4);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 4;
|
||||
|
||||
msg->l3h[2] = BSS_MAP_MSG_CLEAR_RQST;
|
||||
msg->l3h[3] = GSM0808_IE_CAUSE;
|
||||
msg->l3h[4] = 1;
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_bssap(void)
|
||||
{
|
||||
register_signal_handler(SS_LCHAN, bssap_handle_lchan_signal, NULL);
|
||||
}
|
|
@ -218,6 +218,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
|
|||
/* clear multi rate config */
|
||||
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
|
||||
|
||||
/* clear any msc reference */
|
||||
lchan->msc_data = NULL;
|
||||
|
||||
/* Configure the time and start it so it will be closed */
|
||||
lchan->release_timer.cb = auto_release_channel;
|
||||
lchan->release_timer.data = lchan;
|
||||
|
|
|
@ -89,6 +89,7 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
|
|||
request->cbfn(hooknum, event, msg, data, request->param);
|
||||
subscr->in_callback = 0;
|
||||
|
||||
subscr_put(request->subscr);
|
||||
talloc_free(request);
|
||||
return 0;
|
||||
}
|
||||
|
@ -166,7 +167,7 @@ void subscr_get_channel(struct gsm_subscriber *subscr,
|
|||
}
|
||||
|
||||
memset(request, 0, sizeof(*request));
|
||||
request->subscr = subscr;
|
||||
request->subscr = subscr_get(subscr);
|
||||
request->channel_type = type;
|
||||
request->cbfn = cbfn;
|
||||
request->param = param;
|
||||
|
@ -212,3 +213,22 @@ void subscr_put_channel(struct gsm_lchan *lchan)
|
|||
subscr_send_paging_request(lchan->subscr);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
|
||||
const char *imsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
|
||||
if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
subscr = subscr_alloc();
|
||||
if (!subscr)
|
||||
return NULL;
|
||||
|
||||
strcpy(subscr->imsi, imsi);
|
||||
subscr->net = net;
|
||||
return subscr;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ void msgb_reset(struct msgb *msg)
|
|||
msg->l2h = NULL;
|
||||
msg->l3h = NULL;
|
||||
msg->smsh = NULL;
|
||||
msg->l4h = NULL;
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_trau_msgb(void)
|
||||
|
|
Loading…
Reference in New Issue